all repos — mgba @ 9a0640f8346a76e9e6b68d1eaca15eb068541337

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	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}