diff --git a/src/gba/gba-audio.c b/src/gba/gba-audio.c index 98c9dec11..6716abdc7 100644 --- a/src/gba/gba-audio.c +++ b/src/gba/gba-audio.c @@ -20,9 +20,9 @@ static int32_t _updateChannel4(struct GBAAudioChannel4* ch); static int _applyBias(struct GBAAudio* audio, int sample); static void _sample(struct GBAAudio* audio); -void GBAAudioInit(struct GBAAudio* audio) { - CircleBufferInit(&audio->left, GBA_AUDIO_SAMPLES * sizeof(int32_t)); - CircleBufferInit(&audio->right, GBA_AUDIO_SAMPLES * sizeof(int32_t)); +void GBAAudioInit(struct GBAAudio* audio, size_t samples) { + CircleBufferInit(&audio->left, samples * sizeof(int32_t)); + CircleBufferInit(&audio->right, samples * sizeof(int32_t)); CircleBufferInit(&audio->chA.fifo, GBA_AUDIO_FIFO_SIZE); CircleBufferInit(&audio->chB.fifo, GBA_AUDIO_FIFO_SIZE); } @@ -70,6 +70,40 @@ void GBAAudioDeinit(struct GBAAudio* audio) { CircleBufferDeinit(&audio->chB.fifo); } +void GBAAudioResizeBuffer(struct GBAAudio* audio, size_t samples) { + if (samples >= GBA_AUDIO_SAMPLES) { + return; + } + + GBASyncLockAudio(audio->p->sync); + int32_t buffer[GBA_AUDIO_SAMPLES]; + int32_t dummy; + size_t read; + size_t i; + + read = CircleBufferDump(&audio->left, buffer, sizeof(buffer)); + CircleBufferDeinit(&audio->left); + CircleBufferInit(&audio->left, samples * sizeof(int32_t)); + for (i = 0; i * sizeof(int32_t) < read; ++i) { + if (!CircleBufferWrite32(&audio->left, buffer[i])) { + CircleBufferRead32(&audio->left, &dummy); + CircleBufferWrite32(&audio->left, buffer[i]); + } + } + + read = CircleBufferDump(&audio->right, buffer, sizeof(buffer)); + CircleBufferDeinit(&audio->right); + CircleBufferInit(&audio->right, samples * sizeof(int32_t)); + for (i = 0; i * sizeof(int32_t) < read; ++i) { + if (!CircleBufferWrite32(&audio->right, buffer[i])) { + CircleBufferRead32(&audio->right, &dummy); + CircleBufferWrite32(&audio->right, buffer[i]); + } + } + + GBASyncUnlockAudio(audio->p->sync); +} + int32_t GBAAudioProcessEvents(struct GBAAudio* audio, int32_t cycles) { audio->nextEvent -= cycles; audio->eventDiff += cycles; @@ -670,7 +704,7 @@ static void _sample(struct GBAAudio* audio) { CircleBufferWrite32(&audio->left, sampleLeft); CircleBufferWrite32(&audio->right, sampleRight); unsigned produced = CircleBufferSize(&audio->left); - GBASyncProduceAudio(audio->p->sync, produced >= GBA_AUDIO_SAMPLES * 3); + GBASyncProduceAudio(audio->p->sync, produced >= CircleBufferCapacity(&audio->left) / sizeof(int32_t) * 3); } void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* state) { diff --git a/src/gba/gba-audio.h b/src/gba/gba-audio.h index def6ac89b..8fbc3960f 100644 --- a/src/gba/gba-audio.h +++ b/src/gba/gba-audio.h @@ -218,10 +218,12 @@ struct GBAStereoSample { int16_t right; }; -void GBAAudioInit(struct GBAAudio* audio); +void GBAAudioInit(struct GBAAudio* audio, size_t samples); void GBAAudioReset(struct GBAAudio* audio); void GBAAudioDeinit(struct GBAAudio* audio); +void GBAAudioResizeBuffer(struct GBAAudio* audio, size_t samples); + int32_t GBAAudioProcessEvents(struct GBAAudio* audio, int32_t cycles); void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA* info); diff --git a/src/gba/gba-thread.c b/src/gba/gba-thread.c index 9f9baf0ac..404cb26a6 100644 --- a/src/gba/gba-thread.c +++ b/src/gba/gba-thread.c @@ -86,6 +86,11 @@ static THREAD_ENTRY _GBAThreadRun(void* context) { #else TlsSetValue(_contextKey, threadContext); #endif + + if (threadContext->audioBuffers) { + GBAAudioResizeBuffer(&gba.audio, threadContext->audioBuffers); + } + if (threadContext->renderer) { GBAVideoAssociateRenderer(&gba.video, threadContext->renderer); } @@ -551,6 +556,10 @@ void GBASyncLockAudio(struct GBASync* sync) { MutexLock(&sync->audioBufferMutex); } +void GBASyncUnlockAudio(struct GBASync* sync) { + MutexUnlock(&sync->audioBufferMutex); +} + void GBASyncConsumeAudio(struct GBASync* sync) { ConditionWake(&sync->audioRequiredCond); MutexUnlock(&sync->audioBufferMutex); diff --git a/src/gba/gba-thread.h b/src/gba/gba-thread.h index 072fd4a13..9e8c96bd4 100644 --- a/src/gba/gba-thread.h +++ b/src/gba/gba-thread.h @@ -57,6 +57,7 @@ struct GBAThread { int activeKeys; int frameskip; float fpsTarget; + size_t audioBuffers; // Threading state Thread thread; @@ -106,6 +107,7 @@ bool GBASyncDrawingFrame(struct GBASync* sync); void GBASyncProduceAudio(struct GBASync* sync, int wait); void GBASyncLockAudio(struct GBASync* sync); +void GBASyncUnlockAudio(struct GBASync* sync); void GBASyncConsumeAudio(struct GBASync* sync); #endif diff --git a/src/gba/gba.c b/src/gba/gba.c index 6338e9425..05f97a0d5 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -121,7 +121,7 @@ static void GBAInit(struct ARMCore* cpu, struct ARMComponent* component) { GBAVideoInit(&gba->video); gba->audio.p = gba; - GBAAudioInit(&gba->audio); + GBAAudioInit(&gba->audio, GBA_AUDIO_SAMPLES); GBAIOInit(gba);