Merge branch 'master' into qt

This commit is contained in:
Jeffrey Pfau 2014-07-21 22:51:26 -07:00
commit ae534aff74
12 changed files with 102 additions and 32 deletions

View File

@ -4,8 +4,9 @@
#include "gba-io.h" #include "gba-io.h"
#include "gba-serialize.h" #include "gba-serialize.h"
#include "gba-thread.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); const unsigned GBA_AUDIO_FIFO_SIZE = 8 * sizeof(int32_t);
#define SWEEP_CYCLES (GBA_ARM7TDMI_FREQUENCY / 128) #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 int _applyBias(struct GBAAudio* audio, int sample);
static void _sample(struct GBAAudio* audio); static void _sample(struct GBAAudio* audio);
void GBAAudioInit(struct GBAAudio* audio) { void GBAAudioInit(struct GBAAudio* audio, size_t samples) {
CircleBufferInit(&audio->left, GBA_AUDIO_SAMPLES * sizeof(int32_t)); CircleBufferInit(&audio->left, samples * sizeof(int32_t));
CircleBufferInit(&audio->right, GBA_AUDIO_SAMPLES * sizeof(int32_t)); CircleBufferInit(&audio->right, samples * sizeof(int32_t));
CircleBufferInit(&audio->chA.fifo, GBA_AUDIO_FIFO_SIZE); CircleBufferInit(&audio->chA.fifo, GBA_AUDIO_FIFO_SIZE);
CircleBufferInit(&audio->chB.fifo, GBA_AUDIO_FIFO_SIZE); CircleBufferInit(&audio->chB.fifo, GBA_AUDIO_FIFO_SIZE);
} }
@ -69,6 +70,40 @@ void GBAAudioDeinit(struct GBAAudio* audio) {
CircleBufferDeinit(&audio->chB.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) { int32_t GBAAudioProcessEvents(struct GBAAudio* audio, int32_t cycles) {
audio->nextEvent -= cycles; audio->nextEvent -= cycles;
audio->eventDiff += cycles; audio->eventDiff += cycles;
@ -669,7 +704,7 @@ static void _sample(struct GBAAudio* audio) {
CircleBufferWrite32(&audio->left, sampleLeft); CircleBufferWrite32(&audio->left, sampleLeft);
CircleBufferWrite32(&audio->right, sampleRight); CircleBufferWrite32(&audio->right, sampleRight);
unsigned produced = CircleBufferSize(&audio->left); 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) { void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* state) {
@ -751,3 +786,7 @@ void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState
audio->eventDiff = state->audio.eventDiff; audio->eventDiff = state->audio.eventDiff;
audio->nextSample = state->audio.nextSample; 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);
}

View File

@ -218,10 +218,12 @@ struct GBAStereoSample {
int16_t right; int16_t right;
}; };
void GBAAudioInit(struct GBAAudio* audio); void GBAAudioInit(struct GBAAudio* audio, size_t samples);
void GBAAudioReset(struct GBAAudio* audio); void GBAAudioReset(struct GBAAudio* audio);
void GBAAudioDeinit(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); int32_t GBAAudioProcessEvents(struct GBAAudio* audio, int32_t cycles);
void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA* info); void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA* info);
@ -251,4 +253,6 @@ struct GBASerializedState;
void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* state); void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* state);
void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState* state); void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState* state);
float GBAAudioCalculateRatio(struct GBAAudio* audio, float desiredFPS, float desiredSampleRatio);
#endif #endif

View File

