/* ** Copyright (c) 1992 Forte. All rights reserved. ** Written late one night 6/27/93. */ #include #include #include #include #include #include "midi.h" int not_done_playing=1; /* externals */ extern struct header_type header; extern int control_break; unsigned long midi_getvarinum(struct track *track); #pragma warn -par static void chanmessage( struct MIDILIB *ml, int c, int c1, int c2, unsigned long time) { int chan; chan = c & 0x0f; switch (c & 0xf0) { case note_on: (*ml->Mp_note_on)(chan, c1, c2); break; case note_off: (*ml->Mp_note_off)(chan, c1, c2); break; case poly_aftertouch: (*ml->Mp_pressure)(chan, c1, c2); break; case control_change: (*ml->Mp_parameter)(chan, c1, c2); break; case pitch_wheel: (*ml->Mp_pitch_bend)(chan, c1, c2); break; case program_chng: (*ml->Mp_program)(chan, c1); break; case channel_aftertouch: (*ml->Mp_chanpressure)(chan, c1, c2); break; } } #pragma warn .par void midi_do_something(struct MIDILIB *ml, unsigned long now_time) { /* This array is indexed by the high half of a status byte. It's */ /* value is either the number of bytes needed (1 or 2) for a channel */ /* message, or 0 (meaning it's not a channel message). */ static int chantype[] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 through 0x70 */ 2, 2, 2, 2, 1, 1, 2, 0 /* 0x80 through 0xf0 */ }; int not_done = 0, len, needed, type, i; unsigned long us; register struct track *track; unsigned char c, c1, c2, check_next_time; if (now_time < ml->Mp_next_event_time) return; ml->Mp_next_event_time = -1L; for (track=ml->Mp_tracks; track; track = track->next_track) { check_next_time = 1; if (track->play_state == MPS_PLAYING) { while (track->play_time <= now_time) { check_next_time = 0; if (*track->playp & 0x80) { c = track->status = midi_getc(track); } else { c = track->status; } needed = chantype[ (c>>4) & 0xf ]; if ( needed ) { /* is it a channel message? */ c1 = midi_getc(track); c2 = (needed>1) ? midi_getc(track) : 0; chanmessage( ml, c, c1, c2, now_time ); } else { switch ( c ) { case MT_meta_event: type = midi_getc(track); len = midi_getvarinum(track); switch (type) { case MT_set_tempo: len -= 3; us = ((long)midi_getc(track)<<16) + ((long)midi_getc(track)<<8) + (long)midi_getc(track); for ( ; len > 0; len--) { midi_getc(track); } (*ml->Mp_set_tempo)(us, header.division.quarter_note); break; default: for (i=0; i < len; i++) { midi_getc(track); } } break; case system_exclusive: case sysex_continue: len = midi_getvarinum(track); for ( i=0; i < len; i++) { midi_getc(track); } break; default: /* whoops */ track->play_state = MPS_DONE; break; } } midi_get_next_time(ml, track); if (track->play_state != MPS_PLAYING) break; } } if (track->play_state == MPS_PLAYING) { if (check_next_time) { if (track->play_time < ml->Mp_next_event_time) { ml->Mp_next_event_time = track->play_time; } } not_done = 1; } } not_done_playing = not_done; } void midi_out(struct MIDILIB *ml) { struct track *track; unsigned long next_event_time; int i, iret, c; not_done_playing = 1; /* initialize track playback info */ next_event_time = -1L; for (track=ml->Mp_tracks; track; track = track->next_track) { track->playp = track->data; track->position = 0L; track->status = 0; track->play_state = MPS_PLAYING; track->play_time = midi_getvarinum(track); if (track->play_time < next_event_time) { next_event_time = track->play_time; } } ml->Mp_next_event_time = next_event_time; if (ml->Mp_set_tempo && header.division.quarter_note < 0) { (*ml->Mp_set_tempo)(0, header.division.quarter_note); } if (ml->Mp_wait_for == 0L) return; if (ml->Mp_reset_tick_counter) (*ml->Mp_reset_tick_counter)(); if (ml->Mp_reset_midi) (*ml->Mp_reset_midi)(); if (ml->Mp_init_hardware) { iret = (*ml->Mp_init_hardware)(ml); if (iret != 0) { if (ml->Mp_cleanup) (*ml->Mp_cleanup)(); return; } } midi_message("Now playing"); if (ml->Mp_init_timers) { (*ml->Mp_init_timers)(); } not_done_playing = 1; while (not_done_playing) { if ((*ml->Mp_wait_for)(ml->Mp_next_event_time)) break; midi_do_something(ml, ml->Mp_next_event_time); } if (ml->Mp_cleanup_timers) { (*ml->Mp_cleanup_timers)(); } if (ml->Mp_cleanup) (*ml->Mp_cleanup)(); } int midi_getc(struct track *track) { if (track->position < track->length) { track->position++; return(*track->playp++); } else { track->play_state = MPS_DONE; return(0); } } unsigned long midi_getvarinum(struct track *track) { long value=0L; int c; do { c = midi_getc(track); value = (value << 7) + (c & 0x7f); } while (c & 0x80); return (value); } void midi_get_next_time(struct MIDILIB *ml, struct track *track) { if (track->play_state == MPS_PLAYING) { track->play_time += midi_getvarinum(track); if (track->play_time < ml->Mp_next_event_time) { ml->Mp_next_event_time = track->play_time; } } }