Subversion Repositories svn.mios32

Rev

Rev 1919 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
693 tk 1
// $Id: app.c 2425 2016-11-03 00:44:22Z tk $
2
/*
3
 * MIOS32 Tutorial #019: A MIDI Player plays from SD Card
4
 *
5
 * ==========================================================================
6
 *
7
 *  Copyright (C) 2009 Thorsten Klose (tk@midibox.org)
8
 *  Licensed for personal non-commercial use only.
9
 *  All other rights reserved.
10
 *
11
 * ==========================================================================
12
 */
13
 
14
/////////////////////////////////////////////////////////////////////////////
15
// Include files
16
/////////////////////////////////////////////////////////////////////////////
17
 
18
#include <mios32.h>
19
 
1261 tk 20
#include "tasks.h"
693 tk 21
 
22
#include <seq_bpm.h>
23
#include <seq_midi_out.h>
24
 
25
#include "seq.h"
1261 tk 26
#include "file.h"
1118 tk 27
#include "mid_file.h"
693 tk 28
#include "app.h"
29
 
30
 
31
/////////////////////////////////////////////////////////////////////////////
32
// Local definitions
33
/////////////////////////////////////////////////////////////////////////////
34
 
35
/////////////////////////////////////////////////////////////////////////////
36
// Local definitions
37
/////////////////////////////////////////////////////////////////////////////
38
 
39
#define PRIORITY_TASK_SEQ       ( tskIDLE_PRIORITY + 4 ) // higher priority than MIDI receive task!
40
 
41
 
42
/////////////////////////////////////////////////////////////////////////////
1261 tk 43
// Global Variables
44
/////////////////////////////////////////////////////////////////////////////
45
 
46
// for mutual exclusive SD Card access between different tasks
47
// The mutex is handled with MUTEX_SDCARD_TAKE and MUTEX_SDCARD_GIVE
48
// macros inside the application, which contain a different implementation 
49
// for emulation
50
xSemaphoreHandle xSDCardSemaphore;
51
 
52
 
53
/////////////////////////////////////////////////////////////////////////////
693 tk 54
// Local Prototypes
55
/////////////////////////////////////////////////////////////////////////////
56
static void TASK_SEQ(void *pvParameters);
57
static s32 NOTIFY_MIDI_Rx(mios32_midi_port_t port, u8 byte);
58
 
59
 
60
/////////////////////////////////////////////////////////////////////////////
61
// This hook is called after startup to initialize the application
62
/////////////////////////////////////////////////////////////////////////////
63
void APP_Init(void)
64
{
65
  // initialize all LEDs
66
  MIOS32_BOARD_LED_Init(0xffffffff);
67
 
68
  // turn off gate LED
69
  MIOS32_BOARD_LED_Set(1, 0);
70
 
1261 tk 71
  // create semaphores
72
  xSDCardSemaphore = xSemaphoreCreateRecursiveMutex();
73
 
74
  // initialize file functions
75
  FILE_Init(0);
76
 
693 tk 77
  // initialize MIDI handler
78
  SEQ_MIDI_OUT_Init(0);
79
 
80
  // initialize sequencer
81
  SEQ_Init(0);
82
 
83
  // install MIDI Rx callback function
84
  MIOS32_MIDI_DirectRxCallback_Init(NOTIFY_MIDI_Rx);
85
 
86
  // install sequencer task
2425 tk 87
  xTaskCreate(TASK_SEQ, "SEQ", configMINIMAL_STACK_SIZE, NULL, PRIORITY_TASK_SEQ, NULL);
693 tk 88
}
89
 
90
 
91
/////////////////////////////////////////////////////////////////////////////
92
// This task is running endless in background
93
/////////////////////////////////////////////////////////////////////////////
94
void APP_Background(void)
95
{
1919 tk 96
}
97
 
98
 
99
/////////////////////////////////////////////////////////////////////////////
100
// This hook is called each mS from the main task which also handles DIN, ENC
101
// and AIN events. You could add more jobs here, but they shouldn't consume
102
// more than 300 uS to ensure the responsiveness of buttons, encoders, pots.
103
// Alternatively you could create a dedicated task for application specific
104
// jobs as explained in $MIOS32_PATH/apps/tutorials/006_rtos_tasks
105
/////////////////////////////////////////////////////////////////////////////
106
void APP_Tick(void)
107
{
693 tk 108
  // set LED depending on sequencer run state
109
  MIOS32_BOARD_LED_Set(1, SEQ_BPM_IsRunning() ? 1 : 0);
110
}
111
 
