diff options
-rw-r--r-- | src/i_oplmusic.c | 93 | ||||
-rw-r--r-- | src/midifile.c | 10 | ||||
-rw-r--r-- | src/midifile.h | 8 |
3 files changed, 108 insertions, 3 deletions
diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index 74a76b00..1ac502f5 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -206,6 +206,9 @@ static opl_voice_t *voice_free_list; // Track data for playing tracks: static opl_track_data_t *tracks; +static unsigned int num_tracks; +static unsigned int running_tracks = 0; +static boolean song_looping; // In the initialisation stage, register writes are spaced by reading // from the register port (0). After initialisation, spacing is @@ -868,11 +871,40 @@ static void ControllerEvent(opl_track_data_t *track, midi_event_t *event) SetChannelVolume(channel, param); break; - case MIDI_CONTROLLER_PAN: + default: + fprintf(stderr, "Unknown MIDI controller type: %i\n", controller); + break; + } +} + +// Process a meta event. + +static void MetaEvent(opl_track_data_t *track, midi_event_t *event) +{ + switch (event->data.meta.type) + { + // Things we can just ignore. + + case MIDI_META_SEQUENCE_NUMBER: + case MIDI_META_TEXT: + case MIDI_META_COPYRIGHT: + case MIDI_META_TRACK_NAME: + case MIDI_META_INSTR_NAME: + case MIDI_META_LYRICS: + case MIDI_META_MARKER: + case MIDI_META_CUE_POINT: + case MIDI_META_SEQUENCER_SPECIFIC: + break; + + // End of track - actually handled when we run out of events + // in the track, see below. + + case MIDI_META_END_OF_TRACK: break; default: - fprintf(stderr, "Unknown MIDI controller type: %i\n", controller); + fprintf(stderr, "Unknown MIDI meta event type: %i\n", + event->data.meta.type); break; } } @@ -899,6 +931,16 @@ static void ProcessEvent(opl_track_data_t *track, midi_event_t *event) ProgramChangeEvent(track, event); break; + case MIDI_EVENT_META: + MetaEvent(track, event); + break; + + // SysEx events can be ignored. + + case MIDI_EVENT_SYSEX: + case MIDI_EVENT_SYSEX_SPLIT: + break; + default: fprintf(stderr, "Unknown MIDI event type %i\n", event->event_type); break; @@ -907,6 +949,21 @@ static void ProcessEvent(opl_track_data_t *track, midi_event_t *event) static void ScheduleTrack(opl_track_data_t *track); +// Restart a song from the beginning. + +static void RestartSong(void) +{ + unsigned int i; + + running_tracks = num_tracks; + + for (i=0; i<num_tracks; ++i) + { + MIDI_RestartIterator(tracks[i].iter); + ScheduleTrack(&tracks[i]); + } +} + // Callback function invoked when another event needs to be read from // a track. @@ -924,6 +981,23 @@ static void TrackTimerCallback(void *arg) ProcessEvent(track, event); + // End of track? + + if (event->event_type == MIDI_EVENT_META + && event->data.meta.type == MIDI_META_END_OF_TRACK) + { + --running_tracks; + + // When all tracks have finished, restart the song. + + if (running_tracks <= 0 && song_looping) + { + RestartSong(); + } + + return; + } + // Reschedule the callback for the next event in the track. ScheduleTrack(track); @@ -1001,7 +1075,11 @@ static void I_OPL_PlaySong(void *handle, int looping) tracks = malloc(MIDI_NumTracks(file) * sizeof(opl_track_data_t)); - for (i=0; i<MIDI_NumTracks(file); ++i) + num_tracks = MIDI_NumTracks(file); + running_tracks = num_tracks; + song_looping = looping; + + for (i=0; i<num_tracks; ++i) { StartTrack(file, i); } @@ -1046,6 +1124,15 @@ static void I_OPL_StopSong(void) ReleaseVoice(&voices[i]); } } + + // Free all track data. + + for (i=0; i<num_tracks; ++i) + { + MIDI_FreeIterator(tracks[i].iter); + } + + free(tracks); } static void I_OPL_UnRegisterSong(void *handle) diff --git a/src/midifile.c b/src/midifile.c index f1d8bb93..bd935ca1 100644 --- a/src/midifile.c +++ b/src/midifile.c @@ -655,6 +655,11 @@ midi_track_iter_t *MIDI_IterateTrack(midi_file_t *file, unsigned int track) return iter; } +void MIDI_FreeIterator(midi_track_iter_t *iter) +{ + free(iter); +} + // Get the time until the next MIDI event in a track. unsigned int MIDI_GetDeltaTime(midi_track_iter_t *iter) @@ -695,6 +700,11 @@ unsigned int MIDI_GetFileTimeDivision(midi_file_t *file) return file->header.time_division; } +void MIDI_RestartIterator(midi_track_iter_t *iter) +{ + iter->position = 0; +} + #ifdef TEST static char *MIDI_EventTypeToString(midi_event_type_t event_type) diff --git a/src/midifile.h b/src/midifile.h index faef549c..4ee0ddb2 100644 --- a/src/midifile.h +++ b/src/midifile.h @@ -155,6 +155,10 @@ unsigned int MIDI_NumTracks(midi_file_t *file); midi_track_iter_t *MIDI_IterateTrack(midi_file_t *file, unsigned int track_num); +// Free an iterator. + +void MIDI_FreeIterator(midi_track_iter_t *iter); + // Get the time until the next MIDI event in a track. unsigned int MIDI_GetDeltaTime(midi_track_iter_t *iter); @@ -163,5 +167,9 @@ unsigned int MIDI_GetDeltaTime(midi_track_iter_t *iter); int MIDI_GetNextEvent(midi_track_iter_t *iter, midi_event_t **event); +// Reset an iterator to the beginning of a track. + +void MIDI_RestartIterator(midi_track_iter_t *iter); + #endif /* #ifndef MIDIFILE_H */ |