static void OPL_AdvanceTime(unsigned int nsamples) { opl_callback_t callback; void *callback_data; // Advance time. current_time += nsamples; if (opl_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) + pause_offset) { // Pop the callback from the queue to invoke it. if (!OPL_Queue_Pop(callback_queue, &callback, &callback_data)) { break; } callback(callback_data); } }
int main() { opl_callback_queue_t *queue; int iteration; queue = OPL_Queue_Create(); for (iteration=0; iteration<5000; ++iteration) { opl_callback_t callback; void *data; unsigned int time; unsigned int newtime; int i; for (i=0; i<MAX_OPL_QUEUE; ++i) { time = rand() % 0x10000; OPL_Queue_Push(queue, NULL, NULL, time); } time = 0; for (i=0; i<MAX_OPL_QUEUE; ++i) { assert(!OPL_Queue_IsEmpty(queue)); newtime = OPL_Queue_Peek(queue); assert(OPL_Queue_Pop(queue, &callback, &data)); assert(newtime >= time); time = newtime; } assert(OPL_Queue_IsEmpty(queue)); assert(!OPL_Queue_Pop(queue, &callback, &data)); } }
static void AdvanceTime(unsigned int nsamples) { opl_callback_t callback; void *callback_data; uint64_t us; SDL_LockMutex(callback_queue_mutex); // Advance time. us = ((uint64_t) nsamples * OPL_SECOND) / mixing_freq; current_time += us; if (opl_sdl_paused) { pause_offset += us; } // Are there callbacks to invoke now? Keep invoking them // until there are no more left. while (!OPL_Queue_IsEmpty(callback_queue) && current_time >= OPL_Queue_Peek(callback_queue) + pause_offset) { // Pop the callback from the queue to invoke it. if (!OPL_Queue_Pop(callback_queue, &callback, &callback_data)) { break; } // The mutex stuff here is a bit complicated. We must // hold callback_mutex when we invoke the callback (so that // the control thread can use OPL_Lock() to prevent callbacks // from being invoked), but we must not be holding // callback_queue_mutex, as the callback must be able to // call OPL_SetCallback to schedule new callbacks. SDL_UnlockMutex(callback_queue_mutex); SDL_LockMutex(callback_mutex); callback(callback_data); SDL_UnlockMutex(callback_mutex); SDL_LockMutex(callback_queue_mutex); } SDL_UnlockMutex(callback_queue_mutex); }
static uint64_t GetNextTime(void) { opl_callback_t callback = 0; void *callback_data = 0; uint64_t next_time; int have_callback; // Keep running through callbacks until there are none ready to // run. When we run out of callbacks, next_time will be set. do { SDL_LockMutex(callback_queue_mutex); // Check if the callback at the head of the list is ready to // be invoked. If so, pop from the head of the queue. have_callback = CallbackWaiting(&next_time); if (have_callback) { OPL_Queue_Pop(callback_queue, &callback, &callback_data); } SDL_UnlockMutex(callback_queue_mutex); // Now invoke the callback, if we have one. // The timer mutex is held while the callback is invoked. if (have_callback) { SDL_LockMutex(timer_mutex); callback(callback_data); SDL_UnlockMutex(timer_mutex); } } while (have_callback); return next_time; }