all repos — mgba @ a55b4dc87f31bbb4dc9629d1335270f32b00db29

mGBA Game Boy Advance Emulator

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 << 7;
41	} else {
42		context->currentSample.left = 0;
43	}
44	if (CircleBufferRead32(&context->audio->right, &value)) {
45		context->currentSample.right = value << 7;
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}