Core: Fix audio sync breaking when interrupted
Vicki Pfau vi@endrift.com
Mon, 28 May 2018 22:50:40 -0700
6 files changed,
27 insertions(+),
7 deletions(-)
M
CHANGES
→
CHANGES
@@ -34,6 +34,7 @@ - GBA Hardware: Fix RTC overriding light sensor (fixes mgba.io/i/1069)
- 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)
M
include/mgba/core/sync.h
→
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);
M
src/core/sync.c
→
src/core/sync.c
@@ -5,6 +5,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include <mgba/core/sync.h> +#include <mgba/core/blip_buf.h> + 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 @@
_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) {
M
src/core/thread.c
→
src/core/thread.c
@@ -5,6 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include <mgba/core/thread.h> +#include <mgba/core/blip_buf.h> #include <mgba/core/core.h> #include <mgba/core/serialize.h> #include <mgba-util/patch.h>@@ -219,6 +220,11 @@
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);
M
src/gb/audio.c
→
src/gb/audio.c
@@ -667,7 +667,10 @@ if (audio->p->stream && audio->p->stream->postAudioFrame) {
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);
M
src/gba/audio.c
→
src/gba/audio.c
@@ -307,7 +307,10 @@ if (audio->p->stream && audio->p->stream->postAudioFrame) {
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);