Hook up audio for DMA sound channels

This commit is contained in:
Jeffrey Pfau 2013-10-02 02:40:16 -07:00
parent a834f8b1f6
commit ba0596da07
5 changed files with 123 additions and 7 deletions

View File

@ -3,7 +3,7 @@
#include "gba.h" #include "gba.h"
#include "gba-io.h" #include "gba-io.h"
const unsigned GBA_AUDIO_SAMPLES = 4096 * sizeof(int32_t); const unsigned GBA_AUDIO_SAMPLES = 1024;
const unsigned GBA_AUDIO_FIFO_SIZE = 8 * sizeof(int32_t); const unsigned GBA_AUDIO_FIFO_SIZE = 8 * sizeof(int32_t);
static void _sample(struct GBAAudio* audio); static void _sample(struct GBAAudio* audio);
@ -15,8 +15,8 @@ void GBAAudioInit(struct GBAAudio* audio) {
audio->sampleRate = 0x8000; audio->sampleRate = 0x8000;
audio->sampleInterval = GBA_ARM7TDMI_FREQUENCY / audio->sampleRate; audio->sampleInterval = GBA_ARM7TDMI_FREQUENCY / audio->sampleRate;
CircleBufferInit(&audio->left, GBA_AUDIO_SAMPLES); CircleBufferInit(&audio->left, GBA_AUDIO_SAMPLES * sizeof(int32_t));
CircleBufferInit(&audio->right, GBA_AUDIO_SAMPLES); CircleBufferInit(&audio->right, GBA_AUDIO_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);
} }
@ -148,13 +148,29 @@ void GBAAudioSampleFIFO(struct GBAAudio* audio, int fifoId) {
dma->nextCount = 4; dma->nextCount = 4;
GBAMemoryServiceDMA(&audio->p->memory, channel->dmaSource, dma); GBAMemoryServiceDMA(&audio->p->memory, channel->dmaSource, dma);
} }
CircleBufferRead32(&channel->fifo, &channel->sample); CircleBufferRead8(&channel->fifo, &channel->sample);
} }
static void _sample(struct GBAAudio* audio) { static void _sample(struct GBAAudio* audio) {
int32_t sampleLeft = 0; int32_t sampleLeft = 0;
int32_t sampleRight = 0; int32_t sampleRight = 0;
if (audio->chALeft) {
sampleLeft += audio->chA.sample;
}
if (audio->chARight) {
sampleRight += audio->chA.sample;
}
if (audio->chBLeft) {
sampleLeft += audio->chB.sample;
}
if (audio->chBRight) {
sampleRight += audio->chB.sample;
}
CircleBufferWrite32(&audio->left, sampleLeft); CircleBufferWrite32(&audio->left, sampleLeft);
CircleBufferWrite32(&audio->right, sampleRight); CircleBufferWrite32(&audio->right, sampleRight);
} }

View File

