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 float ratio = GBAAudioCalculateRatio(0x8000, threadContext->fpsTarget, 44100);
42 threadContext->audioBuffers = context->samples / ratio;
43 if (context->samples > threadContext->audioBuffers) {
44 threadContext->audioBuffers = context->samples * 2;
45 }
46
47#ifdef USE_FFMPEG
48 context->avr = 0;
49#endif
50
51 SDL_PauseAudio(0);
52 return true;
53}
54
55void GBASDLDeinitAudio(struct GBASDLAudio* context) {
56 UNUSED(context);
57 SDL_PauseAudio(1);
58 SDL_CloseAudio();
59 SDL_QuitSubSystem(SDL_INIT_AUDIO);
60#ifdef USE_FFMPEG
61 avresample_free(&context->avr);
62#endif
63}
64
65void GBASDLPauseAudio(struct GBASDLAudio* context) {
66 UNUSED(context);
67 SDL_PauseAudio(1);
68}
69
70void GBASDLResumeAudio(struct GBASDLAudio* context) {
71 UNUSED(context);
72 SDL_PauseAudio(0);
73}
74
75static void _GBASDLAudioCallback(void* context, Uint8* data, int len) {
76 struct GBASDLAudio* audioContext = context;
77 if (!context || !audioContext->thread || !audioContext->thread->gba) {
78 memset(data, 0, len);
79 return;
80 }
81#ifndef USE_FFMPEG
82 audioContext->ratio = GBAAudioCalculateRatio(audioContext->thread->gba->audio.sampleRate, audioContext->thread->fpsTarget, audioContext->obtainedSpec.freq);
83 if (audioContext->ratio == INFINITY) {
84 memset(data, 0, len);
85 return;
86 }
87 struct GBAStereoSample* ssamples = (struct GBAStereoSample*) data;
88 len /= 2 * audioContext->obtainedSpec.channels;
89 if (audioContext->obtainedSpec.channels == 2) {
90 GBAAudioResampleNN(&audioContext->thread->gba->audio, audioContext->ratio, &audioContext->drift, ssamples, len);
91 }
92#else
93 float ratio = GBAAudioCalculateRatio(audioContext->thread->gba->audio.sampleRate, audioContext->thread->fpsTarget, audioContext->thread->gba->audio.sampleRate);
94 if (!audioContext->avr) {
95 if (!audioContext->thread->gba->audio.sampleRate) {
96 memset(data, 0, len);
97 return;
98 }
99 audioContext->ratio = ratio;
100 audioContext->avr = GBAAudioOpenLAVR(audioContext->thread->gba->audio.sampleRate / ratio, audioContext->obtainedSpec.freq);
101 } else if (ratio != audioContext->ratio) {
102 audioContext->ratio = ratio;
103 audioContext->avr = GBAAudioReopenLAVR(audioContext->avr, audioContext->thread->gba->audio.sampleRate / ratio, audioContext->obtainedSpec.freq);
104 }
105 struct GBAStereoSample* ssamples = (struct GBAStereoSample*) data;
106 len /= 2 * audioContext->obtainedSpec.channels;
107 GBAAudioResampleLAVR(&audioContext->thread->gba->audio, audioContext->avr, ssamples, len);
108#endif
109}