src/platform/sdl/sdl-audio.c (view raw)
1#include "sdl-audio.h"
2
3#include "gba.h"
4#include "gba-thread.h"
5
6static void _GBASDLAudioCallback(void* context, Uint8* data, int len);
7
8int GBASDLInitAudio(struct GBASDLAudio* context) {
9 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
10 GBALog(0, GBA_LOG_ERROR, "Could not initialize SDL sound system");
11 return 0;
12 }
13
14 context->desiredSpec.freq = 44100;
15 context->desiredSpec.format = AUDIO_S16SYS;
16 context->desiredSpec.channels = 2;
17 context->desiredSpec.samples = GBA_AUDIO_SAMPLES >> 2;
18 context->desiredSpec.callback = _GBASDLAudioCallback;
19 context->desiredSpec.userdata = context;
20 context->audio = 0;
21 context->drift = 0.f;
22 if (SDL_OpenAudio(&context->desiredSpec, &context->obtainedSpec) < 0) {
23 GBALog(0, GBA_LOG_ERROR, "Could not open SDL sound system");
24 return 0;
25 }
26 SDL_PauseAudio(0);
27 return 1;
28}
29
30void GBASDLDeinitAudio(struct GBASDLAudio* context) {
31 (void)(context);
32 SDL_PauseAudio(1);
33 SDL_CloseAudio();
34 SDL_QuitSubSystem(SDL_INIT_AUDIO);
35}
36
37static void _pulldownResample(struct GBASDLAudio* context) {
38 int32_t value;
39 if (CircleBufferRead32(&context->audio->left, &value)) {
40 context->currentSample.left = value << 5;
41 } else {
42 context->currentSample.left = 0;
43 }
44 if (CircleBufferRead32(&context->audio->right, &value)) {
45 context->currentSample.right = value << 5;
46 } else {
47 context->currentSample.right = 0;
48 }
49}
50
51static void _GBASDLAudioCallback(void* context, Uint8* data, int len) {
52 struct GBASDLAudio* audioContext = context;
53 int i;
54 if (!context || !audioContext->audio) {
55 for (i = 0; i < len; ++i) {
56 data[i] = 0;
57 }
58 return;
59 }
60 struct StereoSample* ssamples = (struct StereoSample*) data;
61 len /= 2 * audioContext->obtainedSpec.channels;
62 if (audioContext->obtainedSpec.channels == 2) {
63 pthread_mutex_lock(&audioContext->audio->bufferMutex);
64 for (i = 0; i < len; ++i) {
65 audioContext->drift += audioContext->audio->sampleRate / (float) audioContext->obtainedSpec.freq;
66 while (audioContext->drift >= 0) {
67 _pulldownResample(audioContext);
68 audioContext->drift -= 1.f;
69 }
70 ssamples[i] = audioContext->currentSample;
71 }
72 GBASyncConsumeAudio(audioContext->audio->p->sync);
73 pthread_mutex_unlock(&audioContext->audio->bufferMutex);
74 }
75}