all repos — mgba @ 93b7779cb22a8ec64cf3ef8c4874ac9ac7ccbe7b

mGBA Game Boy Advance Emulator

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}