src/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_CloseAudio();
33 SDL_QuitSubSystem(SDL_INIT_AUDIO);
34}
35
36static void _pulldownResample(struct GBASDLAudio* context) {
37 int32_t value;
38 if (CircleBufferRead32(&context->audio->left, &value)) {
39 context->currentSample.left = value << 7;
40 } else {
41 context->currentSample.left = 0;
42 }
43 if (CircleBufferRead32(&context->audio->right, &value)) {
44 context->currentSample.right = value << 7;
45 } else {
46 context->currentSample.right = 0;
47 }
48}
49
50static void _GBASDLAudioCallback(void* context, Uint8* data, int len) {
51 struct GBASDLAudio* audioContext = context;
52 int i;
53 if (!context || !audioContext->audio) {
54 for (i = 0; i < len; ++i) {
55 data[i] = 0;
56 }
57 return;
58 }
59 struct StereoSample* ssamples = (struct StereoSample*) data;
60 len /= 2 * audioContext->obtainedSpec.channels;
61 if (audioContext->obtainedSpec.channels == 2) {
62 pthread_mutex_lock(&audioContext->audio->bufferMutex);
63 for (i = 0; i < len; ++i) {
64 audioContext->drift += audioContext->audio->sampleRate / (float) audioContext->obtainedSpec.freq;
65 while (audioContext->drift >= 0) {
66 _pulldownResample(audioContext);
67 audioContext->drift -= 1.f;
68 }
69 ssamples[i] = audioContext->currentSample;
70 }
71 GBASyncConsumeAudio(audioContext->audio->p->sync);
72 pthread_mutex_unlock(&audioContext->audio->bufferMutex);
73 }
74}