all repos — mgba @ 3e3bb58ae5860673c7c25ed92833f6392063ddb1

mGBA Game Boy Advance Emulator

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}