summaryrefslogtreecommitdiff
path: root/opl/opl_sdl.c
diff options
context:
space:
mode:
authorSimon Howard2014-05-11 00:14:04 -0400
committerSimon Howard2014-05-11 00:14:04 -0400
commit72ce4242077f23b7de876b977397856bd072a6b1 (patch)
tree1002b8eb4f15d16564a1acadfcd04a264cde558d /opl/opl_sdl.c
parent495694da29ff736fba2fdc696553ee7197247174 (diff)
downloadchocolate-doom-72ce4242077f23b7de876b977397856bd072a6b1.tar.gz
chocolate-doom-72ce4242077f23b7de876b977397856bd072a6b1.tar.bz2
chocolate-doom-72ce4242077f23b7de876b977397856bd072a6b1.zip
opl: Change library to use us instead of ms.
Multi-track MIDI files are played back using separate callback chains for each track, and this introduces the possibility of one track becoming out of sync with the others. This was noticeable in WADs that use multi-track MIDIs, such as Alien Vendetta. Increase the timing resolution to microsecond precision to fix this.
Diffstat (limited to 'opl/opl_sdl.c')
-rw-r--r--opl/opl_sdl.c31
1 files changed, 17 insertions, 14 deletions
diff --git a/opl/opl_sdl.c b/opl/opl_sdl.c
index 3ed7f784..fa9f047a 100644
--- a/opl/opl_sdl.c
+++ b/opl/opl_sdl.c
@@ -39,7 +39,7 @@ typedef struct
unsigned int rate; // Number of times the timer is advanced per sec.
unsigned int enabled; // Non-zero if timer is enabled.
unsigned int value; // Last value that was set.
- unsigned int expire_time; // Calculated time that timer will expire.
+ uint64_t expire_time; // Calculated time that timer will expire.
} opl_timer_t;
// When the callback mutex is locked using OPL_Lock, callback functions
@@ -55,18 +55,18 @@ static opl_callback_queue_t *callback_queue;
static SDL_mutex *callback_queue_mutex = NULL;
-// Current time, in number of samples since startup:
+// Current time, in us since startup:
-static int current_time;
+static uint64_t current_time;
// If non-zero, playback is currently paused.
static int opl_sdl_paused;
-// Time offset (in samples) due to the fact that callbacks
+// Time offset (in us) due to the fact that callbacks
// were previously paused.
-static unsigned int pause_offset;
+static uint64_t pause_offset;
// OPL software emulator structure.
@@ -106,20 +106,22 @@ static void AdvanceTime(unsigned int nsamples)
{
opl_callback_t callback;
void *callback_data;
+ uint64_t us;
SDL_LockMutex(callback_queue_mutex);
// Advance time.
- current_time += nsamples;
+ us = ((uint64_t) nsamples * OPL_SECOND) / mixing_freq;
+ current_time += us;
if (opl_sdl_paused)
{
- pause_offset += nsamples;
+ pause_offset += us;
}
// Are there callbacks to invoke now? Keep invoking them
- // until there are none more left.
+ // until there are no more left.
while (!OPL_Queue_IsEmpty(callback_queue)
&& current_time >= OPL_Queue_Peek(callback_queue) + pause_offset)
@@ -193,8 +195,8 @@ static void OPL_Mix_Callback(void *udata,
while (filled < buffer_len)
{
- unsigned int next_callback_time;
- unsigned int nsamples;
+ uint64_t next_callback_time;
+ uint64_t nsamples;
SDL_LockMutex(callback_queue_mutex);
@@ -210,7 +212,8 @@ static void OPL_Mix_Callback(void *udata,
{
next_callback_time = OPL_Queue_Peek(callback_queue) + pause_offset;
- nsamples = next_callback_time - current_time;
+ nsamples = (next_callback_time - current_time) * mixing_freq;
+ nsamples = (nsamples + OPL_SECOND - 1) / OPL_SECOND;
if (nsamples > buffer_len - filled)
{
@@ -395,7 +398,7 @@ static void OPLTimer_CalculateEndTime(opl_timer_t *timer)
{
tics = 0x100 - timer->value;
timer->expire_time = current_time
- + (tics * opl_sample_rate) / timer->rate;
+ + ((uint64_t) tics * OPL_SECOND) / timer->rate;
}
}
@@ -454,13 +457,13 @@ static void OPL_SDL_PortWrite(opl_port_t port, unsigned int value)
}
}
-static void OPL_SDL_SetCallback(unsigned int ms,
+static void OPL_SDL_SetCallback(unsigned int us,
opl_callback_t callback,
void *data)
{
SDL_LockMutex(callback_queue_mutex);
OPL_Queue_Push(callback_queue, callback, data,
- current_time - pause_offset + (ms * mixing_freq) / 1000);
+ current_time - pause_offset + us);
SDL_UnlockMutex(callback_queue_mutex);
}