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-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);
}
@ -69,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;
@ -669,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) {
@ -751,3 +786,7 @@ void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState
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);
}

View File

@ -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);
@ -251,4 +253,6 @@ 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

View File

@ -11,6 +11,8 @@
#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 @@ 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);
}
@ -202,6 +209,10 @@ bool GBAThreadStart(struct GBAThread* threadContext) {
threadContext->rewindBuffer = 0;
}
if (!threadContext->fpsTarget) {
threadContext->fpsTarget = _defaultFPSTarget;
}
if (threadContext->rom && !GBAIsROM(threadContext->rom)) {
threadContext->rom->close(threadContext->rom);
threadContext->rom = 0;
@ -545,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);

View File

@ -56,6 +56,8 @@ struct GBAThread {
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

View File

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

View File

@ -85,6 +85,7 @@ int main(int argc, char** argv) {
struct GBAThread context = {
.renderer = &renderer.d.d,
.audioBuffers = 512,
.startCallback = _GBASDLStart,
.cleanCallback = _GBASDLClean,
.sync.videoFrameWait = 0,
@ -96,6 +97,9 @@ int main(int argc, char** argv) {
GBAMapOptionsToContext(&opts, &context);
renderer.audio.samples = context.audioBuffers;
GBASDLInitAudio(&renderer.audio);
GBAThreadStart(&context);
_GBASDLRunloop(&context, &renderer);
@ -115,7 +119,6 @@ static int _GBASDLInit(struct GLSoftwareRenderer* renderer) {
}
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 _GBASDLDeinit(struct GLSoftwareRenderer* renderer) {
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) {

View File

@ -4,7 +4,6 @@
#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 @@ bool GBASDLInitAudio(struct GBASDLAudio* context) {
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 @@ static void _GBASDLAudioCallback(void* context, Uint8* data, int len) {
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) {

View File

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

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) {
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:

View File

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

View File

@ -2,13 +2,13 @@
#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,10 +26,14 @@ void CircleBufferDeinit(struct CircleBuffer* buffer) {
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) {
buffer->size = 0;
buffer->readPtr = buffer->data;
@ -140,7 +144,7 @@ int CircleBufferRead32(struct CircleBuffer* buffer, int32_t* value) {
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 @@ int CircleBufferRead(struct CircleBuffer* buffer, void* output, size_t 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;
if (buffer->size == 0) {
return 0;

View File

@ -5,21 +5,22 @@
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