From e898c2f0dec6ea5c6365fef9d494c7f94240bea5 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 8 May 2014 00:44:50 -0400 Subject: opl: Process MIDI 'set tempo' meta events. The MIDI format includes a special meta event to set the tempo of playback, and some WADs depend on this - notably the music in Alien Vendetta. Move the variables controlling tempo to the global scope (they are not per-track as I previously thought) and set when the tempo events are encountered. This is some progress towards resolving #334, but that bug is not yet completely fixed, because the tempo change does not retroactively apply to OPL timers that have already been set. --- src/i_oplmusic.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index a2bc22d8..f38e7162 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -46,6 +46,9 @@ #define PERCUSSION_LOG_LEN 16 +// TODO: Figure out why this is needed. +#define TEMPO_FUDGE_FACTOR 0.26 + typedef struct { byte tremolo; @@ -103,11 +106,6 @@ typedef struct // Track iterator used to read new events. midi_track_iter_t *iter; - - // Tempo control variables - - unsigned int ticks_per_beat; - unsigned int ms_per_beat; } opl_track_data_t; typedef struct opl_voice_s opl_voice_t; @@ -324,6 +322,11 @@ static unsigned int num_tracks = 0; static unsigned int running_tracks = 0; static boolean song_looping; +// Tempo control variables + +static unsigned int ticks_per_beat; +static unsigned int us_per_beat; + // Mini-log of recently played percussion instruments: static uint8_t last_perc[PERCUSSION_LOG_LEN]; @@ -1017,6 +1020,9 @@ static void PitchBendEvent(opl_track_data_t *track, midi_event_t *event) static void MetaEvent(opl_track_data_t *track, midi_event_t *event) { + byte *data = event->data.meta.data; + unsigned int data_len = event->data.meta.length; + switch (event->data.meta.type) { // Things we can just ignore. @@ -1032,6 +1038,13 @@ static void MetaEvent(opl_track_data_t *track, midi_event_t *event) case MIDI_META_SEQUENCER_SPECIFIC: break; + case MIDI_META_SET_TEMPO: + if (data_len == 3) + { + us_per_beat = (data[0] << 16) | (data[1] << 8) | data[2]; + } + break; + // End of track - actually handled when we run out of events // in the track, see below. @@ -1161,7 +1174,7 @@ static void ScheduleTrack(opl_track_data_t *track) // Get the number of milliseconds until the next event. nticks = MIDI_GetDeltaTime(track->iter); - ms = (nticks * track->ms_per_beat) / track->ticks_per_beat; + ms = (nticks * us_per_beat * TEMPO_FUDGE_FACTOR) / ticks_per_beat; total += ms; // Set a timer to be invoked when the next event is @@ -1190,12 +1203,6 @@ static void StartTrack(midi_file_t *file, unsigned int track_num) track = &tracks[track_num]; track->iter = MIDI_IterateTrack(file, track_num); - track->ticks_per_beat = MIDI_GetFileTimeDivision(file); - - // Default is 120 bpm. - // TODO: this is wrong - - track->ms_per_beat = 500 * 260; for (i=0; i