Core: Fix audio sync breaking when interrupted

This commit is contained in:
Vicki Pfau 2018-05-28 22:50:40 -07:00
parent 2aa8716cc9
commit 2ee648a2bb
6 changed files with 27 additions and 7 deletions

View File

@ -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)

View File

@ -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);

View File

@ -5,6 +5,8 @@
* 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 @@ 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) {

View File

@ -5,6 +5,7 @@
* 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 @@ 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);

View File

@ -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);

View File

@ -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);