1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * The core MIDI file player.
12 *
13 * By Shawn Hargreaves.
14 *
15 * Pause and seek functions by George Foot.
16 *
17 * get_midi_length by Elias Pschernig.
18 *
19 * See readme.txt for copyright information.
20 */
21
22
23 #include <limits.h>
24 #include <string.h>
25
26 #include "allegro.h"
27 #include "allegro/internal/aintern.h"
28
29
30
31 /* maximum number of layers in a single voice */
32 #define MIDI_LAYERS 4
33
34 /* how often the midi callback gets called maximally / second */
35 #define MIDI_TIMER_FREQUENCY 40
36
37
38 typedef struct MIDI_TRACK /* a track in the MIDI file */
39 {
40 unsigned char *pos; /* position in track data */
41 long timer; /* time until next event */
42 unsigned char running_status; /* last MIDI event */
43 } MIDI_TRACK;
44
45
46 typedef struct MIDI_CHANNEL /* a MIDI channel */
47 {
48 int patch; /* current sound */
49 int volume; /* volume controller */
50 int pan; /* pan position */
51 int pitch_bend; /* pitch bend position */
52 int new_volume; /* cached volume change */
53 int new_pitch_bend; /* cached pitch bend */
54 int note[128][MIDI_LAYERS]; /* status of each note */
55 } MIDI_CHANNEL;
56
57
58 typedef struct MIDI_VOICE /* a voice on the soundcard */
59 {
60 int channel; /* MIDI channel */
61 int note; /* note (-1 = off) */
62 int volume; /* note velocity */
63 long time; /* when note was triggered */
64 } MIDI_VOICE;
65
66
67 typedef struct WAITING_NOTE /* a stored note-on request */
68 {
69 int channel;
70 int note;
71 int volume;
72 } WAITING_NOTE;
73
74
75 typedef struct PATCH_TABLE /* GM -> external synth */
76 {
77 int bank1; /* controller #0 */
78 int bank2; /* controller #32 */
79 int prog; /* program change */
80 int pitch; /* pitch shift */
81 } PATCH_TABLE;
82
83
84 volatile long midi_pos = -1; /* current position in MIDI file */
85 volatile long midi_time = 0; /* current position in seconds */
86 static volatile long midi_timers; /* current position in allegro-timer-ticks */
87 static long midi_pos_counter; /* delta for midi_pos */
88
89 volatile long _midi_tick = 0; /* counter for killing notes */
90
91 static void midi_player(void); /* core MIDI player routine */
92 static void prepare_to_play(MIDI *midi);
93 static void midi_lock_mem(void);
94
95 static MIDI *midifile = NULL; /* the file that is playing */
96
97 static int midi_loop = 0; /* repeat at eof? */
98
99 long midi_loop_start = -1; /* where to loop back to */
100 long midi_loop_end = -1; /* loop at this position */
101
102 static int midi_semaphore = 0; /* reentrancy flag */
103 static int midi_loaded_patches = FALSE; /* loaded entire patch set? */
104
105 static long midi_timer_speed; /* midi_player's timer speed */
106 static int midi_pos_speed; /* MIDI delta -> midi_pos */
107 static int midi_speed; /* MIDI delta -> timer */
108 static int midi_new_speed; /* for tempo change events */
109
110 static int old_midi_volume = -1; /* stored global volume */
111
112 static int midi_alloc_channel; /* so _midi_allocate_voice */
113 static int midi_alloc_note; /* knows which note the */
114 static int midi_alloc_vol; /* sound is associated with */
115
116 static MIDI_TRACK midi_track[MIDI_TRACKS]; /* the active tracks */
117 static MIDI_VOICE midi_voice[MIDI_VOICES]; /* synth voice status */
118 static MIDI_CHANNEL midi_channel[16]; /* MIDI channel info */
119 static WAITING_NOTE midi_waiting[MIDI_VOICES]; /* notes still to be played */
120 static PATCH_TABLE patch_table[128]; /* GM -> external synth */
121
122 static int midi_seeking; /* set during seeks */
123 static int midi_looping; /* set during loops */
124
125 /* hook functions */
126 void (*midi_msg_callback)(int msg, int byte1, int byte2) = NULL;
127 void (*midi_meta_callback)(int type, AL_CONST unsigned char *data, int length) = NULL;
128 void (*midi_sysex_callback)(AL_CONST unsigned char *data, int length) = NULL;
129
130
131
132 /* lock_midi:
133 * Locks a MIDI file into physical memory. Pretty important, since they
134 * are mostly accessed inside interrupt handlers.
135 */
lock_midi(MIDI * midi)136 void lock_midi(MIDI *midi)
137 {
138 int c;
139 ASSERT(midi);
140
141 LOCK_DATA(midi, sizeof(MIDI));
142
143 for (c=0; c<MIDI_TRACKS; c++) {
144 if (midi->track[c].data) {
145 LOCK_DATA(midi->track[c].data, midi->track[c].len);
146 }
147 }
148 }
149
150
151
152 /* load_midi:
153 * Loads a standard MIDI file, returning a pointer to a MIDI structure,
154 * or NULL on error.
155 */
load_midi(AL_CONST char * filename)156 MIDI *load_midi(AL_CONST char *filename)
157 {
158 PACKFILE *f;
159 MIDI *midi;
160 ASSERT(filename);
161
162 f = pack_fopen(filename, F_READ);
163 if (!f)
164 return NULL;
165
166 midi = load_midi_pf(f);
167
168 pack_fclose(f);
169
170 return midi;
171 }
172
173
174
175 /* load_midi_pf:
176 * Reads a standard MIDI file from the packfile given, returning a MIDI
177 * structure, or NULL on error.
178 *
179 * If unsuccessful the offset into the file is unspecified, i.e. you must
180 * either reset the offset to some known place or close the packfile. The
181 * packfile is not closed by this function.
182 */
load_midi_pf(PACKFILE * fp)183 MIDI *load_midi_pf(PACKFILE *fp)
184 {
185 int c;
186 char buf[4];
187 long data;
188 MIDI *midi;
189 int num_tracks;
190 ASSERT(fp);
191
192 midi = _AL_MALLOC(sizeof(MIDI)); /* get some memory */
193 if (!midi)
194 return NULL;
195
196 for (c=0; c<MIDI_TRACKS; c++) {
197 midi->track[c].data = NULL;
198 midi->track[c].len = 0;
199 }
200
201 pack_fread(buf, 4, fp); /* read midi header */
202
203 /* Is the midi inside a .rmi file? */
204 if (memcmp(buf, "RIFF", 4) == 0) { /* check for RIFF header */
205 pack_mgetl(fp);
206
207 while (!pack_feof(fp)) {
208 pack_fread(buf, 4, fp); /* RMID chunk? */
209 if (memcmp(buf, "RMID", 4) == 0) break;
210
211 pack_fseek(fp, pack_igetl(fp)); /* skip to next chunk */
212 }
213
214 if (pack_feof(fp)) goto err;
215
216 pack_mgetl(fp);
217 pack_mgetl(fp);
218 pack_fread(buf, 4, fp); /* read midi header */
219 }
220
221 if (memcmp(buf, "MThd", 4))
222 goto err;
223
224 pack_mgetl(fp); /* skip header chunk length */
225
226 data = pack_mgetw(fp); /* MIDI file type */
227 if ((data != 0) && (data != 1))
228 goto err;
229
230 num_tracks = pack_mgetw(fp); /* number of tracks */
231 if ((num_tracks < 1) || (num_tracks > MIDI_TRACKS))
232 goto err;
233
234 data = pack_mgetw(fp); /* beat divisions */
235 midi->divisions = ABS(data);
236
237 for (c=0; c<num_tracks; c++) { /* read each track */
238 pack_fread(buf, 4, fp); /* read track header */
239 if (memcmp(buf, "MTrk", 4))
240 goto err;
241
242 data = pack_mgetl(fp); /* length of track chunk */
243 midi->track[c].len = data;
244
245 midi->track[c].data = _AL_MALLOC_ATOMIC(data); /* allocate memory */
246 if (!midi->track[c].data)
247 goto err;
248 /* finally, read track data */
249 if (pack_fread(midi->track[c].data, data, fp) != data)
250 goto err;
251 }
252
253 lock_midi(midi);
254 return midi;
255
256 /* oh dear... */
257 err:
258 destroy_midi(midi);
259 return NULL;
260 }
261
262
263
264 /* destroy_midi:
265 * Frees the memory being used by a MIDI file.
266 */
destroy_midi(MIDI * midi)267 void destroy_midi(MIDI *midi)
268 {
269 int c;
270
271 if (midi == midifile)
272 stop_midi();
273
274 if (midi) {
275 for (c=0; c<MIDI_TRACKS; c++) {
276 if (midi->track[c].data) {
277 UNLOCK_DATA(midi->track[c].data, midi->track[c].len);
278 _AL_FREE(midi->track[c].data);
279 }
280 }
281
282 UNLOCK_DATA(midi, sizeof(MIDI));
283 _AL_FREE(midi);
284 }
285 }
286
287
288
289 /* parse_var_len:
290 * The MIDI file format is a strange thing. Time offsets are only 32 bits,
291 * yet they are compressed in a weird variable length format. This routine
292 * reads a variable length integer from a MIDI data stream. It returns the
293 * number read, and alters the data pointer according to the number of
294 * bytes it used.
295 */
parse_var_len(AL_CONST unsigned char ** data)296 static unsigned long parse_var_len(AL_CONST unsigned char **data)
297 {
298 unsigned long val = **data & 0x7F;
299
300 while (**data & 0x80) {
301 (*data)++;
302 val <<= 7;
303 val += (**data & 0x7F);
304 }
305
306 (*data)++;
307 return val;
308 }
309
310 END_OF_STATIC_FUNCTION(parse_var_len);
311
312
313
314 /* global_volume_fix:
315 * Converts a note volume, adjusting it according to the global
316 * _midi_volume variable.
317 */
global_volume_fix(int vol)318 static INLINE int global_volume_fix(int vol)
319 {
320 if (_midi_volume >= 0)
321 return (vol * _midi_volume) / 256;
322
323 return vol;
324 }
325
326
327
328 /* sort_out_volume:
329 * Converts a note volume, adjusting it according to the channel volume
330 * and the global _midi_volume variable.
331 */
sort_out_volume(int c,int vol)332 static INLINE int sort_out_volume(int c, int vol)
333 {
334 return global_volume_fix((vol * midi_channel[c].volume) / 128);
335 }
336
337
338
339 /* raw_program_change:
340 * Sends a program change message to a device capable of handling raw
341 * MIDI data, using patch mapping tables. Assumes that midi_driver->raw_midi
342 * isn't NULL, so check before calling it!
343 */
raw_program_change(int channel,int patch)344 static void raw_program_change(int channel, int patch)
345 {
346 if (channel != 9) {
347 /* bank change #1 */
348 if (patch_table[patch].bank1 >= 0) {
349 midi_driver->raw_midi(0xB0+channel);
350 midi_driver->raw_midi(0);
351 midi_driver->raw_midi(patch_table[patch].bank1);
352 }
353
354 /* bank change #2 */
355 if (patch_table[patch].bank2 >= 0) {
356 midi_driver->raw_midi(0xB0+channel);
357 midi_driver->raw_midi(32);
358 midi_driver->raw_midi(patch_table[patch].bank2);
359 }
360
361 /* program change */
362 midi_driver->raw_midi(0xC0+channel);
363 midi_driver->raw_midi(patch_table[patch].prog);
364
365 /* update volume */
366 midi_driver->raw_midi(0xB0+channel);
367 midi_driver->raw_midi(7);
368 midi_driver->raw_midi(global_volume_fix(midi_channel[channel].volume-1));
369 }
370 }
371
372 END_OF_STATIC_FUNCTION(raw_program_change);
373
374
375
376 /* midi_note_off:
377 * Processes a MIDI note-off event.
378 */
midi_note_off(int channel,int note)379 static void midi_note_off(int channel, int note)
380 {
381 int done = FALSE;
382 int voice, layer;
383 int c;
384
385 /* can we send raw MIDI data? */
386 if (midi_driver->raw_midi) {
387 if (channel != 9)
388 note += patch_table[midi_channel[channel].patch].pitch;
389
390 midi_driver->raw_midi(0x80+channel);
391 midi_driver->raw_midi(note);
392 midi_driver->raw_midi(0);
393 return;
394 }
395
396 /* oh well, have to do it the long way... */
397 for (layer=0; layer<MIDI_LAYERS; layer++) {
398 voice = midi_channel[channel].note[note][layer];
399 if (voice >= 0) {
400 midi_driver->key_off(voice + midi_driver->basevoice);
401 midi_voice[voice].note = -1;
402 midi_voice[voice].time = _midi_tick;
403 midi_channel[channel].note[note][layer] = -1;
404 done = TRUE;
405 }
406 }
407
408 /* if the note isn't playing, it must still be in the waiting room */
409 if (!done) {
410 for (c=0; c<MIDI_VOICES; c++) {
411 if ((midi_waiting[c].channel == channel) &&
412 (midi_waiting[c].note == note)) {
413 midi_waiting[c].note = -1;
414 break;
415 }
416 }
417 }
418 }
419
420 END_OF_STATIC_FUNCTION(midi_note_off);
421
422
423
424 /* sort_out_pitch_bend:
425 * MIDI pitch bend range is + or - two semitones. The low-level soundcard
426 * drivers can only handle bends up to +1 semitone. This routine converts
427 * pitch bends from MIDI format to our own format.
428 */
sort_out_pitch_bend(int * bend,int * note)429 static INLINE void sort_out_pitch_bend(int *bend, int *note)
430 {
431 if (*bend == 0x2000) {
432 *bend = 0;
433 return;
434 }
435
436 (*bend) -= 0x2000;
437
438 while (*bend < 0) {
439 (*note)--;
440 (*bend) += 0x1000;
441 }
442
443 while (*bend >= 0x1000) {
444 (*note)++;
445 (*bend) -= 0x1000;
446 }
447 }
448
449
450
451 /* _midi_allocate_voice:
452 * Allocates a MIDI voice in the range min-max (inclusive). This is
453 * intended to be called by the key_on() handlers in the MIDI driver,
454 * and shouldn't be used by any other code.
455 */
_midi_allocate_voice(int min,int max)456 int _midi_allocate_voice(int min, int max)
457 {
458 int c;
459 int layer;
460 int voice = -1;
461 long best_time = LONG_MAX;
462
463 if (min < 0)
464 min = 0;
465
466 if (max < 0)
467 max = midi_driver->voices-1;
468
469 /* which layer can we use? */
470 for (layer=0; layer<MIDI_LAYERS; layer++)
471 if (midi_channel[midi_alloc_channel].note[midi_alloc_note][layer] < 0)
472 break;
473
474 if (layer >= MIDI_LAYERS)
475 return -1;
476
477 /* find a free voice */
478 for (c=min; c<=max; c++) {
479 if ((midi_voice[c].note < 0) &&
480 (midi_voice[c].time < best_time) &&
481 ((c < midi_driver->xmin) || (c > midi_driver->xmax))) {
482 voice = c;
483 best_time = midi_voice[c].time;
484 }
485 }
486
487 /* if there are no free voices, kill a note to make room */
488 if (voice < 0) {
489 voice = -1;
490 best_time = LONG_MAX;
491 for (c=min; c<=max; c++) {
492 if ((midi_voice[c].time < best_time) &&
493 ((c < midi_driver->xmin) || (c > midi_driver->xmax))) {
494 voice = c;
495 best_time = midi_voice[c].time;
496 }
497 }
498 if (voice >= 0)
499 midi_note_off(midi_voice[voice].channel, midi_voice[voice].note);
500 else
501 return -1;
502 }
503
504 /* ok, we got it... */
505 midi_voice[voice].channel = midi_alloc_channel;
506 midi_voice[voice].note = midi_alloc_note;
507 midi_voice[voice].volume = midi_alloc_vol;
508 midi_voice[voice].time = _midi_tick;
509 midi_channel[midi_alloc_channel].note[midi_alloc_note][layer] = voice;
510
511 return voice + midi_driver->basevoice;
512 }
513
514 END_OF_FUNCTION(_midi_allocate_voice);
515
516
517
518 /* midi_note_on:
519 * Processes a MIDI note-on event. Tries to find a free soundcard voice,
520 * and if it can't either cuts off an existing note, or if 'polite' is
521 * set, just stores the channel, note and volume in the waiting list.
522 */
midi_note_on(int channel,int note,int vol,int polite)523 static void midi_note_on(int channel, int note, int vol, int polite)
524 {
525 int c, layer, inst, bend, corrected_note;
526
527 /* it's easy if the driver can handle raw MIDI data */
528 if (midi_driver->raw_midi) {
529 if (channel != 9)
530 note += patch_table[midi_channel[channel].patch].pitch;
531
532 midi_driver->raw_midi(0x90+channel);
533 midi_driver->raw_midi(note);
534 midi_driver->raw_midi(vol);
535 return;
536 }
537
538 /* if the note is already on, turn it off */
539 for (layer=0; layer<MIDI_LAYERS; layer++) {
540 if (midi_channel[channel].note[note][layer] >= 0) {
541 midi_note_off(channel, note);
542 return;
543 }
544 }
545
546 /* if zero volume and the note isn't playing, we can just ignore it */
547 if (vol == 0)
548 return;
549
550 if (channel != 9) {
551 /* are there any free voices? */
552 for (c=0; c<midi_driver->voices; c++)
553 if ((midi_voice[c].note < 0) &&
554 ((c < midi_driver->xmin) || (c > midi_driver->xmax)))
555 break;
556
557 /* if there are no free voices, remember the note for later */
558 if ((c >= midi_driver->voices) && (polite)) {
559 for (c=0; c<MIDI_VOICES; c++) {
560 if (midi_waiting[c].note < 0) {
561 midi_waiting[c].channel = channel;
562 midi_waiting[c].note = note;
563 midi_waiting[c].volume = vol;
564 break;
565 }
566 }
567 return;
568 }
569 }
570
571 /* drum sound? */
572 if (channel == 9) {
573 inst = 128+note;
574 corrected_note = 60;
575 bend = 0;
576 }
577 else {
578 inst = midi_channel[channel].patch;
579 corrected_note = note;
580 bend = midi_channel[channel].pitch_bend;
581 sort_out_pitch_bend(&bend, &corrected_note);
582 }
583
584 /* play the note */
585 midi_alloc_channel = channel;
586 midi_alloc_note = note;
587 midi_alloc_vol = vol;
588
589 midi_driver->key_on(inst, corrected_note, bend,
590 sort_out_volume(channel, vol),
591 midi_channel[channel].pan);
592 }
593
594 END_OF_STATIC_FUNCTION(midi_note_on);
595
596
597
598 /* all_notes_off:
599 * Turns off all active notes.
600 */
all_notes_off(int channel)601 static void all_notes_off(int channel)
602 {
603 if (midi_driver->raw_midi) {
604 midi_driver->raw_midi(0xB0+channel);
605 midi_driver->raw_midi(123);
606 midi_driver->raw_midi(0);
607 return;
608 }
609 else {
610 int note, layer;
611
612 for (note=0; note<128; note++)
613 for (layer=0; layer<MIDI_LAYERS; layer++)
614 if (midi_channel[channel].note[note][layer] >= 0)
615 midi_note_off(channel, note);
616 }
617 }
618
619 END_OF_STATIC_FUNCTION(all_notes_off);
620
621
622
623 /* all_sound_off:
624 * Turns off sound.
625 */
all_sound_off(int channel)626 static void all_sound_off(int channel)
627 {
628 if (midi_driver->raw_midi) {
629 midi_driver->raw_midi(0xB0+channel);
630 midi_driver->raw_midi(120);
631 midi_driver->raw_midi(0);
632 return;
633 }
634 }
635
636 END_OF_STATIC_FUNCTION(all_sound_off);
637
638
639
640 /* reset_controllers:
641 * Resets volume, pan, pitch bend, etc, to default positions.
642 */
reset_controllers(int channel)643 static void reset_controllers(int channel)
644 {
645 midi_channel[channel].new_volume = 128;
646 midi_channel[channel].new_pitch_bend = 0x2000;
647
648 if (midi_driver->raw_midi) {
649 midi_driver->raw_midi(0xB0+channel);
650 midi_driver->raw_midi(121);
651 midi_driver->raw_midi(0);
652 }
653
654 switch (channel % 3) {
655 case 0: midi_channel[channel].pan = ((channel/3) & 1) ? 60 : 68; break;
656 case 1: midi_channel[channel].pan = 104; break;
657 case 2: midi_channel[channel].pan = 24; break;
658 }
659
660 if (midi_driver->raw_midi) {
661 midi_driver->raw_midi(0xB0+channel);
662 midi_driver->raw_midi(10);
663 midi_driver->raw_midi(midi_channel[channel].pan);
664 }
665 }
666
667 END_OF_STATIC_FUNCTION(reset_controllers);
668
669
670
671 /* update_controllers:
672 * Checks cached controller information and updates active voices.
673 */
update_controllers(void)674 static void update_controllers(void)
675 {
676 int c, c2, vol, bend, note;
677
678 for (c=0; c<16; c++) {
679 /* check for volume controller change */
680 if ((midi_channel[c].volume != midi_channel[c].new_volume) || (old_midi_volume != _midi_volume)) {
681 midi_channel[c].volume = midi_channel[c].new_volume;
682 if (midi_driver->raw_midi) {
683 midi_driver->raw_midi(0xB0+c);
684 midi_driver->raw_midi(7);
685 midi_driver->raw_midi(global_volume_fix(midi_channel[c].volume-1));
686 }
687 else {
688 for (c2=0; c2<MIDI_VOICES; c2++) {
689 if ((midi_voice[c2].channel == c) && (midi_voice[c2].note >= 0)) {
690 vol = sort_out_volume(c, midi_voice[c2].volume);
691 midi_driver->set_volume(c2 + midi_driver->basevoice, vol);
692 }
693 }
694 }
695 }
696
697 /* check for pitch bend change */
698 if (midi_channel[c].pitch_bend != midi_channel[c].new_pitch_bend) {
699 midi_channel[c].pitch_bend = midi_channel[c].new_pitch_bend;
700 if (midi_driver->raw_midi) {
701 midi_driver->raw_midi(0xE0+c);
702 midi_driver->raw_midi(midi_channel[c].pitch_bend & 0x7F);
703 midi_driver->raw_midi(midi_channel[c].pitch_bend >> 7);
704 }
705 else {
706 for (c2=0; c2<MIDI_VOICES; c2++) {
707 if ((midi_voice[c2].channel == c) && (midi_voice[c2].note >= 0)) {
708 bend = midi_channel[c].pitch_bend;
709 note = midi_voice[c2].note;
710 sort_out_pitch_bend(&bend, ¬e);
711 midi_driver->set_pitch(c2 + midi_driver->basevoice, note, bend);
712 }
713 }
714 }
715 }
716 }
717
718 old_midi_volume = _midi_volume;
719 }
720
721 END_OF_STATIC_FUNCTION(update_controllers);
722
723
724
725 /* process_controller:
726 * Deals with a MIDI controller message on the specified channel.
727 */
process_controller(int channel,int ctrl,int data)728 static void process_controller(int channel, int ctrl, int data)
729 {
730 switch (ctrl) {
731
732 case 7: /* main volume */
733 midi_channel[channel].new_volume = data+1;
734 break;
735
736 case 10: /* pan */
737 midi_channel[channel].pan = data;
738 if (midi_driver->raw_midi) {
739 midi_driver->raw_midi(0xB0+channel);
740 midi_driver->raw_midi(10);
741 midi_driver->raw_midi(data);
742 }
743 break;
744
745 case 120: /* all sound off */
746 all_sound_off(channel);
747 break;
748
749 case 121: /* reset all controllers */
750 reset_controllers(channel);
751 break;
752
753 case 123: /* all notes off */
754 case 124: /* omni mode off */
755 case 125: /* omni mode on */
756 case 126: /* poly mode off */
757 case 127: /* poly mode on */
758 all_notes_off(channel);
759 break;
760
761 default:
762 if (midi_driver->raw_midi) {
763 midi_driver->raw_midi(0xB0+channel);
764 midi_driver->raw_midi(ctrl);
765 midi_driver->raw_midi(data);
766 }
767 break;
768 }
769 }
770
771 END_OF_STATIC_FUNCTION(process_controller);
772
773
774
775 /* process_meta_event:
776 * Processes the next meta-event on the specified track.
777 */
process_meta_event(AL_CONST unsigned char ** pos,long * timer)778 static void process_meta_event(AL_CONST unsigned char **pos, long *timer)
779 {
780 unsigned char metatype = *((*pos)++);
781 long length = parse_var_len(pos);
782 long tempo;
783
784 if (midi_meta_callback)
785 midi_meta_callback(metatype, *pos, length);
786
787 if (metatype == 0x2F) { /* end of track */
788 *pos = NULL;
789 *timer = LONG_MAX;
790 return;
791 }
792
793 if (metatype == 0x51) { /* tempo change */
794 tempo = (*pos)[0] * 0x10000L + (*pos)[1] * 0x100 + (*pos)[2];
795 midi_new_speed = (tempo/1000) * (TIMERS_PER_SECOND/1000);
796 midi_new_speed /= midifile->divisions;
797 }
798
799 (*pos) += length;
800 }
801
802 END_OF_STATIC_FUNCTION(process_meta_event);
803
804
805
806 /* process_midi_event:
807 * Processes the next MIDI event on the specified track.
808 */
process_midi_event(AL_CONST unsigned char ** pos,unsigned char * running_status,long * timer)809 static void process_midi_event(AL_CONST unsigned char **pos, unsigned char *running_status, long *timer)
810 {
811 unsigned char byte1, byte2;
812 int channel;
813 unsigned char event;
814 long l;
815
816 event = *((*pos)++);
817
818 if (event & 0x80) { /* regular message */
819 /* no running status for sysex and meta-events! */
820 if ((event != 0xF0) && (event != 0xF7) && (event != 0xFF))
821 *running_status = event;
822 byte1 = (*pos)[0];
823 byte2 = (*pos)[1];
824 }
825 else { /* use running status */
826 byte1 = event;
827 byte2 = (*pos)[0];
828 event = *running_status;
829 (*pos)--;
830 }
831
832 /* program callback? */
833 if ((midi_msg_callback) &&
834 (event != 0xF0) && (event != 0xF7) && (event != 0xFF))
835 midi_msg_callback(event, byte1, byte2);
836
837 channel = event & 0x0F;
838
839 switch (event>>4) {
840
841 case 0x08: /* note off */
842 midi_note_off(channel, byte1);
843 (*pos) += 2;
844 break;
845
846 case 0x09: /* note on */
847 midi_note_on(channel, byte1, byte2, 1);
848 (*pos) += 2;
849 break;
850
851 case 0x0A: /* note aftertouch */
852 (*pos) += 2;
853 break;
854
855 case 0x0B: /* control change */
856 process_controller(channel, byte1, byte2);
857 (*pos) += 2;
858 break;
859
860 case 0x0C: /* program change */
861 midi_channel[channel].patch = byte1;
862 if (midi_driver->raw_midi)
863 raw_program_change(channel, byte1);
864 (*pos) += 1;
865 break;
866
867 case 0x0D: /* channel aftertouch */
868 (*pos) += 1;
869 break;
870
871 case 0x0E: /* pitch bend */
872 midi_channel[channel].new_pitch_bend = byte1 + (byte2<<7);
873 (*pos) += 2;
874 break;
875
876 case 0x0F: /* special event */
877 switch (event) {
878 case 0xF0: /* sysex */
879 case 0xF7:
880 l = parse_var_len(pos);
881 if (midi_sysex_callback)
882 midi_sysex_callback(*pos, l);
883 (*pos) += l;
884 break;
885
886 case 0xF2: /* song position */
887 (*pos) += 2;
888 break;
889
890 case 0xF3: /* song select */
891 (*pos)++;
892 break;
893
894 case 0xFF: /* meta-event */
895 process_meta_event(pos, timer);
896 break;
897
898 default:
899 /* the other special events don't have any data bytes,
900 so we don't need to bother skipping past them */
901 break;
902 }
903 break;
904
905 default:
906 /* something has gone badly wrong if we ever get to here */
907 break;
908 }
909 }
910
911 END_OF_STATIC_FUNCTION(process_midi_event);
912
913
914
915 /* midi_player:
916 * The core MIDI player: to be used as a timer callback.
917 */
midi_player(void)918 static void midi_player(void)
919 {
920 int c;
921 long l;
922 int active;
923
924 if (!midifile)
925 return;
926
927 if (midi_semaphore) {
928 midi_timer_speed += BPS_TO_TIMER(MIDI_TIMER_FREQUENCY);
929 install_int_ex(midi_player, BPS_TO_TIMER(MIDI_TIMER_FREQUENCY));
930 return;
931 }
932
933 midi_semaphore = TRUE;
934 _midi_tick++;
935
936 midi_timers += midi_timer_speed;
937 midi_time = midi_timers / TIMERS_PER_SECOND;
938
939 do_it_all_again:
940
941 for (c=0; c<MIDI_VOICES; c++)
942 midi_waiting[c].note = -1;
943
944 /* deal with each track in turn... */
945 for (c=0; c<MIDI_TRACKS; c++) {
946 if (midi_track[c].pos) {
947 midi_track[c].timer -= midi_timer_speed;
948
949 /* while events are waiting, process them */
950 while (midi_track[c].timer <= 0) {
951 process_midi_event((AL_CONST unsigned char**) &midi_track[c].pos,
952 &midi_track[c].running_status,
953 &midi_track[c].timer);
954
955 /* read next time offset */
956 if (midi_track[c].pos) {
957 l = parse_var_len((AL_CONST unsigned char**) &midi_track[c].pos);
958 l *= midi_speed;
959 midi_track[c].timer += l;
960 }
961 }
962 }
963 }
964
965 /* update global position value */
966 midi_pos_counter -= midi_timer_speed;
967 while (midi_pos_counter <= 0) {
968 midi_pos_counter += midi_pos_speed;
969 midi_pos++;
970 }
971
972 /* tempo change? */
973 if (midi_new_speed > 0) {
974 for (c=0; c<MIDI_TRACKS; c++) {
975 if (midi_track[c].pos) {
976 midi_track[c].timer /= midi_speed;
977 midi_track[c].timer *= midi_new_speed;
978 }
979 }
980 midi_pos_counter /= midi_speed;
981 midi_pos_counter *= midi_new_speed;
982
983 midi_speed = midi_new_speed;
984 midi_pos_speed = midi_new_speed * midifile->divisions;
985 midi_new_speed = -1;
986 }
987
988 /* figure out how long until we need to be called again */
989 active = 0;
990 midi_timer_speed = LONG_MAX;
991 for (c=0; c<MIDI_TRACKS; c++) {
992 if (midi_track[c].pos) {
993 active = 1;
994 if (midi_track[c].timer < midi_timer_speed)
995 midi_timer_speed = midi_track[c].timer;
996 }
997 }
998
999 /* end of the music? */
1000 if ((!active) || ((midi_loop_end > 0) && (midi_pos >= midi_loop_end))) {
1001 if ((midi_loop) && (!midi_looping)) {
1002 if (midi_loop_start > 0) {
1003 remove_int(midi_player);
1004 midi_semaphore = FALSE;
1005 midi_looping = TRUE;
1006 if (midi_seek(midi_loop_start) != 0) {
1007 midi_looping = FALSE;
1008 stop_midi();
1009 return;
1010 }
1011 midi_looping = FALSE;
1012 midi_semaphore = TRUE;
1013 goto do_it_all_again;
1014 }
1015 else {
1016 for (c=0; c<16; c++) {
1017 all_notes_off(c);
1018 all_sound_off(c);
1019 }
1020 prepare_to_play(midifile);
1021 goto do_it_all_again;
1022 }
1023 }
1024 else {
1025 stop_midi();
1026 midi_semaphore = FALSE;
1027 return;
1028 }
1029 }
1030
1031 /* reprogram the timer */
1032 if (midi_timer_speed < BPS_TO_TIMER(MIDI_TIMER_FREQUENCY))
1033 midi_timer_speed = BPS_TO_TIMER(MIDI_TIMER_FREQUENCY);
1034
1035 if (!midi_seeking)
1036 install_int_ex(midi_player, midi_timer_speed);
1037
1038 /* controller changes are cached and only processed here, so we can
1039 condense streams of controller data into just a few voice updates */
1040 update_controllers();
1041
1042 /* and deal with any notes that are still waiting to be played */
1043 for (c=0; c<MIDI_VOICES; c++)
1044 if (midi_waiting[c].note >= 0)
1045 midi_note_on(midi_waiting[c].channel, midi_waiting[c].note,
1046 midi_waiting[c].volume, 0);
1047
1048 midi_semaphore = FALSE;
1049 }
1050
1051 END_OF_STATIC_FUNCTION(midi_player);
1052
1053
1054
1055 /* midi_init:
1056 * Sets up the MIDI player ready for use. Returns non-zero on failure.
1057 */
midi_init(void)1058 static int midi_init(void)
1059 {
1060 int c, c2, c3;
1061 char **argv;
1062 int argc;
1063 char buf[32], tmp[64];
1064
1065 midi_loaded_patches = FALSE;
1066
1067 midi_lock_mem();
1068
1069 for (c=0; c<16; c++) {
1070 midi_channel[c].volume = midi_channel[c].new_volume = 128;
1071 midi_channel[c].pitch_bend = midi_channel[c].new_pitch_bend = 0x2000;
1072
1073 for (c2=0; c2<128; c2++)
1074 for (c3=0; c3<MIDI_LAYERS; c3++)
1075 midi_channel[c].note[c2][c3] = -1;
1076 }
1077
1078 for (c=0; c<MIDI_VOICES; c++) {
1079 midi_voice[c].note = -1;
1080 midi_voice[c].time = 0;
1081 }
1082
1083 for (c=0; c<128; c++) {
1084 uszprintf(buf, sizeof(buf), uconvert_ascii("p%d", tmp), c+1);
1085 argv = get_config_argv(uconvert_ascii("midimap", tmp), buf, &argc);
1086
1087 if ((argv) && (argc == 4)) {
1088 patch_table[c].bank1 = ustrtol(argv[0], NULL, 0);
1089 patch_table[c].bank2 = ustrtol(argv[1], NULL, 0);
1090 patch_table[c].prog = ustrtol(argv[2], NULL, 0);
1091 patch_table[c].pitch = ustrtol(argv[3], NULL, 0);
1092 }
1093 else {
1094 patch_table[c].bank1 = -1;
1095 patch_table[c].bank2 = -1;
1096 patch_table[c].prog = c;
1097 patch_table[c].pitch = 0;
1098 }
1099 }
1100
1101 register_datafile_object(DAT_MIDI, NULL, (void (*)(void *))destroy_midi);
1102
1103 return 0;
1104 }
1105
1106
1107
1108 /* midi_exit:
1109 * Turns off all active notes and removes the timer handler.
1110 */
midi_exit(void)1111 static void midi_exit(void)
1112 {
1113 stop_midi();
1114 }
1115
1116
1117
1118 /* load_patches:
1119 * Scans through a MIDI file and identifies which patches it uses, passing
1120 * them to the soundcard driver so it can load whatever samples are
1121 * neccessary.
1122 */
load_patches(MIDI * midi)1123 static int load_patches(MIDI *midi)
1124 {
1125 char patches[128], drums[128];
1126 unsigned char *p, *end;
1127 unsigned char running_status, event;
1128 long l;
1129 int c;
1130 ASSERT(midi);
1131
1132 for (c=0; c<128; c++) /* initialise to unused */
1133 patches[c] = drums[c] = FALSE;
1134
1135 patches[0] = TRUE; /* always load the piano */
1136
1137 for (c=0; c<MIDI_TRACKS; c++) { /* for each track... */
1138 p = midi->track[c].data;
1139 end = p + midi->track[c].len;
1140 running_status = 0;
1141
1142 while (p < end) { /* work through data stream */
1143 #if defined ALLEGRO_BEOS || defined ALLEGRO_HAIKU
1144 /* Is there a bug in this routine, or in gcc under BeOS/x86? --PW */
1145 { int i; for (i=1; i; i--); }
1146 #endif
1147 event = *p;
1148 if (event & 0x80) { /* regular message */
1149 p++;
1150 if ((event != 0xF0) && (event != 0xF7) && (event != 0xFF))
1151 running_status = event;
1152 }
1153 else /* use running status */
1154 event = running_status;
1155
1156 switch (event>>4) {
1157
1158 case 0x0C: /* program change! */
1159 patches[*p] = TRUE;
1160 p++;
1161 break;
1162
1163 case 0x09: /* note on, is it a drum? */
1164 if ((event & 0x0F) == 9)
1165 drums[*p] = TRUE;
1166 p += 2;
1167 break;
1168
1169 case 0x08: /* note off */
1170 case 0x0A: /* note aftertouch */
1171 case 0x0B: /* control change */
1172 case 0x0E: /* pitch bend */
1173 p += 2;
1174 break;
1175
1176 case 0x0D: /* channel aftertouch */
1177 p += 1;
1178 break;
1179
1180 case 0x0F: /* special event */
1181 switch (event) {
1182 case 0xF0: /* sysex */
1183 case 0xF7:
1184 l = parse_var_len((AL_CONST unsigned char**) &p);
1185 p += l;
1186 break;
1187
1188 case 0xF2: /* song position */
1189 p += 2;
1190 break;
1191
1192 case 0xF3: /* song select */
1193 p++;
1194 break;
1195
1196 case 0xFF: /* meta-event */
1197 p++;
1198 l = parse_var_len((AL_CONST unsigned char**) &p);
1199 p += l;
1200 break;
1201
1202 default:
1203 /* the other special events don't have any data bytes,
1204 so we don't need to bother skipping past them */
1205 break;
1206 }
1207 break;
1208
1209 default:
1210 /* something has gone badly wrong if we ever get to here */
1211 break;
1212 }
1213
1214 if (p < end) /* skip time offset */
1215 parse_var_len((AL_CONST unsigned char**) &p);
1216 }
1217 }
1218
1219 /* tell the driver to do its stuff */
1220 return midi_driver->load_patches(patches, drums);
1221 }
1222
1223
1224
1225 /* prepare_to_play:
1226 * Sets up all the global variables needed to play the specified file.
1227 */
prepare_to_play(MIDI * midi)1228 static void prepare_to_play(MIDI *midi)
1229 {
1230 int c;
1231 ASSERT(midi);
1232
1233 for (c=0; c<16; c++)
1234 reset_controllers(c);
1235
1236 update_controllers();
1237
1238 midifile = midi;
1239 midi_pos = 0;
1240 midi_timers = 0;
1241 midi_time = 0;
1242 midi_pos_counter = 0;
1243 midi_speed = TIMERS_PER_SECOND / 2 / midifile->divisions; /* 120 bpm */
1244 midi_new_speed = -1;
1245 midi_pos_speed = midi_speed * midifile->divisions;
1246 midi_timer_speed = 0;
1247 midi_seeking = 0;
1248 midi_looping = 0;
1249
1250 for (c=0; c<16; c++) {
1251 midi_channel[c].patch = 0;
1252 if (midi_driver->raw_midi)
1253 raw_program_change(c, 0);
1254 }
1255
1256 for (c=0; c<MIDI_TRACKS; c++) {
1257 if (midi->track[c].data) {
1258 midi_track[c].pos = midi->track[c].data;
1259 midi_track[c].timer = parse_var_len((AL_CONST unsigned char**) &midi_track[c].pos);
1260 midi_track[c].timer *= midi_speed;
1261 }
1262 else {
1263 midi_track[c].pos = NULL;
1264 midi_track[c].timer = LONG_MAX;
1265 }
1266 midi_track[c].running_status = 0;
1267 }
1268 }
1269
1270 END_OF_STATIC_FUNCTION(prepare_to_play);
1271
1272
1273
1274 /* play_midi:
1275 * Starts playing the specified MIDI file. If loop is set, the MIDI file
1276 * will be repeated until replaced with something else, otherwise it will
1277 * stop at the end of the file. Passing a NULL MIDI file will stop whatever
1278 * music is currently playing: allegro.h defines the macro stop_midi() to
1279 * be play_midi(NULL, FALSE); Returns non-zero if an error occurs (this
1280 * may happen if a patch-caching wavetable driver is unable to load the
1281 * required samples).
1282 */
play_midi(MIDI * midi,int loop)1283 int play_midi(MIDI *midi, int loop)
1284 {
1285 int c;
1286
1287 remove_int(midi_player);
1288
1289 for (c=0; c<16; c++) {
1290 all_notes_off(c);
1291 all_sound_off(c);
1292 }
1293
1294 if (midi) {
1295 if (!midi_loaded_patches)
1296 if (load_patches(midi) != 0)
1297 return -1;
1298
1299 midi_loop = loop;
1300 midi_loop_start = -1;
1301 midi_loop_end = -1;
1302
1303 prepare_to_play(midi);
1304
1305 /* arbitrary speed, midi_player() will adjust it */
1306 install_int(midi_player, 20);
1307 }
1308 else {
1309 midifile = NULL;
1310
1311 if (midi_pos > 0)
1312 midi_pos = -midi_pos;
1313 else if (midi_pos == 0)
1314 midi_pos = -1;
1315 }
1316
1317 return 0;
1318 }
1319
1320 END_OF_FUNCTION(play_midi);
1321
1322
1323
1324 /* play_looped_midi:
1325 * Like play_midi(), but the file loops from the specified end position
1326 * back to the specified start position (the end position can be -1 to
1327 * indicate the end of the file).
1328 */
play_looped_midi(MIDI * midi,int loop_start,int loop_end)1329 int play_looped_midi(MIDI *midi, int loop_start, int loop_end)
1330 {
1331 if (play_midi(midi, TRUE) != 0)
1332 return -1;
1333
1334 midi_loop_start = loop_start;
1335 midi_loop_end = loop_end;
1336
1337 return 0;
1338 }
1339
1340
1341
1342 /* stop_midi:
1343 * Stops whatever MIDI file is currently playing.
1344 */
stop_midi(void)1345 void stop_midi(void)
1346 {
1347 play_midi(NULL, FALSE);
1348 }
1349
1350 END_OF_FUNCTION(stop_midi);
1351
1352
1353
1354 /* midi_pause:
1355 * Pauses the currently playing MIDI file.
1356 */
midi_pause(void)1357 void midi_pause(void)
1358 {
1359 int c;
1360
1361 if (!midifile)
1362 return;
1363
1364 remove_int(midi_player);
1365
1366 for (c=0; c<16; c++) {
1367 all_notes_off(c);
1368 all_sound_off(c);
1369 }
1370 }
1371
1372 END_OF_FUNCTION(midi_pause);
1373
1374
1375
1376 /* midi_resume:
1377 * Resumes playing a paused MIDI file.
1378 */
midi_resume(void)1379 void midi_resume(void)
1380 {
1381 if (!midifile)
1382 return;
1383
1384 install_int_ex(midi_player, midi_timer_speed);
1385 }
1386
1387 END_OF_FUNCTION(midi_resume);
1388
1389
1390
1391 /* midi_seek:
1392 * Seeks to the given midi_pos in the current MIDI file. If the target
1393 * is earlier in the file than the current midi_pos it seeks from the
1394 * beginning; otherwise it seeks from the current position. Returns zero
1395 * if successful, non-zero if it hit the end of the file (1 means it
1396 * stopped playing, 2 means it looped back to the start).
1397 */
midi_seek(int target)1398 int midi_seek(int target)
1399 {
1400 int old_midi_loop;
1401 MIDI *old_midifile;
1402 MIDI_DRIVER *old_driver;
1403 int old_patch[16];
1404 int old_volume[16];
1405 int old_pan[16];
1406 int old_pitch_bend[16];
1407 int c;
1408
1409 if (!midifile)
1410 return -1;
1411
1412 /* first stop the player */
1413 midi_pause();
1414
1415 /* store current settings */
1416 for (c=0; c<16; c++) {
1417 old_patch[c] = midi_channel[c].patch;
1418 old_volume[c] = midi_channel[c].volume;
1419 old_pan[c] = midi_channel[c].pan;
1420 old_pitch_bend[c] = midi_channel[c].pitch_bend;
1421 }
1422
1423 /* save some variables and give temporary values */
1424 old_driver = midi_driver;
1425 midi_driver = &_midi_none;
1426 old_midi_loop = midi_loop;
1427 midi_loop = 0;
1428 old_midifile = midifile;
1429
1430 /* set flag to tell midi_player not to reinstall itself */
1431 midi_seeking = 1;
1432
1433 /* are we seeking backwards? If so, skip back to the start of the file */
1434 if (target <= midi_pos)
1435 prepare_to_play(midifile);
1436
1437 /* now sit back and let midi_player get to the position */
1438 while ((midi_pos < target) && (midi_pos >= 0)) {
1439 int mmpc = midi_pos_counter;
1440 int mmp = midi_pos;
1441
1442 mmpc -= midi_timer_speed;
1443 while (mmpc <= 0) {
1444 mmpc += midi_pos_speed;
1445 mmp++;
1446 }
1447
1448 if (mmp >= target)
1449 break;
1450
1451 midi_player();
1452 }
1453
1454 /* restore previously saved variables */
1455 midi_loop = old_midi_loop;
1456 midi_driver = old_driver;
1457 midi_seeking = 0;
1458
1459 if (midi_pos >= 0) {
1460 /* refresh the driver with any changed parameters */
1461 if (midi_driver->raw_midi) {
1462 for (c=0; c<16; c++) {
1463 /* program change (this sets the volume as well) */
1464 if ((midi_channel[c].patch != old_patch[c]) ||
1465 (midi_channel[c].volume != old_volume[c]))
1466 raw_program_change(c, midi_channel[c].patch);
1467
1468 /* pan */
1469 if (midi_channel[c].pan != old_pan[c]) {
1470 midi_driver->raw_midi(0xB0+c);
1471 midi_driver->raw_midi(10);
1472 midi_driver->raw_midi(midi_channel[c].pan);
1473 }
1474
1475 /* pitch bend */
1476 if (midi_channel[c].pitch_bend != old_pitch_bend[c]) {
1477 midi_driver->raw_midi(0xE0+c);
1478 midi_driver->raw_midi(midi_channel[c].pitch_bend & 0x7F);
1479 midi_driver->raw_midi(midi_channel[c].pitch_bend >> 7);
1480 }
1481 }
1482 }
1483
1484 /* if we didn't hit the end of the file, continue playing */
1485 if (!midi_looping)
1486 install_int(midi_player, 20);
1487
1488 return 0;
1489 }
1490
1491 if ((midi_loop) && (!midi_looping)) { /* was file looped? */
1492 prepare_to_play(old_midifile);
1493 install_int(midi_player, 20);
1494 return 2; /* seek past EOF => file restarted */
1495 }
1496
1497 return 1; /* seek past EOF => file stopped */
1498 }
1499
1500 END_OF_FUNCTION(midi_seek);
1501
1502
1503
1504 /* get_midi_length:
1505 * Returns the length, in seconds, of the specified midi. This will stop any
1506 * currently playing midi. Don't call it too often, since it simulates playing
1507 * all of the midi to get the time even if the midi contains tempo changes.
1508 */
get_midi_length(MIDI * midi)1509 int get_midi_length(MIDI *midi)
1510 {
1511 play_midi(midi, 0);
1512 while (midi_pos < 0); /* Without this, midi_seek won't work. */
1513 midi_seek(INT_MAX);
1514 return midi_time;
1515 }
1516
1517
1518
1519 /* midi_out:
1520 * Inserts MIDI command bytes into the output stream, in realtime.
1521 */
midi_out(unsigned char * data,int length)1522 void midi_out(unsigned char *data, int length)
1523 {
1524 unsigned char *pos = data;
1525 unsigned char running_status = 0;
1526 long timer = 0;
1527 ASSERT(data);
1528
1529 midi_semaphore = TRUE;
1530 _midi_tick++;
1531
1532 while (pos < data+length)
1533 process_midi_event((AL_CONST unsigned char**) &pos, &running_status, &timer);
1534
1535 update_controllers();
1536
1537 midi_semaphore = FALSE;
1538 }
1539
1540
1541
1542 /* load_midi_patches:
1543 * Tells the MIDI driver to preload the entire sample set.
1544 */
load_midi_patches(void)1545 int load_midi_patches(void)
1546 {
1547 char patches[128], drums[128];
1548 int c, ret;
1549
1550 for (c=0; c<128; c++)
1551 patches[c] = drums[c] = TRUE;
1552
1553 midi_semaphore = TRUE;
1554 ret = midi_driver->load_patches(patches, drums);
1555 midi_semaphore = FALSE;
1556
1557 midi_loaded_patches = TRUE;
1558
1559 return ret;
1560 }
1561
1562
1563
1564 /* midi_lock_mem:
1565 * Locks all the memory that the midi player touches inside the timer
1566 * interrupt handler (which is most of it).
1567 */
midi_lock_mem(void)1568 static void midi_lock_mem(void)
1569 {
1570 LOCK_VARIABLE(midi_pos);
1571 LOCK_VARIABLE(midi_time);
1572 LOCK_VARIABLE(midi_timers);
1573 LOCK_VARIABLE(midi_pos_counter);
1574 LOCK_VARIABLE(_midi_tick);
1575 LOCK_VARIABLE(midifile);
1576 LOCK_VARIABLE(midi_semaphore);
1577 LOCK_VARIABLE(midi_loop);
1578 LOCK_VARIABLE(midi_loop_start);
1579 LOCK_VARIABLE(midi_loop_end);
1580 LOCK_VARIABLE(midi_timer_speed);
1581 LOCK_VARIABLE(midi_pos_speed);
1582 LOCK_VARIABLE(midi_speed);
1583 LOCK_VARIABLE(midi_new_speed);
1584 LOCK_VARIABLE(old_midi_volume);
1585 LOCK_VARIABLE(midi_alloc_channel);
1586 LOCK_VARIABLE(midi_alloc_note);
1587 LOCK_VARIABLE(midi_alloc_vol);
1588 LOCK_VARIABLE(midi_track);
1589 LOCK_VARIABLE(midi_voice);
1590 LOCK_VARIABLE(midi_channel);
1591 LOCK_VARIABLE(midi_waiting);
1592 LOCK_VARIABLE(patch_table);
1593 LOCK_VARIABLE(midi_msg_callback);
1594 LOCK_VARIABLE(midi_meta_callback);
1595 LOCK_VARIABLE(midi_sysex_callback);
1596 LOCK_VARIABLE(midi_seeking);
1597 LOCK_VARIABLE(midi_looping);
1598 LOCK_FUNCTION(parse_var_len);
1599 LOCK_FUNCTION(raw_program_change);
1600 LOCK_FUNCTION(midi_note_off);
1601 LOCK_FUNCTION(_midi_allocate_voice);
1602 LOCK_FUNCTION(midi_note_on);
1603 LOCK_FUNCTION(all_notes_off);
1604 LOCK_FUNCTION(all_sound_off);
1605 LOCK_FUNCTION(reset_controllers);
1606 LOCK_FUNCTION(update_controllers);
1607 LOCK_FUNCTION(process_controller);
1608 LOCK_FUNCTION(process_meta_event);
1609 LOCK_FUNCTION(process_midi_event);
1610 LOCK_FUNCTION(midi_player);
1611 LOCK_FUNCTION(prepare_to_play);
1612 LOCK_FUNCTION(play_midi);
1613 LOCK_FUNCTION(stop_midi);
1614 LOCK_FUNCTION(midi_pause);
1615 LOCK_FUNCTION(midi_resume);
1616 LOCK_FUNCTION(midi_seek);
1617 }
1618
1619
1620
1621 /* midi_constructor:
1622 * Register my functions with the code in sound.c.
1623 */
1624 #ifdef ALLEGRO_USE_CONSTRUCTOR
1625 CONSTRUCTOR_FUNCTION(void _midi_constructor(void));
1626 #endif
1627
1628 static struct _AL_LINKER_MIDI midi_linker = {
1629 midi_init,
1630 midi_exit
1631 };
1632
_midi_constructor(void)1633 void _midi_constructor(void)
1634 {
1635 _al_linker_midi = &midi_linker;
1636 }
1637
1638