1 /*---------------------------------------------------------------------------*
2   Project:  MIDI sequencer application for AX synthesizer
3   File:     seq.c
4 
5   Copyright (C)1998-2006 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   $Log: seq.c,v $
14   Revision 1.3  2006/01/31 06:35:21  aka
15   Changed arguments of SEQAddSequence().
16 
17   Revision 1.2  11/08/2005 01:43:00  aka
18   Changed suiting to Revolution's audio spec.
19 
20   Revision 1.1.1.1  2005/05/12 02:15:50  yasuh-to
21   Imported from dolphin tree.
22 
23     5     03/03/05 3:39p Akagi
24     Fixed timing of calling controller callback.
25 
26     4     6/14/02 1:35p Billyjack
27     - fix for tempo... used to be a tiny bit slow
28 
29     3     8/16/01 12:26p Billyjack
30     added zeroBuffer offset to API
31 
32     2     5/11/01 4:17p Billyjack
33     fixed problem with songs ending and set state to SEQ_STATE_RUN
34 
35     1     5/09/01 1:14p Billyjack
36     created
37 
38   $NoKeywords: $
39  *---------------------------------------------------------------------------*/
40 #include <revolution.h>
41 #include <revolution/seq.h>
42 
43 /*---------------------------------------------------------------------------*
44     parse MIDI chunk name
45  *---------------------------------------------------------------------------*/
46 #define __SEQChunkName(a, b, c, d)(   \
47             ((a & 0xff) << 24)  |   \
48             ((b & 0xff) << 16)  |   \
49             ((c & 0xff) << 8)   |   \
50             (d & 0xff))
51 
52 
53 /*---------------------------------------------------------------------------*
54     table for MIDI event length in bytes
55  *---------------------------------------------------------------------------*/
56 static u8 __SEQMidiEventLength[] =
57 {
58     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, //  0x80 - 0x8F
59     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, //  0x90 - 0x9F
60     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, //  0xA0 - 0xAF
61     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, //  0xB0 - 0xBF
62     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  0xC0 - 0xCF
63     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  0xD0 - 0xDF
64     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, //  0xE0 - 0xEF
65     0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  //  0xF0 - 0xFF
66 };
67 
68 /*---------------------------------------------------------------------------*
69     list of sequences to run
70  *---------------------------------------------------------------------------*/
71 static SEQSEQUENCE *__SEQSequenceList;
72 
73 
74 /*---------------------------------------------------------------------------*
75     push the specified sequence into the sequence list
76  *---------------------------------------------------------------------------*/
__SEQPushSequenceList(SEQSEQUENCE * sequence)77 static void __SEQPushSequenceList(SEQSEQUENCE *sequence)
78 {
79     int old;
80 
81     old = OSDisableInterrupts();
82 
83     if (__SEQSequenceList)
84         sequence->next      = __SEQSequenceList;
85     else
86         sequence->next      = NULL;
87 
88     __SEQSequenceList       = sequence;
89 
90     OSRestoreInterrupts(old);
91 }
92 
93 
94 /*---------------------------------------------------------------------------*
95     remove the specified sequence from list
96  *---------------------------------------------------------------------------*/
__SEQRemoveSequenceFromList(SEQSEQUENCE * sequence)97 static void __SEQRemoveSequenceFromList(SEQSEQUENCE *sequence)
98 {
99     int         old;
100     SEQSEQUENCE *thisSequence;
101 
102     old = OSDisableInterrupts();
103 
104     thisSequence        = __SEQSequenceList;
105     __SEQSequenceList   = NULL;
106 
107     while (thisSequence)
108     {
109         SEQSEQUENCE *next = thisSequence->next;
110 
111         if (thisSequence != sequence)
112             __SEQPushSequenceList(thisSequence);
113 
114         thisSequence = next;
115     }
116 
117     OSRestoreInterrupts(old);
118 }
119 
120 
121 /*---------------------------------------------------------------------------*
122     get MIDI variable length integer
123  *---------------------------------------------------------------------------*/
__SEQGetIntTrack(SEQTRACK * track)124 static u32 __SEQGetIntTrack(SEQTRACK *track)
125 {
126     u32 value;
127 
128     ASSERT(track);
129 
130     value = (u32)(*track->current & 0x7f);
131 
132     while (*track->current & 0x80)
133     {
134         track->current++;
135         value = (value << 7) + (*track->current & 0x7f);
136     }
137 
138     track->current++;
139 
140     return value;
141 }
142 
143 
144 /*---------------------------------------------------------------------------*
145     system exclusive events
146  *---------------------------------------------------------------------------*/
__SEQHandleSysExEvent(SEQTRACK * track)147 static void __SEQHandleSysExEvent(SEQTRACK *track)
148 {
149     u32 length;
150 
151     ASSERT(track);
152 
153     length              =   __SEQGetIntTrack(track);
154     track->current      +=  length;
155 }
156 
157 
158 /*---------------------------------------------------------------------------*
159     set the ticks per frame based on beats per second
160  *---------------------------------------------------------------------------*/
__SEQSetTicksPerFrame(SEQTRACK * track,f32 bps)161 static void __SEQSetTicksPerFrame(SEQTRACK *track, f32 bps)
162 {
163     SEQSEQUENCE *sequence;
164 
165     ASSERT(track);
166 
167     sequence = (SEQSEQUENCE*)track->sequence;
168 
169     track->beatsPerSec      = bps;
170     track->ticksPerFrame    =
171         (u32)(0x00010000 * (
172                   (f32)AX_IN_SAMPLES_PER_FRAME / (   // 160 samples / frame
173                       (f32)AX_IN_SAMPLES_PER_SEC  /  // 32000Hz
174                       bps /
175                       sequence->timeFormat)));
176 }
177 
178 
179 /*---------------------------------------------------------------------------*
180     handle tempo meta events
181  *---------------------------------------------------------------------------*/
__SEQTempoMetaEvent(SEQTRACK * track)182 static void __SEQTempoMetaEvent(SEQTRACK *track)
183 {
184     u32         data;
185     f32         beatsPerSec;
186 
187     data = (u32)(*track->current);
188     track->current++;
189     data = (data << 8) + (u32)(*track->current);
190     track->current++;
191     data = (data << 8) + (u32)(*track->current);
192     track->current++;
193 
194     beatsPerSec = 1000000.0f / data;
195 
196     __SEQSetTicksPerFrame(track, beatsPerSec);
197 }
198 
199 
200 /*---------------------------------------------------------------------------*
201     rewind the track to starting position
202  *---------------------------------------------------------------------------*/
__SEQTrackEnd(SEQTRACK * track)203 static void __SEQTrackEnd(SEQTRACK *track)
204 {
205     SEQSEQUENCE *sequence;
206 
207     ASSERT(track);
208 
209     sequence = track->sequence;
210     sequence->tracksRunning--;
211 
212     track->state = SEQ_STATE_STOP;
213 
214     if (sequence->tracksRunning == 0)
215         sequence->end = 1;
216 }
217 
218 /*---------------------------------------------------------------------------*
219     handle meta events
220  *---------------------------------------------------------------------------*/
__SEQHandleMetaEvent(SEQTRACK * track)221 static void __SEQHandleMetaEvent(SEQTRACK *track)
222 {
223     u8  type;
224     u32 length;
225 
226     ASSERT(track);
227 
228     type = *track->current;
229     track->current++;
230 
231     switch (type)
232     {
233     case 47:    // end of track
234 
235         __SEQTrackEnd(track);
236 
237         break;
238 
239     case 81:    // tempo
240 
241         length =   __SEQGetIntTrack(track);
242         __SEQTempoMetaEvent(track);
243 
244         break;
245 
246     default:
247 
248         length =   __SEQGetIntTrack(track);
249         track->current  +=  length;
250 
251         break;
252     }
253 }
254 
255 
256 /*---------------------------------------------------------------------------*
257     handle MIDI events to pass to the synth
258  *---------------------------------------------------------------------------*/
__SEQHandleSynthEvent(SYNSYNTH * synth,SEQTRACK * track)259 static void __SEQHandleSynthEvent(SYNSYNTH *synth, SEQTRACK *track)
260 {
261     u8  ch[3];
262     u32 bytes;
263 
264     bytes = __SEQMidiEventLength[track->status - 0x80];
265 
266     ch[0] = track->status;
267 
268     switch (bytes)
269     {
270     case 0:
271 
272         break;
273 
274     case 1:
275 
276         ch[1] = *track->current;
277         track->current++;
278 
279         break;
280 
281     case 2:
282 
283         ch[1] = *track->current;
284         track->current++;
285         ch[2] = *track->current;
286         track->current++;
287 
288         break;
289     }
290 
291     // perform controller callback if any
292     if ((ch[0] & 0xf0) == 0xb0)
293     {
294         SEQCALLBACK callback = ((SEQSEQUENCE*)(track->sequence))->callback[ch[1]];
295 
296         if (callback)
297             (*callback)(track, ch[1]);
298     }
299 
300     SYNMidiInput(synth, ch);
301 }
302 
303 
304 /*---------------------------------------------------------------------------*
305     run the next event on the MIDI stream
306  *---------------------------------------------------------------------------*/
__SEQRunEvent(SYNSYNTH * synth,SEQTRACK * track)307 static void __SEQRunEvent(SYNSYNTH *synth, SEQTRACK *track)
308 {
309     u8 event;
310 
311     ASSERT(synth);
312     ASSERT(track);
313 
314     event = *track->current;
315 
316     if (event >= 0x80)
317     {
318         track->status = event;
319         track->current++;
320     }
321 
322     switch (track->status)
323     {
324     case 0xf0:  // system exclusive
325     case 0xf7:  // special system exclusive
326 
327         __SEQHandleSysExEvent(track);
328 
329         break;
330 
331     case 0xff:  // meta events
332 
333         __SEQHandleMetaEvent(track);
334 
335         break;
336 
337     default:    // send the event to the synth
338 
339         __SEQHandleSynthEvent(synth, track);
340 
341         break;
342     }
343 
344     if (track->current >= track->end)
345         __SEQTrackEnd(track);
346 }
347 
348 
349 /*---------------------------------------------------------------------------*
350     initialize tracks
351  *---------------------------------------------------------------------------*/
__SEQInitTracks(SEQSEQUENCE * sequence,u8 * read,int tracks)352 static void __SEQInitTracks(SEQSEQUENCE *sequence, u8 *read, int tracks)
353 {
354     int i;
355     u8  *p;
356 
357     i = 0;
358     p = read;
359 
360     while (tracks)
361     {
362         while(1)
363         {
364             u32 chunk;
365             u32 bytes;
366 
367             chunk   = *(u32*)p; p += 4;
368             bytes   = *(u32*)p; p += 4;
369 
370             if (chunk == __SEQChunkName('M', 'T', 'r', 'k'))
371             {
372                 SEQTRACK *track = &sequence->track[i];
373 
374                 track->sequence             = sequence;
375                 track->start                = p;
376                 track->end                  = p + bytes;
377                 track->current              = p;
378                 track->defaultTicksPerFrame =
379                     (u32)(0x00010000 * (
380                               (f32)AX_IN_SAMPLES_PER_FRAME / (   // 160 samples / frame
381                                   60.0f / 120.0f *
382                                   (f32)AX_IN_SAMPLES_PER_SEC  /  // 32000Hz
383                                   sequence->timeFormat)));
384                 track->state                = SEQ_STATE_STOP;
385 
386                 p += bytes;
387 
388                 break;
389             }
390 
391             p += bytes;
392         }
393 
394         tracks--;
395         i++;
396     }
397 }
398 
399 
400 /*---------------------------------------------------------------------------*
401     reads header from MIDI stream
402  *---------------------------------------------------------------------------*/
__SEQReadHeader(SEQSEQUENCE * sequence,u8 * midiStream)403 static void __SEQReadHeader(SEQSEQUENCE *sequence, u8 *midiStream)
404 {
405     u8  *read;
406     u32 bytes;
407     u32 fileType;
408 
409     read = midiStream;
410 
411     ASSERTMSG(
412         *(u32*)read == __SEQChunkName('M', 'T', 'h', 'd'),
413         "!!!midiStream is not a valid MIDI file\n!!!"
414         );
415 
416     read += 4;
417 
418     bytes = *(u32*)read;
419 
420     read += 4;
421 
422     fileType                = *(u16*)(read);    read += 2;
423     sequence->nTracks       = *(u16*)(read);    read += 2;
424     sequence->timeFormat    = *(s16*)(read);    read += 2;
425 
426     ASSERTMSG(
427         sequence->timeFormat >= 0,
428         "!!!SEQ does not support SMPTE time!!!\n"
429         );
430 
431     bytes -= 6;
432 
433     read += bytes;
434 
435     // load up tracks according to file type
436     switch (fileType)
437     {
438     case 0: // type 0 only play first track
439 
440         sequence->nTracks = 1;
441 
442         __SEQInitTracks(sequence, read, 1);
443 
444         break;
445 
446     case 1:
447 
448         ASSERTMSG(
449             sequence->nTracks < SEQ_MAX_TRACKS,
450             "exceeded SEQ_MAX_TRACKS, please increase SEQ_MAX_TRACKS\n"
451             );
452 
453         __SEQInitTracks(sequence, read, sequence->nTracks);
454 
455         break;
456 
457     default:
458 
459         ASSERTMSG(0, "!!!Invalid MIDI file type\n!!!");
460 
461         break;
462     }
463 
464     sequence->tracksRunning = sequence->nTracks;
465 }
466 
467 
468 /*---------------------------------------------------------------------------*
469     Exposed API functions
470  *---------------------------------------------------------------------------*/
471 
472 /*---------------------------------------------------------------------------*
473     initialize the sequencer
474  *---------------------------------------------------------------------------*/
SEQInit(void)475 void SEQInit(void)
476 {
477     __SEQSequenceList = NULL;
478 }
479 
480 
481 /*---------------------------------------------------------------------------*
482     quit the sequencer gracefully
483  *---------------------------------------------------------------------------*/
SEQQuit(void)484 void SEQQuit(void)
485 {
486     __SEQSequenceList = NULL;
487 }
488 
489 
490 /*---------------------------------------------------------------------------*
491     run one audio frame's worth of events
492  *---------------------------------------------------------------------------*/
SEQRunAudioFrame(void)493 void SEQRunAudioFrame(void)
494 {
495     SEQSEQUENCE *sequence = __SEQSequenceList;
496 
497     // go through all the sequences
498     while (sequence)
499     {
500         if ((sequence->state == SEQ_STATE_RUN) ||
501             (sequence->state == SEQ_STATE_RUNLOOPED))
502         {
503             u32 i;
504 
505             for (i = 0; i < sequence->nTracks; i++)
506             {
507                 SEQTRACK *track = &sequence->track[i];
508 
509                 if ((track->state == SEQ_STATE_RUN) ||
510                     (track->state == SEQ_STATE_RUNLOOPED))
511                 {
512                     u32 ticks = track->ticksPerFrame;
513 
514                     if (track->delay > ticks)
515                     {
516                         track->delay -= ticks;
517                     }
518                     else
519                     {
520                         while (ticks >= track->delay)
521                         {
522                             ticks -= track->delay;
523                             __SEQRunEvent(&sequence->synth, track);
524 
525                             if (track->state == SEQ_STATE_STOP)
526                                 break;
527 
528                             track->delay =  __SEQGetIntTrack(track) << 16;
529                         }
530 
531                         track->delay -= ticks;
532                     }
533                 }
534             }
535         }
536 
537         if (sequence->end)
538         {
539             if (sequence->state == SEQ_STATE_RUNLOOPED)
540             {
541                 SEQSetState(sequence, SEQ_STATE_STOP);
542                 SEQSetState(sequence, SEQ_STATE_RUNLOOPED);
543             }
544             else
545             {
546                 SEQSetState(sequence, SEQ_STATE_STOP);
547             }
548         }
549 
550         sequence = sequence->next;
551     }
552 }
553 
554 
555 /*---------------------------------------------------------------------------*
556     initialize and add the specified sequence to sequence list
557  *---------------------------------------------------------------------------*/
558 void
SEQAddSequence(SEQSEQUENCE * sequence,u8 * midiStream,u8 * wavetable,u8 * samples,u8 * zerobuffer,u32 priorityVoiceAlloc,u32 priorityNoteOn,u32 priorityNoteRelease)559 SEQAddSequence(
560     SEQSEQUENCE     *sequence,          // user allocated SEQSEQUENCE
561     u8              *midiStream,        // pointer to MIDI stream
562     u8              *wavetable,         // pointer to wave table
563     u8              *samples,           // pointer to samples
564     u8              *zerobuffer,        // pointer to zero buffer
565     u32             priorityVoiceAlloc, // priority for allocating notes
566     u32             priorityNoteOn,     // priority for notes that are on
567     u32             priorityNoteRelease // priority for notes in release stage
568     )
569 {
570     int i;
571 
572     ASSERT(sequence);
573     ASSERT(midiStream);
574     ASSERT(wavetable);
575     ASSERT(samples);
576     ASSERT(zerobuffer);
577     ASSERT((priorityVoiceAlloc < 32) && (priorityVoiceAlloc > 0));
578     ASSERT((priorityNoteOn < 32) && (priorityNoteOn > 0));
579     ASSERT((priorityNoteRelease < 32) && (priorityNoteRelease > 0));
580 
581     // initialize the synth
582     SYNInitSynth(
583         &sequence->synth,
584         wavetable,
585         samples,
586         zerobuffer,
587         priorityVoiceAlloc,
588         priorityNoteOn,
589         priorityNoteRelease
590         );
591 
592     // initialize data members
593     sequence->state = SEQ_STATE_STOP;
594 
595     // 0 controller callbacks
596     for (i = 0; i < 128; i++)
597     {
598         sequence->callback[i] = NULL;
599     }
600 
601     // read the MIDI file header
602     __SEQReadHeader(sequence, midiStream);
603 
604     // put it in a list of sequences to service
605     __SEQPushSequenceList(sequence);
606 }
607 
608 
609 /*---------------------------------------------------------------------------*
610     remove the specified sequence from sequence list
611  *---------------------------------------------------------------------------*/
SEQRemoveSequence(SEQSEQUENCE * sequence)612 void SEQRemoveSequence(SEQSEQUENCE *sequence)
613 {
614     ASSERT(sequence);
615 
616     // remove from list of running sequences
617     __SEQRemoveSequenceFromList(sequence);
618 
619     // shut down the synth for the sequence
620     SYNQuitSynth(&sequence->synth);
621 }
622 
623 
624 /*---------------------------------------------------------------------------*
625     register callback for controller event
626  *---------------------------------------------------------------------------*/
SEQRegisterControllerCallback(SEQSEQUENCE * sequence,u8 controller,SEQCALLBACK callback)627 void SEQRegisterControllerCallback(
628             SEQSEQUENCE     *sequence,          // user initialized SEQSEQUENCE
629             u8              controller,         // MIDI controller
630             SEQCALLBACK     callback            // callback function
631             )
632 {
633     ASSERT(sequence);
634     ASSERT(controller < 128);
635     ASSERT(callback);
636 
637     sequence->callback[controller] = callback;
638 }
639 
640 
641 /*---------------------------------------------------------------------------*
642     set specified sequence to specified state
643  *---------------------------------------------------------------------------*/
SEQSetState(SEQSEQUENCE * sequence,u32 state)644 void SEQSetState(SEQSEQUENCE *sequence, u32 state)
645 {
646     int i;
647 
648     ASSERT(sequence);
649 
650     switch (state)
651     {
652     case SEQ_STATE_RUN:
653     case SEQ_STATE_RUNLOOPED:
654 
655         // if the previous state was SEQ_STATE_STOP start the tracks from
656         // the beginning
657         if (sequence->state == SEQ_STATE_STOP)
658         {
659             int old = OSDisableInterrupts();
660 
661             for (i = 0; i < sequence->nTracks; i++)
662             {
663 
664                 SEQTRACK *track = &sequence->track[i];
665 
666 
667                 track->current          = track->start;
668                 track->ticksPerFrame    = track->defaultTicksPerFrame;
669                 track->delay            = __SEQGetIntTrack(track) << 16;
670                 track->state            = SEQ_STATE_RUN;
671 
672             }
673 
674             sequence->tracksRunning = sequence->nTracks;
675 
676             OSRestoreInterrupts(old);
677         }
678 
679         sequence->end = 0;
680 
681         break;
682 
683         // we also to silence all sounds from the synth
684     case SEQ_STATE_STOP:
685     case SEQ_STATE_PAUSE:
686 
687         for (i = 0; i < 16; i++)
688         {
689             int old;
690 
691             u8 ch[3];
692 
693             old = OSDisableInterrupts();
694 
695             ch[0] = (u8)(0xb0 | i);
696             ch[1] = 0x7b;
697             ch[2] = 0;
698 
699             SYNMidiInput(&sequence->synth, ch);
700 
701             OSRestoreInterrupts(old);
702         }
703 
704         break;
705     }
706 
707     sequence->state = state;
708 }
709 
710 
711 /*---------------------------------------------------------------------------*
712     get current state of sequence
713  *---------------------------------------------------------------------------*/
SEQGetState(SEQSEQUENCE * sequence)714 u32 SEQGetState(SEQSEQUENCE *sequence)
715 {
716     ASSERT(sequence);
717 
718     return sequence->state;
719 }
720 
721 
722 /*---------------------------------------------------------------------------*
723     set specified track(s) or specified sequence to specified BPM
724  *---------------------------------------------------------------------------*/
SEQSetTempo(SEQSEQUENCE * sequence,u32 trackIndex,f32 bpm)725 void SEQSetTempo(SEQSEQUENCE *sequence, u32 trackIndex, f32 bpm)
726 {
727     ASSERT(sequence);
728     ASSERT((trackIndex < sequence->nTracks) || (trackIndex == SEQ_ALL_TRACKS));
729 
730     if (trackIndex == SEQ_ALL_TRACKS)
731     {
732         int i;
733 
734         for (i = 0; i < sequence->nTracks; i++)
735             __SEQSetTicksPerFrame(&sequence->track[i], bpm / 60);
736     }
737     else
738     {
739         __SEQSetTicksPerFrame(&sequence->track[trackIndex], bpm / 60);
740     }
741 }
742 
743 
744 /*---------------------------------------------------------------------------*
745     get current tempo for specified track of specified sequencer
746  *---------------------------------------------------------------------------*/
SEQGetTempo(SEQSEQUENCE * sequence,u32 trackIndex)747 f32 SEQGetTempo(SEQSEQUENCE *sequence, u32 trackIndex)
748 {
749     ASSERT(sequence);
750     ASSERT(trackIndex < sequence->nTracks);
751 
752     return sequence->track[trackIndex].beatsPerSec * 60;
753 }
754 
755 
756 /*---------------------------------------------------------------------------*
757     set specified sequence to specified volume 0x00010000 = 0.1dB
758  *---------------------------------------------------------------------------*/
SEQSetVolume(SEQSEQUENCE * sequence,s32 dB)759 void SEQSetVolume(SEQSEQUENCE *sequence, s32 dB)
760 {
761     ASSERT(sequence);
762 
763     SYNSetMasterVolume(&sequence->synth, dB);
764 }
765 
766 
767 /*---------------------------------------------------------------------------*
768     get current volume for specified sequence
769  *---------------------------------------------------------------------------*/
SEQGetVolume(SEQSEQUENCE * sequence)770 s32 SEQGetVolume(SEQSEQUENCE *sequence)
771 {
772     ASSERT(sequence);
773 
774     return SYNGetMasterVolume(&sequence->synth);
775 }
776