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