Implement pausing of music.
Subversion-branch: /branches/opl-branch Subversion-revision: 1688
This commit is contained in:
parent
38b5ee9991
commit
79698ecfd9
9 changed files with 99 additions and 11 deletions
1
OPL-TODO
1
OPL-TODO
|
|
@ -15,7 +15,6 @@ Bad MIDIs:
|
|||
|
||||
Other tasks:
|
||||
|
||||
* Pause music
|
||||
* Add option to select MIDI type in setup tool
|
||||
* DMXOPTIONS opl3/phase option support.
|
||||
|
||||
|
|
|
|||
10
opl/opl.c
10
opl/opl.c
|
|
@ -33,7 +33,7 @@
|
|||
#include "opl.h"
|
||||
#include "opl_internal.h"
|
||||
|
||||
//#define OPL_DEBUG_TRACE
|
||||
#define OPL_DEBUG_TRACE
|
||||
|
||||
#ifdef HAVE_IOPERM
|
||||
extern opl_driver_t opl_linux_driver;
|
||||
|
|
@ -195,3 +195,11 @@ void OPL_Delay(unsigned int ms)
|
|||
SDL_DestroyCond(delay_data.cond);
|
||||
}
|
||||
|
||||
void OPL_SetPaused(int paused)
|
||||
{
|
||||
if (driver != NULL)
|
||||
{
|
||||
driver->set_paused_func(paused);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -96,5 +96,9 @@ void OPL_Unlock(void);
|
|||
|
||||
void OPL_Delay(unsigned int ms);
|
||||
|
||||
// Pause the OPL callbacks.
|
||||
|
||||
void OPL_SetPaused(int paused);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ typedef void (*opl_set_callback_func)(unsigned int ms,
|
|||
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 struct
|
||||
{
|
||||
|
|
@ -52,6 +53,7 @@ typedef struct
|
|||
opl_clear_callbacks_func clear_callbacks_func;
|
||||
opl_lock_func lock_func;
|
||||
opl_unlock_func unlock_func;
|
||||
opl_set_paused_func set_paused_func;
|
||||
} opl_driver_t;
|
||||
|
||||
#endif /* #ifndef OPL_INTERNAL_H */
|
||||
|
|
|
|||
|
|
@ -94,7 +94,8 @@ opl_driver_t opl_linux_driver =
|
|||
OPL_Timer_SetCallback,
|
||||
OPL_Timer_ClearCallbacks,
|
||||
OPL_Timer_Lock,
|
||||
OPL_Timer_Unlock
|
||||
OPL_Timer_Unlock,
|
||||
OPL_Timer_SetPaused
|
||||
};
|
||||
|
||||
#endif /* #ifdef HAVE_IOPERM */
|
||||
|
|
|
|||
|
|
@ -60,6 +60,15 @@ static SDL_mutex *callback_queue_mutex = NULL;
|
|||
|
||||
static int current_time;
|
||||
|
||||
// If non-zero, playback is currently paused.
|
||||
|
||||
static int opl_sdl_paused;
|
||||
|
||||
// Time offset (in samples) due to the fact that callbacks
|
||||
// were previously paused.
|
||||
|
||||
static unsigned int pause_offset;
|
||||
|
||||
// OPL software emulator structure.
|
||||
|
||||
static FM_OPL *opl_emulator = NULL;
|
||||
|
|
@ -96,11 +105,16 @@ static void AdvanceTime(unsigned int nsamples)
|
|||
|
||||
current_time += nsamples;
|
||||
|
||||
if (opl_sdl_paused)
|
||||
{
|
||||
pause_offset += nsamples;
|
||||
}
|
||||
|
||||
// Are there callbacks to invoke now? Keep invoking them
|
||||
// until there are none more left.
|
||||
|
||||
while (!OPL_Queue_IsEmpty(callback_queue)
|
||||
&& current_time >= OPL_Queue_Peek(callback_queue))
|
||||
&& current_time >= OPL_Queue_Peek(callback_queue) + pause_offset)
|
||||
{
|
||||
// Pop the callback from the queue to invoke it.
|
||||
|
||||
|
|
@ -180,13 +194,13 @@ static void OPL_Mix_Callback(void *udata,
|
|||
// the callback queue must be invoked. We can then fill the
|
||||
// buffer with this many samples.
|
||||
|
||||
if (OPL_Queue_IsEmpty(callback_queue))
|
||||
if (opl_sdl_paused || OPL_Queue_IsEmpty(callback_queue))
|
||||
{
|
||||
nsamples = buffer_len - filled;
|
||||
}
|
||||
else
|
||||
{
|
||||
next_callback_time = OPL_Queue_Peek(callback_queue);
|
||||
next_callback_time = OPL_Queue_Peek(callback_queue) + pause_offset;
|
||||
|
||||
nsamples = next_callback_time - current_time;
|
||||
|
||||
|
|
@ -260,7 +274,7 @@ static void TimerHandler(int channel, double interval_seconds)
|
|||
|
||||
SDL_LockMutex(callback_queue_mutex);
|
||||
OPL_Queue_Push(callback_queue, TimerOver, (void *) channel,
|
||||
current_time + interval_samples);
|
||||
current_time - pause_offset + interval_samples);
|
||||
SDL_UnlockMutex(callback_queue_mutex);
|
||||
}
|
||||
|
||||
|
|
@ -297,6 +311,9 @@ static int OPL_SDL_Init(unsigned int port_base)
|
|||
sdl_was_initialised = 0;
|
||||
}
|
||||
|
||||
opl_sdl_paused = 0;
|
||||
pause_offset = 0;
|
||||
|
||||
// Queue structure of callbacks to invoke.
|
||||
|
||||
callback_queue = OPL_Queue_Create();
|
||||
|
|
@ -370,7 +387,7 @@ static void OPL_SDL_SetCallback(unsigned int ms,
|
|||
{
|
||||
SDL_LockMutex(callback_queue_mutex);
|
||||
OPL_Queue_Push(callback_queue, callback, data,
|
||||
current_time + (ms * mixing_freq) / 1000);
|
||||
current_time - pause_offset + (ms * mixing_freq) / 1000);
|
||||
SDL_UnlockMutex(callback_queue_mutex);
|
||||
}
|
||||
|
||||
|
|
@ -391,6 +408,11 @@ static void OPL_SDL_Unlock(void)
|
|||
SDL_UnlockMutex(callback_mutex);
|
||||
}
|
||||
|
||||
static void OPL_SDL_SetPaused(int paused)
|
||||
{
|
||||
opl_sdl_paused = paused;
|
||||
}
|
||||
|
||||
opl_driver_t opl_sdl_driver =
|
||||
{
|
||||
"SDL",
|
||||
|
|
@ -401,6 +423,7 @@ opl_driver_t opl_sdl_driver =
|
|||
OPL_SDL_SetCallback,
|
||||
OPL_SDL_ClearCallbacks,
|
||||
OPL_SDL_Lock,
|
||||
OPL_SDL_Unlock
|
||||
OPL_SDL_Unlock,
|
||||
OPL_SDL_SetPaused
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,15 @@ static SDL_Thread *timer_thread = NULL;
|
|||
static thread_state_t timer_thread_state;
|
||||
static int current_time;
|
||||
|
||||
// If non-zero, callbacks are currently paused.
|
||||
|
||||
static int opl_timer_paused;
|
||||
|
||||
// Offset in milliseconds to adjust time due to the fact that playback
|
||||
// was paused.
|
||||
|
||||
static unsigned int pause_offset = 0;
|
||||
|
||||
// Queue of callbacks waiting to be invoked.
|
||||
// The callback queue mutex is held while the callback queue structure
|
||||
// or current_time is being accessed.
|
||||
|
|
@ -59,6 +68,17 @@ static SDL_mutex *timer_mutex;
|
|||
|
||||
static int CallbackWaiting(unsigned int *next_time)
|
||||
{
|
||||
// If paused, just wait in 50ms increments until unpaused.
|
||||
// Update pause_offset so after we unpause, the callback
|
||||
// times will be right.
|
||||
|
||||
if (opl_timer_paused)
|
||||
{
|
||||
*next_time = current_time + 50;
|
||||
pause_offset += 50;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If there are no queued callbacks, sleep for 50ms at a time
|
||||
// until a callback is added.
|
||||
|
||||
|
|
@ -72,7 +92,7 @@ static int CallbackWaiting(unsigned int *next_time)
|
|||
// If the time for the callback has not yet arrived,
|
||||
// we must sleep until the callback time.
|
||||
|
||||
*next_time = OPL_Queue_Peek(callback_queue);
|
||||
*next_time = OPL_Queue_Peek(callback_queue) + pause_offset;
|
||||
|
||||
return *next_time <= current_time;
|
||||
}
|
||||
|
|
@ -169,6 +189,8 @@ int OPL_Timer_StartThread(void)
|
|||
|
||||
timer_thread_state = THREAD_STATE_RUNNING;
|
||||
current_time = SDL_GetTicks();
|
||||
opl_timer_paused = 0;
|
||||
pause_offset = 0;
|
||||
|
||||
timer_thread = SDL_CreateThread(ThreadFunction, NULL);
|
||||
|
||||
|
|
@ -198,7 +220,8 @@ void OPL_Timer_StopThread(void)
|
|||
void OPL_Timer_SetCallback(unsigned int ms, opl_callback_t callback, void *data)
|
||||
{
|
||||
SDL_LockMutex(callback_queue_mutex);
|
||||
OPL_Queue_Push(callback_queue, callback, data, current_time + ms);
|
||||
OPL_Queue_Push(callback_queue, callback, data,
|
||||
current_time + ms - pause_offset);
|
||||
SDL_UnlockMutex(callback_queue_mutex);
|
||||
}
|
||||
|
||||
|
|
@ -219,3 +242,10 @@ void OPL_Timer_Unlock(void)
|
|||
SDL_UnlockMutex(timer_mutex);
|
||||
}
|
||||
|
||||
void OPL_Timer_SetPaused(int paused)
|
||||
{
|
||||
SDL_LockMutex(callback_queue_mutex);
|
||||
opl_timer_paused = paused;
|
||||
SDL_UnlockMutex(callback_queue_mutex);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ void OPL_Timer_SetCallback(unsigned int ms,
|
|||
void OPL_Timer_ClearCallbacks(void);
|
||||
void OPL_Timer_Lock(void);
|
||||
void OPL_Timer_Unlock(void);
|
||||
void OPL_Timer_SetPaused(int paused);
|
||||
|
||||
#endif /* #ifndef OPL_TIMER_H */
|
||||
|
||||
|
|
|
|||
|
|
@ -1363,10 +1363,28 @@ static void I_OPL_PlaySong(void *handle, int looping)
|
|||
|
||||
static void I_OPL_PauseSong(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (!music_initialised)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Pause OPL callbacks.
|
||||
|
||||
OPL_SetPaused(1);
|
||||
|
||||
// Turn off all main instrument voices (not percussion).
|
||||
// This is what Vanilla does.
|
||||
|
||||
for (i=0; i<OPL_NUM_VOICES; ++i)
|
||||
{
|
||||
if (voices[i].channel != NULL
|
||||
&& voices[i].current_instr < percussion_instrs)
|
||||
{
|
||||
VoiceKeyOff(&voices[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void I_OPL_ResumeSong(void)
|
||||
|
|
@ -1375,6 +1393,8 @@ static void I_OPL_ResumeSong(void)
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OPL_SetPaused(0);
|
||||
}
|
||||
|
||||
static void I_OPL_StopSong(void)
|
||||
|
|
|
|||
Loading…
Reference in a new issue