bool GBASDLInitAudio(struct GBASDLAudio* context, struct GBAThread* threadContext) { if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { GBALog(0, GBA_LOG_ERROR, "Could not initialize SDL sound system"); return false; } context->desiredSpec.freq = 44100; context->desiredSpec.format = AUDIO_S16SYS; context->desiredSpec.channels = 2; context->desiredSpec.samples = context->samples; context->desiredSpec.callback = _GBASDLAudioCallback; context->desiredSpec.userdata = context; #if RESAMPLE_LIBRARY == RESAMPLE_NN context->drift = 0.f; #endif if (SDL_OpenAudio(&context->desiredSpec, &context->obtainedSpec) < 0) { GBALog(0, GBA_LOG_ERROR, "Could not open SDL sound system"); return false; } context->thread = threadContext; context->samples = context->obtainedSpec.samples; float ratio = GBAAudioCalculateRatio(0x8000, threadContext->fpsTarget, 44100); threadContext->audioBuffers = context->samples / ratio; if (context->samples > threadContext->audioBuffers) { threadContext->audioBuffers = context->samples * 2; } SDL_PauseAudio(0); return true; }
bool GBASDLInitAudio(struct GBASDLAudio* context, struct GBAThread* threadContext) { if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { GBALog(0, GBA_LOG_ERROR, "Could not initialize SDL sound system: %s", SDL_GetError()); return false; } context->desiredSpec.freq = 44100; context->desiredSpec.format = AUDIO_S16SYS; context->desiredSpec.channels = 2; context->desiredSpec.samples = context->samples; context->desiredSpec.callback = _GBASDLAudioCallback; context->desiredSpec.userdata = context; #if RESAMPLE_LIBRARY == RESAMPLE_NN context->drift = 0.f; #endif #if SDL_VERSION_ATLEAST(2, 0, 0) context->deviceId = SDL_OpenAudioDevice(0, 0, &context->desiredSpec, &context->obtainedSpec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); if (context->deviceId == 0) { #else if (SDL_OpenAudio(&context->desiredSpec, &context->obtainedSpec) < 0) { #endif GBALog(0, GBA_LOG_ERROR, "Could not open SDL sound system"); return false; } context->thread = threadContext; context->samples = context->obtainedSpec.samples; float ratio = GBAAudioCalculateRatio(0x8000, threadContext->fpsTarget, 44100); threadContext->audioBuffers = context->samples / ratio; if (context->samples > threadContext->audioBuffers) { threadContext->audioBuffers = context->samples * 2; } #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_PauseAudioDevice(context->deviceId, 0); #else SDL_PauseAudio(0); #endif return true; } void GBASDLDeinitAudio(struct GBASDLAudio* context) { UNUSED(context); #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_PauseAudioDevice(context->deviceId, 1); SDL_CloseAudioDevice(context->deviceId); #else SDL_PauseAudio(1); SDL_CloseAudio(); #endif SDL_QuitSubSystem(SDL_INIT_AUDIO); }
static void _GBASDLAudioCallback(void* context, Uint8* data, int len) { struct GBASDLAudio* audioContext = context; if (!context || !audioContext->thread || !audioContext->thread->gba) { memset(data, 0, len); return; } #if RESAMPLE_LIBRARY == RESAMPLE_NN audioContext->ratio = GBAAudioCalculateRatio(audioContext->thread->gba->audio.sampleRate, audioContext->thread->fpsTarget, audioContext->obtainedSpec.freq); if (audioContext->ratio == INFINITY) { memset(data, 0, len); return; } struct GBAStereoSample* ssamples = (struct GBAStereoSample*) data; len /= 2 * audioContext->obtainedSpec.channels; if (audioContext->obtainedSpec.channels == 2) { GBAAudioResampleNN(&audioContext->thread->gba->audio, audioContext->ratio, &audioContext->drift, ssamples, len); } #elif RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF double fauxClock = GBAAudioCalculateRatio(1, audioContext->thread->fpsTarget, 1); GBASyncLockAudio(&audioContext->thread->sync); blip_set_rates(audioContext->thread->gba->audio.left, GBA_ARM7TDMI_FREQUENCY, audioContext->obtainedSpec.freq * fauxClock); blip_set_rates(audioContext->thread->gba->audio.right, GBA_ARM7TDMI_FREQUENCY, audioContext->obtainedSpec.freq * fauxClock); len /= 2 * audioContext->obtainedSpec.channels; int available = blip_samples_avail(audioContext->thread->gba->audio.left); if (available > len) { available = len; } blip_read_samples(audioContext->thread->gba->audio.left, (short*) data, available, audioContext->obtainedSpec.channels == 2); if (audioContext->obtainedSpec.channels == 2) { blip_read_samples(audioContext->thread->gba->audio.right, ((short*) data) + 1, available, 1); } GBASyncConsumeAudio(&audioContext->thread->sync); if (available < len) { memset(((short*) data) + audioContext->obtainedSpec.channels * available, 0, (len - available) * audioContext->obtainedSpec.channels * sizeof(short)); } #endif }
static void _mSDLAudioCallback(void* context, Uint8* data, int len) { struct mSDLAudio* audioContext = context; if (!context || !audioContext->core) { memset(data, 0, len); return; } blip_t* left = NULL; blip_t* right = NULL; int32_t clockRate = GBA_ARM7TDMI_FREQUENCY; if (audioContext->core) { left = audioContext->core->getAudioChannel(audioContext->core, 0); right = audioContext->core->getAudioChannel(audioContext->core, 1); clockRate = audioContext->core->frequency(audioContext->core); } double fauxClock = 1; if (audioContext->sync) { if (audioContext->sync->fpsTarget > 0) { fauxClock = GBAAudioCalculateRatio(1, audioContext->sync->fpsTarget, 1); } mCoreSyncLockAudio(audioContext->sync); } blip_set_rates(left, clockRate, audioContext->obtainedSpec.freq * fauxClock); blip_set_rates(right, clockRate, audioContext->obtainedSpec.freq * fauxClock); len /= 2 * audioContext->obtainedSpec.channels; int available = blip_samples_avail(left); if (available > len) { available = len; } blip_read_samples(left, (short*) data, available, audioContext->obtainedSpec.channels == 2); if (audioContext->obtainedSpec.channels == 2) { blip_read_samples(right, ((short*) data) + 1, available, 1); } if (audioContext->sync) { mCoreSyncConsumeAudio(audioContext->sync); } if (available < len) { memset(((short*) data) + audioContext->obtainedSpec.channels * available, 0, (len - available) * audioContext->obtainedSpec.channels * sizeof(short)); } }
static void _setup(struct GBAGUIRunner* runner) { struct GBAOptions opts = { .useBios = true, .logLevel = 0, .idleOptimization = IDLE_LOOP_DETECT }; GBAConfigLoadDefaults(&runner->context.config, &opts); runner->context.gba->logHandler = GBA3DSLog; runner->context.gba->rotationSource = &rotation.d; if (hasSound) { runner->context.gba->stream = &stream; } GBAVideoSoftwareRendererCreate(&renderer); renderer.outputBuffer = linearAlloc(256 * VIDEO_VERTICAL_PIXELS * 2); renderer.outputBufferStride = 256; runner->context.renderer = &renderer.d; GBAAudioResizeBuffer(&runner->context.gba->audio, AUDIO_SAMPLES); } static void _gameLoaded(struct GBAGUIRunner* runner) { if (runner->context.gba->memory.hw.devices & HW_TILT) { HIDUSER_EnableAccelerometer(); } if (runner->context.gba->memory.hw.devices & HW_GYRO) { HIDUSER_EnableGyroscope(); } #if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF double ratio = GBAAudioCalculateRatio(1, 60, 1); blip_set_rates(runner->context.gba->audio.left, GBA_ARM7TDMI_FREQUENCY, 0x8000 * ratio); blip_set_rates(runner->context.gba->audio.right, GBA_ARM7TDMI_FREQUENCY, 0x8000 * ratio); #endif if (hasSound) { memset(audioLeft, 0, AUDIO_SAMPLES * sizeof(int16_t)); memset(audioRight, 0, AUDIO_SAMPLES * sizeof(int16_t)); } } static void _gameUnloaded(struct GBAGUIRunner* runner) { if (hasSound) { CSND_SetPlayState(8, 0); CSND_SetPlayState(9, 0); csndExecCmds(false); } if (runner->context.gba->memory.hw.devices & HW_TILT) { HIDUSER_DisableAccelerometer(); } if (runner->context.gba->memory.hw.devices & HW_GYRO) { HIDUSER_DisableGyroscope(); } } static void _drawFrame(struct GBAGUIRunner* runner, bool faded) { GX_SetDisplayTransfer(0, renderer.outputBuffer, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), tex->data, GX_BUFFER_DIM(256, VIDEO_VERTICAL_PIXELS), 0x000002202); GSPGPU_FlushDataCache(0, tex->data, 256 * VIDEO_VERTICAL_PIXELS * 2); #if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF if (!hasSound) { blip_clear(runner->context.gba->audio.left); blip_clear(runner->context.gba->audio.right); } #endif gspWaitForPPF(); _drawStart(); sf2d_draw_texture_scale_blend(tex, 40, 296, 1, -1, 0xFFFFFF3F | (faded ? 0 : 0xC0)); _drawEnd(); }