112
 
113
/////////////////////////////////////////////////////////////////////////////
1919 tk 114
// This hook is called each mS from the MIDI task which checks for incoming
115
// MIDI events. You could add more MIDI related jobs here, but they shouldn't
116
// consume more than 300 uS to ensure the responsiveness of incoming MIDI.
117
/////////////////////////////////////////////////////////////////////////////
118
void APP_MIDI_Tick(void)
119
{
120
}
121
 
122
 
123
/////////////////////////////////////////////////////////////////////////////
693 tk 124
// This hook is called when a MIDI package has been received
125
/////////////////////////////////////////////////////////////////////////////
126
void APP_MIDI_NotifyPackage(mios32_midi_port_t port, mios32_midi_package_t midi_package)
127
{
128
  // Note On received?
129
  if( midi_package.type == NoteOn &&
130
      midi_package.chn == Chn1 &&
131
      midi_package.velocity > 0 ) {
132
 
133
    // determine base key number (0=C, 1=C#, 2=D, ...)
134
    u8 base_key = midi_package.note % 12;
135
 
136
    // branch depending on note
137
    switch( base_key ) {
138
      case 0: // "C" starts the sequencer
1261 tk 139
    MIOS32_MIDI_SendDebugMessage("Start\n");
693 tk 140
    // if in auto mode and BPM generator is clocked in slave mode:
141
    // change to master mode
142
    SEQ_BPM_CheckAutoMaster();
143
    // start sequencer
144
    SEQ_BPM_Start();
145
    break;
146
 
147
      case 2: // "D" stops the sequencer. If pressed twice, the sequencer will be reset
1261 tk 148
    MIOS32_MIDI_SendDebugMessage("Stop\n");
693 tk 149
    if( SEQ_BPM_IsRunning() )
150
      SEQ_BPM_Stop();          // stop sequencer
151
    else
1261 tk 152
      SEQ_Reset(1);            // reset sequencer
693 tk 153
    break;
154
 
155
      case 4: // "E" pauses the sequencer
156
    // if in auto mode and BPM generator is clocked in slave mode:
157
    // change to master mode
158
    SEQ_BPM_CheckAutoMaster();
159
 
160
    // toggle pause mode
161
    seq_pause ^= 1;
162
 
1261 tk 163
    MIOS32_MIDI_SendDebugMessage("Pause %s\n", seq_pause ? "on" : "off");
164
 
693 tk 165
    // execute stop/continue depending on new mode
166
    if( seq_pause )
167
      SEQ_BPM_Stop();         // stop sequencer
168
    else
169
      SEQ_BPM_Cont();         // continue sequencer
170
    break;
171
 
172
      case 5: // "F" switches to next file
1261 tk 173
    MIOS32_MIDI_SendDebugMessage("Next File\n");
693 tk 174
    SEQ_PlayFileReq(1);
175
    break;
176
    }
177
  }
178
}
179
 
180
 
181
/////////////////////////////////////////////////////////////////////////////
182
// This hook is called before the shift register chain is scanned
183
/////////////////////////////////////////////////////////////////////////////
184
void APP_SRIO_ServicePrepare(void)
185
{
186
}
187
 
188
 
189
/////////////////////////////////////////////////////////////////////////////
190
// This hook is called after the shift register chain has been scanned
191
/////////////////////////////////////////////////////////////////////////////
192
void APP_SRIO_ServiceFinish(void)
193
{
194
}
195
 
196
 
197
/////////////////////////////////////////////////////////////////////////////
198
// This hook is called when a button has been toggled
199
// pin_value is 1 when button released, and 0 when button pressed
200
/////////////////////////////////////////////////////////////////////////////
201
void APP_DIN_NotifyToggle(u32 pin, u32 pin_value)
202
{
203
}
204
 
205
 
