1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - SND - demos - seq
3 File: seq.c
4
5 Copyright 2007-2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Date:: 2008-09-18#$
14 $Rev: 8573 $
15 $Author: okubata_ryoma $
16 *---------------------------------------------------------------------------*/
17 #include "seq.h"
18 #include "smfdefine.h"
19
20 /* Status constants. */
21 #define SEQ_STATE_PLAY 0x01 /* Playing */
22 #define SEQ_STATE_END 0x02 /* End of playback (end of track) */
23 #define SEQ_STATE_LOOP 0x04 /* Loop flag */
24 #define SEQ_STATE_MUTE 0x10 /* Mute */
25
26 /* Default tempo = 120 BPM (microseconds) */
27 #define SEQ_DEFAULT_TEMPO 500000
28
29 /* System exclusive buffer size (ignores the message when over size) */
30 #define SEQ_SYSX_BUFFER_SIZE 64
31
32
33 static u8 SeqReadVariableData(const u8 *data, u32 *result);
34 static u8 SeqReadSMFHeader(SeqHandle * block, const u8 *data);
35 static u8 SeqExecMetaEvent(SeqHandle * block);
36
37 static u16 ReverseEndian16(u16 data);
38 static u32 ReverseEndian32(u32 data);
39
40 typedef struct tSeqSystemBlock
41 {
42 void (*callback) (const u8 *);
43 u32 clock_interval; /* Time interval that calls SeqMain. Units in microseconds. */
44 }
45 SeqSystemBlock;
46
47 SeqSystemBlock seq_sys;
48
49 /* Data byte number of each MIDI event */
50 static const u8 seq_midi_byte_size[8] = {
51 /* 8x,9x,Ax,Bx,Cx,Dx,Ex,Fx*/
52 2, 2, 2, 2, 1, 1, 2, 0
53 };
54
55 /* System exclusive buffer */
56 static u8 seqSysxBuffer[SEQ_SYSX_BUFFER_SIZE];
57
58 /* Saves the error code at time of an error */
59 static u8 seqErrorCode;
60
61 /*---------------------------------------------------------------------------*
62 Name: SeqInit
63
64 Description: Initializes the sequence system.
65
66 Arguments: clock_interval: Time interval that calls SeqMain. Units in microseconds.
67 callback: Configures the function called when a MIDI event occurs.
68
69 Returns: None.
70 *---------------------------------------------------------------------------*/
SeqInit(u32 clock_interval,void (* callback)(const u8 *))71 void SeqInit(u32 clock_interval, void (*callback) (const u8 *))
72 {
73 seq_sys.callback = callback; // Saves the callback function
74 seq_sys.clock_interval = clock_interval; // Saves the call interval
75 }
76
77 /*---------------------------------------------------------------------------*
78 Name: SeqMain
79
80 Description: The main routine of the sequencer.
81
82 Arguments: handle: Song handle that executes a process
83
84 Returns: TRUE if an error occurs.
85 *---------------------------------------------------------------------------*/
SeqMain(SeqHandle * handle)86 BOOL SeqMain(SeqHandle * handle)
87 {
88 u8 read_size;
89 u8 current_event;
90 u8 f_exist_status; /* Whether there are MIDI event instructions (whether currently in running status) */
91
92 /* Returns as-is when not in a playback state */
93 if (!(handle->state & SEQ_STATE_PLAY))
94 {
95 return FALSE;
96 }
97
98 /* Progresses 1 callback's worth of time */
99 handle->time_control += handle->time_per_callback;
100
101 while (handle->time_control > handle->tempo)
102 {
103 /* Process for each tick */
104
105 /* Subtracts delta time */
106 if (handle->delta_time > 0)
107 {
108 handle->delta_time--;
109 }
110
111 while (handle->delta_time == 0)
112 {
113
114 /* Delta time reached 0, so an event is executed */
115 handle->current_ptr += handle->next_delta_bytesize;
116
117 /* current_ptr is the start of a MIDI message */
118 if (*handle->current_ptr >= 0x80)
119 {
120 /* Running status is configured because of starting from an instruction */
121 current_event = handle->running_status = *handle->current_ptr;
122 f_exist_status = 1;
123 }
124 else
125 {
126 /* Running status is used because of starting from a value */
127 if (handle->running_status < 0x80)
128 {
129 seqErrorCode = SEQ_ERROR_WRONG_TRACK;
130 return TRUE; /* Error */
131 }
132 current_event = handle->running_status;
133 f_exist_status = 0;
134 }
135
136 if (*handle->current_ptr == SMF_META)
137 {
138
139 /* The meta event is an operation within the sequencer */
140 read_size = SeqExecMetaEvent(handle);
141
142 if (handle->state & SEQ_STATE_END)
143 {
144 /* END OF TRACK: Finished playing a song to the end. */
145 (void)SeqStop(handle);
146 handle->state &= ~SEQ_STATE_END;
147 return FALSE;
148 }
149 else if (handle->state & SEQ_STATE_LOOP)
150 {
151 /* LOOP END: Return to the starting position of a loop. */
152 handle->current_ptr = handle->loop_begin;
153 handle->state &= ~SEQ_STATE_LOOP;
154 }
155 else
156 {
157 /* Proceed to the next event */
158 handle->current_ptr += read_size;
159 }
160
161 }
162 else /* Other than meta-event */
163 {
164 if (*handle->current_ptr == SMF_SYSX)
165 {
166 /* System exclusive */
167
168 if (SEQ_SYSX_BUFFER_SIZE > handle->current_ptr[1] + 1)
169 {
170 u8 i;
171
172 /* Copy to buffer */
173 seqSysxBuffer[0] = handle->current_ptr[0];
174 for (i = 1; i <= handle->current_ptr[1]; i++)
175 {
176 seqSysxBuffer[i] = handle->current_ptr[i + 1];
177 }
178
179 /* Send the MIDI event to the callback */
180 seq_sys.callback(seqSysxBuffer);
181 }
182
183 /* Proceed to the next event */
184 handle->current_ptr += handle->current_ptr[1] + 2;
185 }
186 else
187 {
188 /* Short MIDI event */
189
190 /* Send the MIDI event to the callback */
191 seq_sys.callback(handle->current_ptr);
192
193 /* Proceed to the next event */
194 handle->current_ptr +=
195 seq_midi_byte_size[(current_event >> 4) - 8] + f_exist_status;
196 }
197 }
198
199 /* Read the delta time of the next event */
200 handle->next_delta_bytesize =
201 SeqReadVariableData(handle->current_ptr, &handle->delta_time);
202 if (handle->next_delta_bytesize == 0)
203 {
204 return TRUE; /* Error */
205 }
206 }
207
208 /* Advance tick */
209 handle->total_tick++;
210
211 /* Advance time */
212 handle->time_control -= handle->tempo;
213 }
214 return FALSE;
215 }
216
217 /*---------------------------------------------------------------------------*
218 Name: SeqExecMetaEvent
219
220 Description: Meta-event process routine.
221
222 Arguments: handle: Song handle that executes a process
223
224 Returns: Meta-event byte size.
225 *---------------------------------------------------------------------------*/
SeqExecMetaEvent(SeqHandle * handle)226 static u8 SeqExecMetaEvent(SeqHandle * handle)
227 {
228 switch (handle->current_ptr[1])
229 {
230 case SMF_META_MARKER: /* Marker */
231 if (handle->current_ptr[2] != 1)
232 {
233 break;
234 }
235
236 /* NITRO Composer compatible loop functionality */
237 if (handle->current_ptr[3] == '[')
238 {
239 /* Loop start position */
240 handle->loop_begin = handle->current_ptr + handle->current_ptr[2] + 3;
241 }
242 else if (handle->current_ptr[3] == ']')
243 {
244 /* Loop end position */
245 if (handle->loop_begin != NULL)
246 {
247 handle->state |= SEQ_STATE_LOOP;
248 }
249 }
250 break;
251 case SMF_META_ENDOFTRACK: /* End of track */
252 handle->state |= SEQ_STATE_END;
253 break;
254 case SMF_META_TEMPO: /* Set tempo */
255 handle->tempo = handle->current_ptr[3];
256 handle->tempo <<= 8;
257 handle->tempo += handle->current_ptr[4];
258 handle->tempo <<= 8;
259 handle->tempo += handle->current_ptr[5];
260 break;
261 default:
262 break;
263 }
264
265 return (u8)(handle->current_ptr[2] + 3);
266 }
267
268 /*---------------------------------------------------------------------------*
269 Name: SeqPlay
270
271 Description: Starts SMF data playback.
272
273 Arguments: handle: Song handle that executes a process
274 smfdata: SMF data
275
276 Returns: Meta-event byte size.
277 *---------------------------------------------------------------------------*/
SeqPlay(SeqHandle * handle,const u8 * smfdata)278 BOOL SeqPlay(SeqHandle * handle, const u8 *smfdata)
279 {
280 u8 read_size;
281 static const u8 mtrk[] = "MTrk";
282 u8 i;
283
284 /* Reads the SMF header chunk */
285 read_size = SeqReadSMFHeader(handle, smfdata);
286 if (read_size == 0)
287 return TRUE; /* Error */
288
289 handle->current_ptr = smfdata + read_size;
290
291 /* Reads track chunk header */
292 /* 'MTrk' check */
293 for (i = 0; i < 4; i++)
294 {
295 if (handle->current_ptr[i] != mtrk[i])
296 {
297 seqErrorCode = SEQ_ERROR_WRONG_TRACK; /* Error */
298 return TRUE;
299 }
300 }
301 handle->current_ptr += sizeof(u8) * 4;
302 /* Chunk size */
303 handle->chunk_size = ReverseEndian32(*(u32 *)handle->current_ptr);
304 handle->current_ptr += sizeof(u32);
305
306 /* Track head */
307 handle->track_begin = handle->current_ptr;
308
309 /* Initial settings */
310 handle->tempo = SEQ_DEFAULT_TEMPO;
311 handle->time_control = 0;
312 handle->time_per_callback = handle->division * seq_sys.clock_interval;
313 handle->total_tick = 0;
314 handle->running_status = 0x00;
315 handle->loop_begin = NULL;
316
317 /* Status variable settings */
318 handle->state = SEQ_STATE_PLAY;
319
320 /* Reads the initial delta time */
321 handle->next_delta_bytesize = SeqReadVariableData(handle->current_ptr, &handle->delta_time);
322 if (handle->next_delta_bytesize == 0)
323 {
324 seqErrorCode = SEQ_ERROR_WRONG_TRACK;
325 return TRUE; /* Error */
326 }
327
328 return FALSE;
329 }
330
331 /*---------------------------------------------------------------------------*
332 Name: SeqStop
333
334 Description: Stops SMF data playback.
335
336 Arguments: handle: Song handle that executes a process
337
338 Returns: None.
339 *---------------------------------------------------------------------------*/
SeqStop(SeqHandle * handle)340 void SeqStop(SeqHandle * handle)
341 {
342 handle->current_ptr = handle->track_begin;
343
344 /* Status variable settings */
345 handle->state &= ~SEQ_STATE_PLAY;
346 }
347
348 /*---------------------------------------------------------------------------*
349 Name: SeqPause
350
351 Description: Pauses SMF data playback.
352
353 Arguments: handle: Song handle that executes a process
354
355 Returns: None.
356 *---------------------------------------------------------------------------*/
SeqPause(SeqHandle * handle)357 void SeqPause(SeqHandle * handle)
358 {
359 /* Status variable settings */
360 handle->state &= ~SEQ_STATE_PLAY;
361 }
362
363 /*---------------------------------------------------------------------------*
364 Name: SeqReadSMFHeader
365
366 Description: Reads the SMF header chunk.
367
368 Arguments: handle: Song handle that executes a process
369 data: SMF data string
370
371 Returns: Number of bytes read. Normally 14.
372 *---------------------------------------------------------------------------*/
SeqReadSMFHeader(SeqHandle * handle,const u8 * data)373 static u8 SeqReadSMFHeader(SeqHandle * handle, const u8 *data)
374 {
375 static const u8 mthd[] = "MThd";
376 u8 i;
377 const u8 *ptr = data;
378
379 /* All data that is fixed in a format other than 0 is considered an error. */
380
381 /* 'MThd' check */
382 for (i = 0; i < 4; i++)
383 {
384 if (ptr[i] != mthd[i])
385 {
386 seqErrorCode = SEQ_ERROR_WRONG_HEADER; /* Error */
387 return 0;
388 }
389 }
390 ptr += sizeof(u8) * 4;
391
392 /* The length of the header chunk data is 6 bytes */
393 if (ReverseEndian32(*(u32 *)ptr) != 6)
394 {
395 seqErrorCode = SEQ_ERROR_WRONG_HEADER; /* Error */
396 return 0;
397 }
398 ptr += sizeof(u32);
399
400 /* Only handles format 0 */
401 if (*(u16 *)ptr != SMF_FORMAT0)
402 {
403 seqErrorCode = SEQ_ERROR_NOT_FORMAT0; /* Error */
404 return 0;
405 }
406 ptr += sizeof(u16);
407
408 /* Error if there is other than 1 track */
409 if (ReverseEndian16(*(u16 *)ptr) != 1)
410 {
411 seqErrorCode = SEQ_ERROR_WRONG_HEADER; /* Error */
412 return 0;
413 }
414 ptr += sizeof(u16);
415
416 /* Saves the resolution */
417 handle->division = ReverseEndian16(*(u16 *)ptr);
418 if (handle->division >= 0x8000)
419 {
420 seqErrorCode = SEQ_ERROR_DIVISION_TIMECODE; /* Error */
421 return 0;
422 }
423 ptr += sizeof(u16);
424
425 return (u8)(ptr - data);
426 }
427
428 /*---------------------------------------------------------------------------*
429 Name: SeqReadVariableData
430
431 Description: Routine for reading variable length data.
432
433 Arguments: data: Variable length SMFMIDI data string
434 result: Area for storing the read numerical value
435
436 Returns: Number of bytes read. The maximum is 4 bytes in SMF, so anything above that is considered an error and returns 0.
437
438 *---------------------------------------------------------------------------*/
SeqReadVariableData(const u8 * data,u32 * result)439 static u8 SeqReadVariableData(const u8 *data, u32 *result)
440 {
441 u8 count = 0;
442 *result = 0;
443
444 while (*data & 0x80)
445 {
446 /* Continuous bytes */
447 *result = (*result << 7) + (*data & 0x7f);
448 count++;
449 if (count == 4)
450 {
451 /* The 4th byte is not the final byte, so this is an error */
452 seqErrorCode = SEQ_ERROR_WRONG_DELTA_TIME;
453 return 0;
454 }
455 data++;
456 }
457
458 /* Final byte */
459 *result = (*result << 7) + *data;
460 count++;
461
462 return count;
463 }
464
465 /*---------------------------------------------------------------------------*
466 Name: ReverseEndian16
467
468 Description: Endian conversion (2 bytes).
469
470 Arguments: data: The data to convert
471
472 Returns: Endian converted data.
473 *---------------------------------------------------------------------------*/
ReverseEndian16(u16 data)474 static u16 ReverseEndian16(u16 data)
475 {
476 return (u16)(((data & 0x00ff) << 8) | ((data & 0xff00) >> 8));
477 }
478
479 /*---------------------------------------------------------------------------*
480 Name: ReverseEndian32
481
482 Description: Endian conversion (4 bytes).
483
484 Arguments: data: The data to convert
485
486 Returns: Endian converted data.
487 *---------------------------------------------------------------------------*/
ReverseEndian32(u32 data)488 static u32 ReverseEndian32(u32 data)
489 {
490 return (((data >> 24) & 0x000000ff) |
491 ((data >> 8) & 0x0000ff00) | ((data << 8) & 0x00ff0000) | ((data << 24) & 0xff000000));
492 }
493
494 /*---------------------------------------------------------------------------*/
SeqGetErrorCode(void)495 u8 SeqGetErrorCode(void)
496 {
497 return seqErrorCode;
498 }
499