From 2ee648a2bb4a0953d489e0bf225bba7d9d9752dc Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 28 May 2018 22:50:40 -0700 Subject: [PATCH] Core: Fix audio sync breaking when interrupted --- CHANGES | 1 + include/mgba/core/sync.h | 3 ++- src/core/sync.c | 14 ++++++++++---- src/core/thread.c | 6 ++++++ src/gb/audio.c | 5 ++++- src/gba/audio.c | 5 ++++- 6 files changed, 27 insertions(+), 7 deletions(-) diff --git a/CHANGES b/CHANGES index 0e60c1fd5..5b324f977 100644 --- a/CHANGES +++ b/CHANGES @@ -34,6 +34,7 @@ Bugfixes: - GBA Savedata: Fix savedata modified time updating when read-only - GB Video: Fix enabling window when LY > WY (fixes mgba.io/i/409) - GBA Video: Start timing mid-scanline when skipping BIOS + - Core: Fix audio sync breaking when interrupted Misc: - GBA Timer: Use global cycles for timers - GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722) diff --git a/include/mgba/core/sync.h b/include/mgba/core/sync.h index 1ca30335a..d301108d8 100644 --- a/include/mgba/core/sync.h +++ b/include/mgba/core/sync.h @@ -33,7 +33,8 @@ bool mCoreSyncWaitFrameStart(struct mCoreSync* sync); void mCoreSyncWaitFrameEnd(struct mCoreSync* sync); void mCoreSyncSetVideoSync(struct mCoreSync* sync, bool wait); -void mCoreSyncProduceAudio(struct mCoreSync* sync, bool wait); +struct blip_t; +bool mCoreSyncProduceAudio(struct mCoreSync* sync, const struct blip_t*, size_t samples); void mCoreSyncLockAudio(struct mCoreSync* sync); void mCoreSyncUnlockAudio(struct mCoreSync* sync); void mCoreSyncConsumeAudio(struct mCoreSync* sync); diff --git a/src/core/sync.c b/src/core/sync.c index 5fc5e72d9..859c73eda 100644 --- a/src/core/sync.c +++ b/src/core/sync.c @@ -5,6 +5,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include +#include + static void _changeVideoSync(struct mCoreSync* sync, bool frameOn) { // Make sure the video thread can process events while the GBA thread is paused MutexLock(&sync->videoFrameMutex); @@ -76,16 +78,20 @@ void mCoreSyncSetVideoSync(struct mCoreSync* sync, bool wait) { _changeVideoSync(sync, wait); } -void mCoreSyncProduceAudio(struct mCoreSync* sync, bool wait) { +bool mCoreSyncProduceAudio(struct mCoreSync* sync, const struct blip_t* buf, size_t samples) { if (!sync) { - return; + return true; } - if (sync->audioWait && wait) { - // TODO loop properly in event of spurious wakeups + size_t produced = blip_samples_avail(buf); + size_t producedNew = produced; + while (sync->audioWait && producedNew >= samples) { ConditionWait(&sync->audioRequiredCond, &sync->audioBufferMutex); + produced = producedNew; + producedNew = blip_samples_avail(buf); } MutexUnlock(&sync->audioBufferMutex); + return producedNew != produced; } void mCoreSyncLockAudio(struct mCoreSync* sync) { diff --git a/src/core/thread.c b/src/core/thread.c index c08a1ab7e..7584f711f 100644 --- a/src/core/thread.c +++ b/src/core/thread.c @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include +#include #include #include #include @@ -219,6 +220,11 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { deferred = impl->state; while (impl->state >= THREAD_WAITING && impl->state <= THREAD_MAX_WAITING) { ConditionWait(&impl->stateCond, &impl->stateMutex); + + if (impl->sync.audioWait) { + mCoreSyncLockAudio(&impl->sync); + mCoreSyncProduceAudio(&impl->sync, core->getAudioChannel(core, 0), core->getAudioBufferSize(core)); + } } } MutexUnlock(&impl->stateMutex); diff --git a/src/gb/audio.c b/src/gb/audio.c index afacc6fdd..4b098230c 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -667,7 +667,10 @@ static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) { audio->p->stream->postAudioFrame(audio->p->stream, sampleLeft, sampleRight); } bool wait = produced >= audio->samples; - mCoreSyncProduceAudio(audio->p->sync, wait); + if (!mCoreSyncProduceAudio(audio->p->sync, audio->left, audio->samples)) { + // Interrupted + audio->p->earlyExit = true; + } if (wait && audio->p->stream && audio->p->stream->postAudioBuffer) { audio->p->stream->postAudioBuffer(audio->p->stream, audio->left, audio->right); diff --git a/src/gba/audio.c b/src/gba/audio.c index 8a12c36df..14f47ff56 100644 --- a/src/gba/audio.c +++ b/src/gba/audio.c @@ -307,7 +307,10 @@ static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) { audio->p->stream->postAudioFrame(audio->p->stream, sampleLeft, sampleRight); } bool wait = produced >= audio->samples; - mCoreSyncProduceAudio(audio->p->sync, wait); + if (!mCoreSyncProduceAudio(audio->p->sync, audio->psg.left, audio->samples)) { + // Interrupted + audio->p->earlyExit = true; + } if (wait && audio->p->stream && audio->p->stream->postAudioBuffer) { audio->p->stream->postAudioBuffer(audio->p->stream, audio->psg.left, audio->psg.right);