foxygit / doom Log in
commit c7e82b3866134277e73f9a9d2b0f67da3fa403d0
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Tue Oct 14 22:59:42 2014 -0400
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Tue Oct 14 22:59:42 2014 -0400

    Fix OPL MIDI tempo calculations.

    It turns out that the way that tempo has been calculated in OPL playback
    has been broken for a long time. The mysterious "fudge factor" that I
    had to apply to tempo calculations is actually completely unnecessary:
    the byte-swapping in the MIDI_GetFileTimeDivision() function was being
    done wrong, so the time division being used by the OPL MIDI code was
    completely wrong. Presumably the multiply by 260 was close enough to an
    8-bit bitshift that it worked okayish, but large enough time division
    values would overflow a single byte and screw up.

    This fixes long-running OPL playback problems in a number of WADs, most
    notably Alien Vendetta. This *really* fixes #352.
---
 src/i_oplmusic.c | 6 +-----
 src/midifile.c   | 6 +++---
 2 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c
index bcc8fe68..a1e90506 100644
--- a/src/i_oplmusic.c
+++ b/src/i_oplmusic.c
@@ -46,9 +46,6 @@

 #define PERCUSSION_LOG_LEN 16

-// TODO: Figure out why this is needed.
-#define TEMPO_FUDGE_FACTOR 260
-
 typedef struct
 {
     byte tremolo;
@@ -1198,8 +1195,7 @@ static void ScheduleTrack(opl_track_data_t *track)
     // Get the number of microseconds until the next event.

     nticks = MIDI_GetDeltaTime(track->iter);
-    us = ((uint64_t) nticks * us_per_beat * TEMPO_FUDGE_FACTOR)
-       / ticks_per_beat;
+    us = ((uint64_t) nticks * us_per_beat) / ticks_per_beat;

     // Set a timer to be invoked when the next event is
     // ready to play.
diff --git a/src/midifile.c b/src/midifile.c
index 94ec4441..92ffd803 100644
--- a/src/midifile.c
+++ b/src/midifile.c
@@ -699,14 +699,14 @@ int MIDI_GetNextEvent(midi_track_iter_t *iter, midi_event_t **event)

 unsigned int MIDI_GetFileTimeDivision(midi_file_t *file)
 {
-    short result = SHORT(file->header.time_division);
+    short result = SDL_SwapBE16(file->header.time_division);

     // Negative time division indicates SMPTE time and must be handled
     // differently.
     if (result < 0)
     {
-        // TODO: Figure this out.
-        return 96;
+        return (signed int)(-(result/256))
+             * (signed int)(result & 0xFF);
     }
     else
     {