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