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