@ -7,6 +7,8 @@
struct GBADMA; struct GBADMA;
const unsigned GBA_AUDIO_SAMPLES;
union GBAAudioWave { union GBAAudioWave {
struct { struct {
unsigned length : 6; unsigned length : 6;
@ -100,7 +102,7 @@ struct GBAAudioChannel4 {
struct GBAAudioFIFO { struct GBAAudioFIFO {
struct CircleBuffer fifo; struct CircleBuffer fifo;
int dmaSource; int dmaSource;
int32_t sample; int8_t sample;
}; };
struct GBAAudio { struct GBAAudio {

View File

@ -1,6 +1,7 @@
#include "debugger.h" #include "debugger.h"
#include "gba-thread.h" #include "gba-thread.h"
#include "gba.h" #include "gba.h"
#include "sdl-audio.h"
#include "sdl-events.h" #include "sdl-events.h"
#include "renderers/video-software.h" #include "renderers/video-software.h"
@ -19,6 +20,8 @@
struct GLSoftwareRenderer { struct GLSoftwareRenderer {
struct GBAVideoSoftwareRenderer d; struct GBAVideoSoftwareRenderer d;
struct GBASDLAudio audio;
struct GBASDLEvents events;
GLuint tex; GLuint tex;
}; };
@ -69,6 +72,7 @@ int main(int argc, char** argv) {
context.useDebugger = 1; context.useDebugger = 1;
context.renderer = &renderer.d.d; context.renderer = &renderer.d.d;
GBAThreadStart(&context); GBAThreadStart(&context);
renderer.audio.audio = &context.gba->audio;
_GBASDLRunloop(&context, &renderer); _GBASDLRunloop(&context, &renderer);
@ -85,7 +89,8 @@ static int _GBASDLInit(struct GLSoftwareRenderer* renderer) {
return 0; return 0;
} }
GBASDLInitEvents(); GBASDLInitEvents(&renderer->events);
GBASDLInitAudio(&renderer->audio);
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1); SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
@ -155,6 +160,7 @@ static void _GBASDLRunloop(struct GBAThread* context, struct GLSoftwareRenderer*
static void _GBASDLDeinit(struct GLSoftwareRenderer* renderer) { static void _GBASDLDeinit(struct GLSoftwareRenderer* renderer) {
free(renderer->d.outputBuffer); free(renderer->d.outputBuffer);
GBASDLDeinitEvents(); GBASDLDeinitEvents(&renderer->events);
GBASDLDeinitAudio(&renderer->audio);
SDL_Quit(); SDL_Quit();
} }

70
src/sdl/sdl-audio.c Normal file
View File

@ -0,0 +1,70 @@
#include "sdl-audio.h"
#include "gba.h"
static void _GBASDLAudioCallback(void* context, Uint8* data, int len);
int GBASDLInitAudio(struct GBASDLAudio* context) {
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
GBALog(0, GBA_LOG_ERROR, "Could not initialize SDL sound system");
return 0;
}
context->desiredSpec.freq = 44100;
context->desiredSpec.format = AUDIO_S16SYS;
context->desiredSpec.channels = 2;
context->desiredSpec.samples = GBA_AUDIO_SAMPLES >> 1;
context->desiredSpec.callback = _GBASDLAudioCallback;
context->desiredSpec.userdata = context;
context->audio = 0;
context->drift = 0.f;
if (SDL_OpenAudio(&context->desiredSpec, &context->obtainedSpec) < 0) {
GBALog(0, GBA_LOG_ERROR, "Could not open SDL sound system");
return 0;
}
SDL_PauseAudio(0);
return 1;
}
void GBASDLDeinitAudio(struct GBASDLAudio* context) {
(void)(context);
SDL_CloseAudio();
SDL_QuitSubSystem(SDL_INIT_AUDIO);
}
static void _pulldownResample(struct GBASDLAudio* context) {
int32_t value;
if (CircleBufferRead32(&context->audio->left, &value)) {
context->currentSample.left = value << 7;
} else {
context->currentSample.left = 0;
}
if (CircleBufferRead32(&context->audio->right, &value)) {
context->currentSample.right = value << 7;
} else {
context->currentSample.right = 0;
}
}
static void _GBASDLAudioCallback(void* context, Uint8* data, int len) {
struct GBASDLAudio* audioContext = context;
int i;
if (!context || !audioContext->audio) {
for (i = 0; i < len; ++i) {
data[i] = 0;
}
return;
}
struct StereoSample* ssamples = (struct StereoSample*) data;
len /= 2 * audioContext->obtainedSpec.channels;
if (audioContext->obtainedSpec.channels == 2) {
for (i = 0; i < len; ++i) {
audioContext->drift += audioContext->audio->sampleRate / (float) audioContext->obtainedSpec.freq;
while (audioContext->drift >= 0) {
_pulldownResample(audioContext);
audioContext->drift -= 1.f;
}
ssamples[i] = audioContext->currentSample;
}
}
}

22
src/sdl/sdl-audio.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef SDL_AUDIO_H
#define SDL_AUDIO_H
#include <SDL.h>
struct StereoSample {
Sint16 left;
Sint16 right;
};
struct GBASDLAudio {
SDL_AudioSpec desiredSpec;
SDL_AudioSpec obtainedSpec;
float drift;
struct GBAAudio* audio;
struct StereoSample currentSample;
};
int GBASDLInitAudio(struct GBASDLAudio* context);
void GBASDLDeinitAudio(struct GBASDLAudio* context);
#endif