src/platform/sdl/sdl-audio.c (view raw)
1/* Copyright (c) 2013-2014 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "sdl-audio.h"
7
8#include "gba.h"
9#include "gba-thread.h"
10
11#ifdef USE_FFMPEG
12#include "platform/ffmpeg/ffmpeg-resample.h"
13#include <libavresample/avresample.h>
14#endif
15
16#define BUFFER_SIZE (GBA_AUDIO_SAMPLES >> 2)
17
18static void _GBASDLAudioCallback(void* context, Uint8* data, int len);
19
20bool GBASDLInitAudio(struct GBASDLAudio* context, struct GBAThread* threadContext) {
21 if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
22 GBALog(0, GBA_LOG_ERROR, "Could not initialize SDL sound system");
23 return false;
24 }
25
26 context->desiredSpec.freq = 44100;
27 context->desiredSpec.format = AUDIO_S16SYS;
28 context->desiredSpec.channels = 2;
29 context->desiredSpec.samples = context->samples;
30 context->desiredSpec.callback = _GBASDLAudioCallback;
31 context->desiredSpec.userdata = context;
32#ifndef USE_FFMPEG
33 context->drift = 0.f;
34#endif
35 if (SDL_OpenAudio(&context->desiredSpec, &context->obtainedSpec) < 0) {
36 GBALog(0, GBA_LOG_ERROR, "Could not open SDL sound system");
37 return false;
38 }
39 context->thread = threadContext;
40 context->samples = context->obtainedSpec.samples;
41 if (context->samples > threadContext->audioBuffers) {
42 threadContext->audioBuffers = context->samples * 2;
43 }
44
45#ifdef USE_FFMPEG
46 context->avr = 0;
47#endif
48
49 SDL_PauseAudio(0);
50 return true;
51}
52
53void GBASDLDeinitAudio(struct GBASDLAudio* context) {
54 UNUSED(context);
55 SDL_PauseAudio(1);
56 SDL_CloseAudio();
57 SDL_QuitSubSystem(SDL_INIT_AUDIO);
58#ifdef USE_FFMPEG
59 avresample_free(&context->avr);
60#endif
61}
62
63void GBASDLPauseAudio(struct GBASDLAudio* context) {
64 UNUSED(context);
65 SDL_PauseAudio(1);
66}
67
68void GBASDLResumeAudio(struct GBASDLAudio* context) {
69 UNUSED(context);
70 SDL_PauseAudio(0);
71}
72
73static void _GBASDLAudioCallback(void* context, Uint8* data, int len) {
74 struct GBASDLAudio* audioContext = context;
75 if (!context || !audioContext->thread || !audioContext->thread->gba) {
76 memset(data, 0, len);
77 return;
78 }
79#ifndef USE_FFMPEG
80 audioContext->ratio = GBAAudioCalculateRatio(&audioContext->thread->gba->audio, audioContext->thread->fpsTarget, audioContext->obtainedSpec.freq);
81 if (audioContext->ratio == INFINITY) {
82 memset(data, 0, len);
83 return;
84 }
85 struct GBAStereoSample* ssamples = (struct GBAStereoSample*) data;
86 len /= 2 * audioContext->obtainedSpec.channels;
87 if (audioContext->obtainedSpec.channels == 2) {
88 GBAAudioResampleNN(&audioContext->thread->gba->audio, audioContext->ratio, &audioContext->drift, ssamples, len);
89 }
90#else
91 if (!audioContext->avr) {
92 if (!audioContext->thread->gba->audio.sampleRate) {
93 memset(data, 0, len);
94 return;
95 }
96 audioContext->avr = GBAAudioOpenLAVR(&audioContext->thread->gba->audio, audioContext->obtainedSpec.freq);
97 }
98 struct GBAStereoSample* ssamples = (struct GBAStereoSample*) data;
99 len /= 2 * audioContext->obtainedSpec.channels;
100 GBAAudioResampleLAVR(&audioContext->thread->gba->audio, audioContext->avr, ssamples, len);
101#endif
102}