diff options
-rw-r--r-- | opl/opl.c | 8 | ||||
-rw-r--r-- | opl/opl.h | 5 | ||||
-rw-r--r-- | opl/opl_internal.h | 2 | ||||
-rw-r--r-- | opl/opl_linux.c | 3 | ||||
-rw-r--r-- | opl/opl_obsd.c | 3 | ||||
-rw-r--r-- | opl/opl_queue.c | 13 | ||||
-rw-r--r-- | opl/opl_queue.h | 2 | ||||
-rw-r--r-- | opl/opl_sdl.c | 10 | ||||
-rw-r--r-- | opl/opl_timer.c | 7 | ||||
-rw-r--r-- | opl/opl_timer.h | 1 | ||||
-rw-r--r-- | opl/opl_win32.c | 3 | ||||
-rw-r--r-- | src/i_oplmusic.c | 18 |
12 files changed, 65 insertions, 10 deletions
@@ -452,3 +452,11 @@ void OPL_SetPaused(int paused) } } +void OPL_AdjustCallbacks(float value) +{ + if (driver != NULL) + { + driver->adjust_callbacks_func(value); + } +} + @@ -104,6 +104,11 @@ void OPL_InitRegisters(void); void OPL_SetCallback(unsigned int ms, opl_callback_t callback, void *data); +// Adjust callback times by the specified factor. For example, a value of +// 0.5 will halve all remaining times. + +void OPL_AdjustCallbacks(float factor); + // Clear all OPL callbacks that have been set. void OPL_ClearCallbacks(void); diff --git a/opl/opl_internal.h b/opl/opl_internal.h index 91a275d5..24e79644 100644 --- a/opl/opl_internal.h +++ b/opl/opl_internal.h @@ -32,6 +32,7 @@ typedef void (*opl_clear_callbacks_func)(void); typedef void (*opl_lock_func)(void); typedef void (*opl_unlock_func)(void); typedef void (*opl_set_paused_func)(int paused); +typedef void (*opl_adjust_callbacks_func)(float value); typedef struct { @@ -46,6 +47,7 @@ typedef struct opl_lock_func lock_func; opl_unlock_func unlock_func; opl_set_paused_func set_paused_func; + opl_adjust_callbacks_func adjust_callbacks_func; } opl_driver_t; // Sample rate to use when doing software emulation. diff --git a/opl/opl_linux.c b/opl/opl_linux.c index 12d21075..5df5d468 100644 --- a/opl/opl_linux.c +++ b/opl/opl_linux.c @@ -95,7 +95,8 @@ opl_driver_t opl_linux_driver = OPL_Timer_ClearCallbacks, OPL_Timer_Lock, OPL_Timer_Unlock, - OPL_Timer_SetPaused + OPL_Timer_SetPaused, + OPL_Timer_AdjustCallbacks, }; #endif /* #ifdef HAVE_IOPERM */ diff --git a/opl/opl_obsd.c b/opl/opl_obsd.c index 3313c1b2..39e0c156 100644 --- a/opl/opl_obsd.c +++ b/opl/opl_obsd.c @@ -110,7 +110,8 @@ opl_driver_t opl_openbsd_driver = OPL_Timer_ClearCallbacks, OPL_Timer_Lock, OPL_Timer_Unlock, - OPL_Timer_SetPaused + OPL_Timer_SetPaused, + OPL_Timer_AdjustCallbacks, }; #endif /* #ifndef NO_OBSD_DRIVER */ diff --git a/opl/opl_queue.c b/opl/opl_queue.c index d05cc6a1..ee87a19b 100644 --- a/opl/opl_queue.c +++ b/opl/opl_queue.c @@ -201,6 +201,19 @@ unsigned int OPL_Queue_Peek(opl_callback_queue_t *queue) } } +void OPL_Queue_AdjustCallbacks(opl_callback_queue_t *queue, + unsigned int time, float factor) +{ + int offset; + int i; + + for (i = 0; i < queue->num_entries; ++i) + { + offset = queue->entries[i].time - time; + queue->entries[i].time = time + (int) (offset * factor); + } +} + #ifdef TEST #include <assert.h> diff --git a/opl/opl_queue.h b/opl/opl_queue.h index b0f479f4..20ddeda9 100644 --- a/opl/opl_queue.h +++ b/opl/opl_queue.h @@ -32,6 +32,8 @@ void OPL_Queue_Push(opl_callback_queue_t *queue, int OPL_Queue_Pop(opl_callback_queue_t *queue, opl_callback_t *callback, void **data); unsigned int OPL_Queue_Peek(opl_callback_queue_t *queue); +void OPL_Queue_AdjustCallbacks(opl_callback_queue_t *queue, + unsigned int time, float factor); #endif /* #ifndef OPL_QUEUE_H */ diff --git a/opl/opl_sdl.c b/opl/opl_sdl.c index 4cd3dc7b..3ed7f784 100644 --- a/opl/opl_sdl.c +++ b/opl/opl_sdl.c @@ -486,6 +486,13 @@ static void OPL_SDL_SetPaused(int paused) opl_sdl_paused = paused; } +static void OPL_SDL_AdjustCallbacks(float factor) +{ + SDL_LockMutex(callback_queue_mutex); + OPL_Queue_AdjustCallbacks(callback_queue, current_time, factor); + SDL_UnlockMutex(callback_queue_mutex); +} + opl_driver_t opl_sdl_driver = { "SDL", @@ -497,6 +504,7 @@ opl_driver_t opl_sdl_driver = OPL_SDL_ClearCallbacks, OPL_SDL_Lock, OPL_SDL_Unlock, - OPL_SDL_SetPaused + OPL_SDL_SetPaused, + OPL_SDL_AdjustCallbacks, }; diff --git a/opl/opl_timer.c b/opl/opl_timer.c index 97e5ea8b..bab15687 100644 --- a/opl/opl_timer.c +++ b/opl/opl_timer.c @@ -224,6 +224,13 @@ void OPL_Timer_ClearCallbacks(void) SDL_UnlockMutex(callback_queue_mutex); } +void OPL_Timer_AdjustCallbacks(float factor) +{ + SDL_LockMutex(callback_queue_mutex); + OPL_Queue_AdjustCallbacks(callback_queue, current_time, factor); + SDL_UnlockMutex(callback_queue_mutex); +} + void OPL_Timer_Lock(void) { SDL_LockMutex(timer_mutex); diff --git a/opl/opl_timer.h b/opl/opl_timer.h index 1febcac9..73544013 100644 --- a/opl/opl_timer.h +++ b/opl/opl_timer.h @@ -29,6 +29,7 @@ void OPL_Timer_ClearCallbacks(void); void OPL_Timer_Lock(void); void OPL_Timer_Unlock(void); void OPL_Timer_SetPaused(int paused); +void OPL_Timer_AdjustCallbacks(float factor); #endif /* #ifndef OPL_TIMER_H */ diff --git a/opl/opl_win32.c b/opl/opl_win32.c index c6c37803..ea7b9eeb 100644 --- a/opl/opl_win32.c +++ b/opl/opl_win32.c @@ -184,7 +184,8 @@ opl_driver_t opl_win32_driver = OPL_Timer_ClearCallbacks, OPL_Timer_Lock, OPL_Timer_Unlock, - OPL_Timer_SetPaused + OPL_Timer_SetPaused, + OPL_Timer_AdjustCallbacks, }; #endif /* #ifdef _WIN32 */ diff --git a/src/i_oplmusic.c b/src/i_oplmusic.c index f38e7162..489b6d55 100644 --- a/src/i_oplmusic.c +++ b/src/i_oplmusic.c @@ -1016,6 +1016,12 @@ static void PitchBendEvent(opl_track_data_t *track, midi_event_t *event) } } +static void MetaSetTempo(unsigned int tempo) +{ + OPL_AdjustCallbacks((float) us_per_beat / tempo); + us_per_beat = tempo; +} + // Process a meta event. static void MetaEvent(opl_track_data_t *track, midi_event_t *event) @@ -1041,7 +1047,7 @@ static void MetaEvent(opl_track_data_t *track, midi_event_t *event) case MIDI_META_SET_TEMPO: if (data_len == 3) { - us_per_beat = (data[0] << 16) | (data[1] << 8) | data[2]; + MetaSetTempo((data[0] << 16) | (data[1] << 8) | data[2]); } break; @@ -1168,19 +1174,19 @@ static void TrackTimerCallback(void *arg) static void ScheduleTrack(opl_track_data_t *track) { unsigned int nticks; - unsigned int ms; - static int total = 0; + uint64_t ms; // Get the number of milliseconds until the next event. nticks = MIDI_GetDeltaTime(track->iter); - ms = (nticks * us_per_beat * TEMPO_FUDGE_FACTOR) / ticks_per_beat; - total += ms; + ms = nticks; + ms *= us_per_beat * TEMPO_FUDGE_FACTOR; + ms /= ticks_per_beat; // Set a timer to be invoked when the next event is // ready to play. - OPL_SetCallback(ms, TrackTimerCallback, track); + OPL_SetCallback((unsigned int) ms, TrackTimerCallback, track); } // Initialize a channel. |