all repos — mgba @ 2ee648a2bb4a0953d489e0bf225bba7d9d9752dc

mGBA Game Boy Advance Emulator

Core: Fix audio sync breaking when interrupted
Vicki Pfau vi@endrift.com
Mon, 28 May 2018 22:50:40 -0700
commit

2ee648a2bb4a0953d489e0bf225bba7d9d9752dc

parent

2aa8716cc95d380adcfa83131ad4d2aa3e071eaa

6 files changed, 27 insertions(+), 7 deletions(-)

jump to
M CHANGESCHANGES

@@ -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.hinclude/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.csrc/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.csrc/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.csrc/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.csrc/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);