mirror of https://github.com/mgba-emu/mgba.git
Hook up audio for DMA sound channels
This commit is contained in:
parent
a834f8b1f6
commit
ba0596da07
|
@ -3,7 +3,7 @@
|
|||
#include "gba.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);
|
||||
|
||||
static void _sample(struct GBAAudio* audio);
|
||||
|
@ -15,8 +15,8 @@ void GBAAudioInit(struct GBAAudio* audio) {
|
|||
audio->sampleRate = 0x8000;
|
||||
audio->sampleInterval = GBA_ARM7TDMI_FREQUENCY / audio->sampleRate;
|
||||
|
||||
CircleBufferInit(&audio->left, GBA_AUDIO_SAMPLES);
|
||||
CircleBufferInit(&audio->right, GBA_AUDIO_SAMPLES);
|
||||
CircleBufferInit(&audio->left, GBA_AUDIO_SAMPLES * sizeof(int32_t));
|
||||
CircleBufferInit(&audio->right, GBA_AUDIO_SAMPLES * sizeof(int32_t));
|
||||
CircleBufferInit(&audio->chA.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;
|
||||
GBAMemoryServiceDMA(&audio->p->memory, channel->dmaSource, dma);
|
||||
}
|
||||
CircleBufferRead32(&channel->fifo, &channel->sample);
|
||||
CircleBufferRead8(&channel->fifo, &channel->sample);
|
||||
}
|
||||
|
||||
static void _sample(struct GBAAudio* audio) {
|
||||
int32_t sampleLeft = 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->right, sampleRight);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
struct GBADMA;
|
||||
|
||||
const unsigned GBA_AUDIO_SAMPLES;
|
||||
|
||||
union GBAAudioWave {
|
||||
struct {
|
||||
unsigned length : 6;
|
||||
|
@ -100,7 +102,7 @@ struct GBAAudioChannel4 {
|
|||
struct GBAAudioFIFO {
|
||||
struct CircleBuffer fifo;
|
||||
int dmaSource;
|
||||
int32_t sample;
|
||||
int8_t sample;
|
||||
};
|
||||
|
||||
struct GBAAudio {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "debugger.h"
|
||||
#include "gba-thread.h"
|
||||
#include "gba.h"
|
||||
#include "sdl-audio.h"
|
||||
#include "sdl-events.h"
|
||||
#include "renderers/video-software.h"
|
||||
|
||||
|
@ -19,6 +20,8 @@
|
|||
|
||||
struct GLSoftwareRenderer {
|
||||
struct GBAVideoSoftwareRenderer d;
|
||||
struct GBASDLAudio audio;
|
||||
struct GBASDLEvents events;
|
||||
|
||||
GLuint tex;
|
||||
};
|
||||
|
@ -69,6 +72,7 @@ int main(int argc, char** argv) {
|
|||
context.useDebugger = 1;
|
||||
context.renderer = &renderer.d.d;
|
||||
GBAThreadStart(&context);
|
||||
renderer.audio.audio = &context.gba->audio;
|
||||
|
||||
_GBASDLRunloop(&context, &renderer);
|
||||
|
||||
|
@ -85,7 +89,8 @@ static int _GBASDLInit(struct GLSoftwareRenderer* renderer) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
GBASDLInitEvents();
|
||||
GBASDLInitEvents(&renderer->events);
|
||||
GBASDLInitAudio(&renderer->audio);
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
|
||||
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) {
|
||||
free(renderer->d.outputBuffer);
|
||||
|
||||
GBASDLDeinitEvents();
|
||||
GBASDLDeinitEvents(&renderer->events);
|
||||
GBASDLDeinitAudio(&renderer->audio);
|
||||
SDL_Quit();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue