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.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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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