@ -11,6 +11,8 @@
#include <signal.h> #include <signal.h>
static const float _defaultFPSTarget = 60.f;
#ifdef USE_PTHREADS #ifdef USE_PTHREADS
static pthread_key_t _contextKey; static pthread_key_t _contextKey;
static pthread_once_t _contextOnce = PTHREAD_ONCE_INIT; static pthread_once_t _contextOnce = PTHREAD_ONCE_INIT;
@ -84,6 +86,11 @@ static THREAD_ENTRY _GBAThreadRun(void* context) {
#else #else
TlsSetValue(_contextKey, threadContext); TlsSetValue(_contextKey, threadContext);
#endif #endif
if (threadContext->audioBuffers) {
GBAAudioResizeBuffer(&gba.audio, threadContext->audioBuffers);
}
if (threadContext->renderer) { if (threadContext->renderer) {
GBAVideoAssociateRenderer(&gba.video, threadContext->renderer); GBAVideoAssociateRenderer(&gba.video, threadContext->renderer);
} }
@ -202,6 +209,10 @@ bool GBAThreadStart(struct GBAThread* threadContext) {
threadContext->rewindBuffer = 0; threadContext->rewindBuffer = 0;
} }
if (!threadContext->fpsTarget) {
threadContext->fpsTarget = _defaultFPSTarget;
}
if (threadContext->rom && !GBAIsROM(threadContext->rom)) { if (threadContext->rom && !GBAIsROM(threadContext->rom)) {
threadContext->rom->close(threadContext->rom); threadContext->rom->close(threadContext->rom);
threadContext->rom = 0; threadContext->rom = 0;
@ -545,6 +556,10 @@ void GBASyncLockAudio(struct GBASync* sync) {
MutexLock(&sync->audioBufferMutex); MutexLock(&sync->audioBufferMutex);
} }
void GBASyncUnlockAudio(struct GBASync* sync) {
MutexUnlock(&sync->audioBufferMutex);
}
void GBASyncConsumeAudio(struct GBASync* sync) { void GBASyncConsumeAudio(struct GBASync* sync) {
ConditionWake(&sync->audioRequiredCond); ConditionWake(&sync->audioRequiredCond);
MutexUnlock(&sync->audioBufferMutex); MutexUnlock(&sync->audioBufferMutex);

View File

@ -56,6 +56,8 @@ struct GBAThread {
const char* fname; const char* fname;
int activeKeys; int activeKeys;
int frameskip; int frameskip;
float fpsTarget;
size_t audioBuffers;
// Threading state // Threading state
Thread thread; Thread thread;
@ -105,6 +107,7 @@ bool GBASyncDrawingFrame(struct GBASync* sync);
void GBASyncProduceAudio(struct GBASync* sync, int wait); void GBASyncProduceAudio(struct GBASync* sync, int wait);
void GBASyncLockAudio(struct GBASync* sync); void GBASyncLockAudio(struct GBASync* sync);
void GBASyncUnlockAudio(struct GBASync* sync);
void GBASyncConsumeAudio(struct GBASync* sync); void GBASyncConsumeAudio(struct GBASync* sync);
#endif #endif

View File

@ -121,7 +121,7 @@ static void GBAInit(struct ARMCore* cpu, struct ARMComponent* component) {
GBAVideoInit(&gba->video); GBAVideoInit(&gba->video);
gba->audio.p = gba; gba->audio.p = gba;
GBAAudioInit(&gba->audio); GBAAudioInit(&gba->audio, GBA_AUDIO_SAMPLES);
GBAIOInit(gba); GBAIOInit(gba);

View File

@ -85,6 +85,7 @@ int main(int argc, char** argv) {
struct GBAThread context = { struct GBAThread context = {
.renderer = &renderer.d.d, .renderer = &renderer.d.d,
.audioBuffers = 512,
.startCallback = _GBASDLStart, .startCallback = _GBASDLStart,
.cleanCallback = _GBASDLClean, .cleanCallback = _GBASDLClean,
.sync.videoFrameWait = 0, .sync.videoFrameWait = 0,
@ -96,6 +97,9 @@ int main(int argc, char** argv) {
GBAMapOptionsToContext(&opts, &context); GBAMapOptionsToContext(&opts, &context);
renderer.audio.samples = context.audioBuffers;
GBASDLInitAudio(&renderer.audio);
GBAThreadStart(&context); GBAThreadStart(&context);
_GBASDLRunloop(&context, &renderer); _GBASDLRunloop(&context, &renderer);
@ -115,7 +119,6 @@ static int _GBASDLInit(struct GLSoftwareRenderer* renderer) {
} }
GBASDLInitEvents(&renderer->events); GBASDLInitEvents(&renderer->events);
GBASDLInitAudio(&renderer->audio);
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
@ -230,6 +233,7 @@ static void _GBASDLDeinit(struct GLSoftwareRenderer* renderer) {
static void _GBASDLStart(struct GBAThread* threadContext) { static void _GBASDLStart(struct GBAThread* threadContext) {
struct GLSoftwareRenderer* renderer = threadContext->userData; struct GLSoftwareRenderer* renderer = threadContext->userData;
renderer->audio.audio = &threadContext->gba->audio; renderer->audio.audio = &threadContext->gba->audio;
renderer->audio.thread = threadContext;
} }
static void _GBASDLClean(struct GBAThread* threadContext) { static void _GBASDLClean(struct GBAThread* threadContext) {

View File

@ -4,7 +4,6 @@
#include "gba-thread.h" #include "gba-thread.h"
#define BUFFER_SIZE (GBA_AUDIO_SAMPLES >> 2) #define BUFFER_SIZE (GBA_AUDIO_SAMPLES >> 2)
#define FPS_TARGET 60.f
static void _GBASDLAudioCallback(void* context, Uint8* data, int len); static void _GBASDLAudioCallback(void* context, Uint8* data, int len);
@ -17,10 +16,11 @@ bool GBASDLInitAudio(struct GBASDLAudio* context) {
context->desiredSpec.freq = 44100; context->desiredSpec.freq = 44100;
context->desiredSpec.format = AUDIO_S16SYS; context->desiredSpec.format = AUDIO_S16SYS;
context->desiredSpec.channels = 2; context->desiredSpec.channels = 2;
context->desiredSpec.samples = GBA_AUDIO_SAMPLES; context->desiredSpec.samples = context->samples;
context->desiredSpec.callback = _GBASDLAudioCallback; context->desiredSpec.callback = _GBASDLAudioCallback;
context->desiredSpec.userdata = context; context->desiredSpec.userdata = context;
context->audio = 0; context->audio = 0;
context->thread = 0;
context->drift = 0.f; context->drift = 0.f;
if (SDL_OpenAudio(&context->desiredSpec, &context->obtainedSpec) < 0) { if (SDL_OpenAudio(&context->desiredSpec, &context->obtainedSpec) < 0) {
GBALog(0, GBA_LOG_ERROR, "Could not open SDL sound system"); GBALog(0, GBA_LOG_ERROR, "Could not open SDL sound system");
@ -43,8 +43,7 @@ static void _GBASDLAudioCallback(void* context, Uint8* data, int len) {
memset(data, 0, len); memset(data, 0, len);
return; return;
} }
float ratio = 280896.0f * FPS_TARGET / GBA_ARM7TDMI_FREQUENCY; audioContext->ratio = GBAAudioCalculateRatio(audioContext->audio, audioContext->thread->fpsTarget, audioContext->obtainedSpec.freq);
audioContext->ratio = audioContext->obtainedSpec.freq / ratio / (float) audioContext->audio->sampleRate;
struct GBAStereoSample* ssamples = (struct GBAStereoSample*) data; struct GBAStereoSample* ssamples = (struct GBAStereoSample*) data;
len /= 2 * audioContext->obtainedSpec.channels; len /= 2 * audioContext->obtainedSpec.channels;
if (audioContext->obtainedSpec.channels == 2) { if (audioContext->obtainedSpec.channels == 2) {

View File

@ -6,11 +6,17 @@
#include <SDL.h> #include <SDL.h>
struct GBASDLAudio { struct GBASDLAudio {
// Input
size_t samples;
// State
SDL_AudioSpec desiredSpec; SDL_AudioSpec desiredSpec;
SDL_AudioSpec obtainedSpec; SDL_AudioSpec obtainedSpec;
float drift; float drift;
float ratio; float ratio;
struct GBAAudio* audio; struct GBAAudio* audio;
struct GBAThread* thread;
}; };
bool GBASDLInitAudio(struct GBASDLAudio* context); bool GBASDLInitAudio(struct GBASDLAudio* context);

View File

@ -248,14 +248,7 @@ static void _GBASDLHandleWindowEvent(struct GBAThread* context, struct GBASDLEve
void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const union SDL_Event* event) { void GBASDLHandleEvent(struct GBAThread* context, struct GBASDLEvents* sdlContext, const union SDL_Event* event) {
switch (event->type) { switch (event->type) {
case SDL_QUIT: case SDL_QUIT:
// FIXME: this isn't thread-safe GBAThreadEnd(context);
if (context->debugger) {
context->debugger->state = DEBUGGER_EXITING;
}
MutexLock(&context->stateMutex);
context->state = THREAD_EXITING;
ConditionWake(&context->stateCond);
MutexUnlock(&context->stateMutex);
break; break;
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
case SDL_WINDOWEVENT: case SDL_WINDOWEVENT:

View File

@ -79,6 +79,9 @@ int main(int argc, char** argv) {
GBAMapOptionsToContext(&opts, &context); GBAMapOptionsToContext(&opts, &context);
renderer.audio.samples = context.audioBuffers;
GBASDLInitAudio(&renderer.audio);
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
renderer.events.fullscreen = graphicsOpts.fullscreen; 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)); 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 @@ static int _GBASDLInit(struct SoftwareRenderer* renderer) {
} }
GBASDLInitEvents(&renderer->events); GBASDLInitEvents(&renderer->events);
GBASDLInitAudio(&renderer->audio);
#if !SDL_VERSION_ATLEAST(2, 0, 0) #if !SDL_VERSION_ATLEAST(2, 0, 0)
#ifdef COLOR_16_BIT #ifdef COLOR_16_BIT

View File

@ -2,13 +2,13 @@
#ifndef NDEBUG #ifndef NDEBUG
static int _checkIntegrity(struct CircleBuffer* buffer) { 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; 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; 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 1;
} }
return 0; return 0;
@ -26,10 +26,14 @@ void CircleBufferDeinit(struct CircleBuffer* buffer) {
buffer->data = 0; buffer->data = 0;
} }
unsigned CircleBufferSize(const struct CircleBuffer* buffer) { size_t CircleBufferSize(const struct CircleBuffer* buffer) {
return buffer->size; return buffer->size;
} }
size_t CircleBufferCapacity(const struct CircleBuffer* buffer) {
return buffer->capacity;
}
void CircleBufferClear(struct CircleBuffer* buffer) { void CircleBufferClear(struct CircleBuffer* buffer) {
buffer->size = 0; buffer->size = 0;
buffer->readPtr = buffer->data; buffer->readPtr = buffer->data;
@ -140,7 +144,7 @@ int CircleBufferRead32(struct CircleBuffer* buffer, int32_t* value) {
return 4; 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; int8_t* data = buffer->readPtr;
if (buffer->size == 0) { if (buffer->size == 0) {
return 0; return 0;
@ -171,7 +175,7 @@ int CircleBufferRead(struct CircleBuffer* buffer, void* output, size_t length) {
return length; 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; int8_t* data = buffer->readPtr;
if (buffer->size == 0) { if (buffer->size == 0) {
return 0; return 0;

View File

@ -5,21 +5,22 @@
struct CircleBuffer { struct CircleBuffer {
void* data; void* data;
unsigned capacity; size_t capacity;
unsigned size; size_t size;
void* readPtr; void* readPtr;
void* writePtr; void* writePtr;
}; };
void CircleBufferInit(struct CircleBuffer* buffer, unsigned capacity); void CircleBufferInit(struct CircleBuffer* buffer, unsigned capacity);
void CircleBufferDeinit(struct CircleBuffer* buffer); 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); void CircleBufferClear(struct CircleBuffer* buffer);
int CircleBufferWrite8(struct CircleBuffer* buffer, int8_t value); int CircleBufferWrite8(struct CircleBuffer* buffer, int8_t value);
int CircleBufferWrite32(struct CircleBuffer* buffer, int32_t value); int CircleBufferWrite32(struct CircleBuffer* buffer, int32_t value);
int CircleBufferRead8(struct CircleBuffer* buffer, int8_t* value); int CircleBufferRead8(struct CircleBuffer* buffer, int8_t* value);
int CircleBufferRead32(struct CircleBuffer* buffer, int32_t* value); int CircleBufferRead32(struct CircleBuffer* buffer, int32_t* value);
int CircleBufferRead(struct CircleBuffer* buffer, void* output, size_t length); size_t CircleBufferRead(struct CircleBuffer* buffer, void* output, size_t length);
int CircleBufferDump(const struct CircleBuffer* buffer, void* output, size_t length); size_t CircleBufferDump(const struct CircleBuffer* buffer, void* output, size_t length);
#endif #endif