206
/////////////////////////////////////////////////////////////////////////////
207
// This hook is called when an encoder has been moved
208
// incrementer is positive when encoder has been turned clockwise, else
209
// it is negative
210
/////////////////////////////////////////////////////////////////////////////
211
void APP_ENC_NotifyChange(u32 encoder, s32 incrementer)
212
{
213
}
214
 
215
 
216
/////////////////////////////////////////////////////////////////////////////
217
// This hook is called when a pot has been moved
218
/////////////////////////////////////////////////////////////////////////////
219
void APP_AIN_NotifyChange(u32 pin, u32 pin_value)
220
{
221
}
222
 
223
 
224
/////////////////////////////////////////////////////////////////////////////
225
// This task is called periodically each mS to handle sequencer requests
226
/////////////////////////////////////////////////////////////////////////////
227
static void TASK_SEQ(void *pvParameters)
228
{
229
  portTickType xLastExecutionTime;
1261 tk 230
  u16 sdcard_check_ctr = 0;
693 tk 231
 
232
  // Initialise the xLastExecutionTime variable on task entry
233
  xLastExecutionTime = xTaskGetTickCount();
234
 
235
  while( 1 ) {
236
    vTaskDelayUntil(&xLastExecutionTime, 1 / portTICK_RATE_MS);
237
 
238
    // execute sequencer handler
239
    SEQ_Handler();
240
 
241
    // send timestamped MIDI events
242
    SEQ_MIDI_OUT_Handler();
243
 
1261 tk 244
    // each second: check if SD Card (still) available
693 tk 245
    if( ++sdcard_check_ctr >= 1000 ) {
246
      sdcard_check_ctr = 0;
247
 
1261 tk 248
      // use a mutex if multiple tasks access the SD Card!
249
      MUTEX_SDCARD_TAKE;
250
      s32 status = FILE_CheckSDCard();
693 tk 251
 
1261 tk 252
      if( status == 1 ) {
253
    MIOS32_MIDI_SendDebugMessage("SD Card connected: %s\n", FILE_VolumeLabel());
254
      } else if( status == 2 ) {
255
    MIOS32_MIDI_SendDebugMessage("SD Card disconnected\n");
693 tk 256
 
1261 tk 257
    // stop sequencer
258
    SEQ_BPM_Stop();
259
 
260
    // change filename
261
    sprintf(MID_FILE_UI_NameGet(), "No SD Card");
262
      } else if( status == 3 ) {
263
    if( !FILE_SDCardAvailable() ) {
264
      MIOS32_MIDI_SendDebugMessage("SD Card not found\n");
265
      // change filename
266
      sprintf(MID_FILE_UI_NameGet(), "No SD Card");
267
    } else if( !FILE_VolumeAvailable() ) {
268
      MIOS32_MIDI_SendDebugMessage("ERROR: SD Card contains invalid FAT!\n");
269
      MIOS32_BOARD_LED_Set(0x1, 0x0); // turn off LED
270
      // change filename
271
      sprintf(MID_FILE_UI_NameGet(), "No FAT");
272
      // stop sequencer
273
      SEQ_BPM_Stop();
693 tk 274
    } else {
1261 tk 275
      // change filename
276
      sprintf(MID_FILE_UI_NameGet(), "SDCard found");
693 tk 277
      // if in auto mode and BPM generator is clocked in slave mode:
278
      // change to master mode
279
      SEQ_BPM_CheckAutoMaster();
280
      // reset sequencer
1261 tk 281
      SEQ_Reset(1);
693 tk 282
      // request to play the first file
283
      SEQ_PlayFileReq(0);
284
      // start sequencer
285
      SEQ_BPM_Start();
286
    }
287
      }
1261 tk 288
      MUTEX_SDCARD_GIVE;
693 tk 289
    }
290
  }
291
}
292
 
293
/////////////////////////////////////////////////////////////////////////////
294
// Installed via MIOS32_MIDI_DirectRxCallback_Init
295
/////////////////////////////////////////////////////////////////////////////
296
static s32 NOTIFY_MIDI_Rx(mios32_midi_port_t port, u8 midi_byte)
297
{
298
  // here we could filter a certain port
299
  // The BPM generator will deliver inaccurate results if MIDI clock 
300
  // is received from multiple ports
301
  SEQ_BPM_NotifyMIDIRx(midi_byte);
302
 
303
  return 0; // no error, no filtering
304
}