Merge branch 'master' into qt
@@ -4,8 +4,9 @@ #include "gba.h"
#include "gba-io.h" #include "gba-serialize.h" #include "gba-thread.h" +#include "gba-video.h" -const unsigned GBA_AUDIO_SAMPLES = 512; +const unsigned GBA_AUDIO_SAMPLES = 2048; const unsigned GBA_AUDIO_FIFO_SIZE = 8 * sizeof(int32_t); #define SWEEP_CYCLES (GBA_ARM7TDMI_FREQUENCY / 128)@@ -19,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); }@@ -67,6 +68,40 @@ CircleBufferDeinit(&audio->left);
CircleBufferDeinit(&audio->right); CircleBufferDeinit(&audio->chA.fifo); 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) {@@ -669,7 +704,7 @@ GBASyncLockAudio(audio->p->sync);
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) {@@ -751,3 +786,7 @@ audio->nextEvent = state->audio.nextEvent;
audio->eventDiff = state->audio.eventDiff; audio->nextSample = state->audio.nextSample; } + +float GBAAudioCalculateRatio(struct GBAAudio* audio, float desiredFPS, float desiredSampleRate) { + return desiredSampleRate * GBA_ARM7TDMI_FREQUENCY / (VIDEO_TOTAL_LENGTH * desiredFPS * audio->sampleRate); +}
@@ -218,9 +218,11 @@ int16_t left;
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);@@ -250,5 +252,7 @@
struct GBASerializedState; void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* state); void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState* state); + +float GBAAudioCalculateRatio(struct GBAAudio* audio, float desiredFPS, float desiredSampleRatio); #endif
@@ -11,6 +11,8 @@ #include "util/vfs.h"
#include <signal.h> +static const float _defaultFPSTarget = 60.f; + #ifdef USE_PTHREADS static pthread_key_t _contextKey; static pthread_once_t _contextOnce = PTHREAD_ONCE_INIT;@@ -84,6 +86,11 @@ pthread_setspecific(_contextKey, threadContext);
#else TlsSetValue(_contextKey, threadContext); #endif + + if (threadContext->audioBuffers) { + GBAAudioResizeBuffer(&gba.audio, threadContext->audioBuffers); + } + if (threadContext->renderer) { GBAVideoAssociateRenderer(&gba.video, threadContext->renderer); }@@ -200,6 +207,10 @@ if (threadContext->rewindBufferCapacity) {
threadContext->rewindBuffer = calloc(threadContext->rewindBufferCapacity, sizeof(void*)); } else { threadContext->rewindBuffer = 0; + } + + if (!threadContext->fpsTarget) { + threadContext->fpsTarget = _defaultFPSTarget; } if (threadContext->rom && !GBAIsROM(threadContext->rom)) {@@ -543,6 +554,10 @@ }
void GBASyncLockAudio(struct GBASync* sync) { MutexLock(&sync->audioBufferMutex); +} + +void GBASyncUnlockAudio(struct GBASync* sync) { + MutexUnlock(&sync->audioBufferMutex); } void GBASyncConsumeAudio(struct GBASync* sync) {
@@ -56,6 +56,8 @@ struct VFile* patch;
const char* fname; int activeKeys; int frameskip; + float fpsTarget; + size_t audioBuffers; // Threading state Thread thread;@@ -105,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
@@ -121,7 +121,7 @@ gba->video.p = gba;
GBAVideoInit(&gba->video); gba->audio.p = gba; - GBAAudioInit(&gba->audio); + GBAAudioInit(&gba->audio, GBA_AUDIO_SAMPLES); GBAIOInit(gba);
@@ -85,6 +85,7 @@ }
struct GBAThread context = { .renderer = &renderer.d.d, + .audioBuffers = 512, .startCallback = _GBASDLStart, .cleanCallback = _GBASDLClean, .sync.videoFrameWait = 0,@@ -95,6 +96,9 @@
context.debugger = createDebugger(&opts); GBAMapOptionsToContext(&opts, &context); + + renderer.audio.samples = context.audioBuffers; + GBASDLInitAudio(&renderer.audio); GBAThreadStart(&context);@@ -115,7 +119,6 @@ return 0;
} GBASDLInitEvents(&renderer->events); - GBASDLInitAudio(&renderer->audio); #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);@@ -230,6 +233,7 @@
static void _GBASDLStart(struct GBAThread* threadContext) { struct GLSoftwareRenderer* renderer = threadContext->userData; renderer->audio.audio = &threadContext->gba->audio; + renderer->audio.thread = threadContext; } static void _GBASDLClean(struct GBAThread* threadContext) {
@@ -4,7 +4,6 @@ #include "gba.h"
#include "gba-thread.h" #define BUFFER_SIZE (GBA_AUDIO_SAMPLES >> 2) -#define FPS_TARGET 60.f static void _GBASDLAudioCallback(void* context, Uint8* data, int len);@@ -17,10 +16,11 @@
context->desiredSpec.freq = 44100; context->desiredSpec.format = AUDIO_S16SYS; context->desiredSpec.channels = 2; - context->desiredSpec.samples = GBA_AUDIO_SAMPLES; + context->desiredSpec.samples = context->samples; context->desiredSpec.callback = _GBASDLAudioCallback; context->desiredSpec.userdata = context; context->audio = 0; + context->thread = 0; context->drift = 0.f; if (SDL_OpenAudio(&context->desiredSpec, &context->obtainedSpec) < 0) { GBALog(0, GBA_LOG_ERROR, "Could not open SDL sound system");@@ -43,8 +43,7 @@ if (!context || !audioContext->audio) {
memset(data, 0, len); return; } - float ratio = 280896.0f * FPS_TARGET / GBA_ARM7TDMI_FREQUENCY; - audioContext->ratio = audioContext->obtainedSpec.freq / ratio / (float) audioContext->audio->sampleRate; + audioContext->ratio = GBAAudioCalculateRatio(audioContext->audio, audioContext->thread->fpsTarget, audioContext->obtainedSpec.freq); struct GBAStereoSample* ssamples = (struct GBAStereoSample*) data; len /= 2 * audioContext->obtainedSpec.channels; if (audioContext->obtainedSpec.channels == 2) {
@@ -6,11 +6,17 @@
#include <SDL.h> struct GBASDLAudio { + // Input + size_t samples; + + // State SDL_AudioSpec desiredSpec; SDL_AudioSpec obtainedSpec; float drift; float ratio; + struct GBAAudio* audio; + struct GBAThread* thread; }; bool GBASDLInitAudio(struct GBASDLAudio* context);
@@ -248,14 +248,7 @@
void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const union SDL_Event* event) { switch (event->type) { case SDL_QUIT: - // FIXME: this isn't thread-safe - if (context->debugger) { - context->debugger->state = DEBUGGER_EXITING; - } - MutexLock(&context->stateMutex); - context->state = THREAD_EXITING; - ConditionWake(&context->stateCond); - MutexUnlock(&context->stateMutex); + GBAThreadEnd(context); break; #if SDL_VERSION_ATLEAST(2, 0, 0) case SDL_WINDOWEVENT:
@@ -79,6 +79,9 @@ context.debugger = createDebugger(&opts);
GBAMapOptionsToContext(&opts, &context); + renderer.audio.samples = context.audioBuffers; + GBASDLInitAudio(&renderer.audio); + #if SDL_VERSION_ATLEAST(2, 0, 0) renderer.events.fullscreen = graphicsOpts.fullscreen; renderer.window = SDL_CreateWindow(PROJECT_NAME, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, renderer.viewportWidth, renderer.viewportHeight, SDL_WINDOW_OPENGL | (SDL_WINDOW_FULLSCREEN_DESKTOP * renderer.events.fullscreen));@@ -145,7 +148,6 @@ return 0;
} GBASDLInitEvents(&renderer->events); - GBASDLInitAudio(&renderer->audio); #if !SDL_VERSION_ATLEAST(2, 0, 0) #ifdef COLOR_16_BIT
@@ -2,13 +2,13 @@ #include "circle-buffer.h"
#ifndef NDEBUG static int _checkIntegrity(struct CircleBuffer* buffer) { - if ((int8_t*) buffer->writePtr - (int8_t*) buffer->readPtr == buffer->size) { + if ((int8_t*) buffer->writePtr - (int8_t*) buffer->readPtr == (ssize_t) buffer->size) { return 1; } - if (buffer->capacity - buffer->size == ((int8_t*) buffer->writePtr - (int8_t*) buffer->readPtr)) { + if ((ssize_t) (buffer->capacity - buffer->size) == ((int8_t*) buffer->writePtr - (int8_t*) buffer->readPtr)) { return 1; } - if (buffer->capacity - buffer->size == ((int8_t*) buffer->readPtr - (int8_t*) buffer->writePtr)) { + if ((ssize_t) (buffer->capacity - buffer->size) == ((int8_t*) buffer->readPtr - (int8_t*) buffer->writePtr)) { return 1; } return 0;@@ -26,8 +26,12 @@ free(buffer->data);
buffer->data = 0; } -unsigned CircleBufferSize(const struct CircleBuffer* buffer) { +size_t CircleBufferSize(const struct CircleBuffer* buffer) { return buffer->size; +} + +size_t CircleBufferCapacity(const struct CircleBuffer* buffer) { + return buffer->capacity; } void CircleBufferClear(struct CircleBuffer* buffer) {@@ -140,7 +144,7 @@ #endif
return 4; } -int CircleBufferRead(struct CircleBuffer* buffer, void* output, size_t length) { +size_t CircleBufferRead(struct CircleBuffer* buffer, void* output, size_t length) { int8_t* data = buffer->readPtr; if (buffer->size == 0) { return 0;@@ -171,7 +175,7 @@ #endif
return length; } -int CircleBufferDump(const struct CircleBuffer* buffer, void* output, size_t length) { +size_t CircleBufferDump(const struct CircleBuffer* buffer, void* output, size_t length) { int8_t* data = buffer->readPtr; if (buffer->size == 0) { return 0;
@@ -5,21 +5,22 @@ #include "common.h"
struct CircleBuffer { void* data; - unsigned capacity; - unsigned size; + size_t capacity; + size_t size; void* readPtr; void* writePtr; }; void CircleBufferInit(struct CircleBuffer* buffer, unsigned capacity); void CircleBufferDeinit(struct CircleBuffer* buffer); -unsigned CircleBufferSize(const struct CircleBuffer* buffer); +size_t CircleBufferSize(const struct CircleBuffer* buffer); +size_t CircleBufferCapacity(const struct CircleBuffer* buffer); void CircleBufferClear(struct CircleBuffer* buffer); int CircleBufferWrite8(struct CircleBuffer* buffer, int8_t value); int CircleBufferWrite32(struct CircleBuffer* buffer, int32_t value); int CircleBufferRead8(struct CircleBuffer* buffer, int8_t* value); int CircleBufferRead32(struct CircleBuffer* buffer, int32_t* value); -int CircleBufferRead(struct CircleBuffer* buffer, void* output, size_t length); -int CircleBufferDump(const struct CircleBuffer* buffer, void* output, size_t length); +size_t CircleBufferRead(struct CircleBuffer* buffer, void* output, size_t length); +size_t CircleBufferDump(const struct CircleBuffer* buffer, void* output, size_t length); #endif