mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-29 03:32:54 +00:00
8ea6bef98f
While trying to work on adding audiodump support for CLI, I was alerted that it was important to first try moving the DSP configs to the new config before continuing, as that makes it substantially easier to write clean code to add such a feature. This commit aims to allow for Dolphin to only rely on the new config for DSP-related settings.
252 lines
7.0 KiB
C++
252 lines
7.0 KiB
C++
// Copyright 2009 Dolphin Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include "AudioCommon/AudioCommon.h"
|
|
#include "AudioCommon/AlsaSoundStream.h"
|
|
#include "AudioCommon/CubebStream.h"
|
|
#include "AudioCommon/Mixer.h"
|
|
#include "AudioCommon/NullSoundStream.h"
|
|
#include "AudioCommon/OpenALStream.h"
|
|
#include "AudioCommon/OpenSLESStream.h"
|
|
#include "AudioCommon/PulseAudioStream.h"
|
|
#include "AudioCommon/WASAPIStream.h"
|
|
#include "Common/Common.h"
|
|
#include "Common/FileUtil.h"
|
|
#include "Common/Logging/Log.h"
|
|
#include "Core/Config/MainSettings.h"
|
|
#include "Core/ConfigManager.h"
|
|
|
|
// This shouldn't be a global, at least not here.
|
|
std::unique_ptr<SoundStream> g_sound_stream;
|
|
|
|
namespace AudioCommon
|
|
{
|
|
static bool s_audio_dump_start = false;
|
|
static bool s_sound_stream_running = false;
|
|
|
|
constexpr int AUDIO_VOLUME_MIN = 0;
|
|
constexpr int AUDIO_VOLUME_MAX = 100;
|
|
|
|
static std::unique_ptr<SoundStream> CreateSoundStreamForBackend(std::string_view backend)
|
|
{
|
|
if (backend == BACKEND_CUBEB)
|
|
return std::make_unique<CubebStream>();
|
|
else if (backend == BACKEND_OPENAL && OpenALStream::IsValid())
|
|
return std::make_unique<OpenALStream>();
|
|
else if (backend == BACKEND_NULLSOUND)
|
|
return std::make_unique<NullSound>();
|
|
else if (backend == BACKEND_ALSA && AlsaSound::IsValid())
|
|
return std::make_unique<AlsaSound>();
|
|
else if (backend == BACKEND_PULSEAUDIO && PulseAudio::IsValid())
|
|
return std::make_unique<PulseAudio>();
|
|
else if (backend == BACKEND_OPENSLES && OpenSLESStream::IsValid())
|
|
return std::make_unique<OpenSLESStream>();
|
|
else if (backend == BACKEND_WASAPI && WASAPIStream::IsValid())
|
|
return std::make_unique<WASAPIStream>();
|
|
return {};
|
|
}
|
|
|
|
void InitSoundStream()
|
|
{
|
|
std::string backend = Config::Get(Config::MAIN_AUDIO_BACKEND);
|
|
g_sound_stream = CreateSoundStreamForBackend(backend);
|
|
|
|
if (!g_sound_stream)
|
|
{
|
|
WARN_LOG_FMT(AUDIO, "Unknown backend {}, using {} instead.", backend, GetDefaultSoundBackend());
|
|
backend = GetDefaultSoundBackend();
|
|
g_sound_stream = CreateSoundStreamForBackend(GetDefaultSoundBackend());
|
|
}
|
|
|
|
if (!g_sound_stream || !g_sound_stream->Init())
|
|
{
|
|
WARN_LOG_FMT(AUDIO, "Could not initialize backend {}, using {} instead.", backend,
|
|
BACKEND_NULLSOUND);
|
|
g_sound_stream = std::make_unique<NullSound>();
|
|
g_sound_stream->Init();
|
|
}
|
|
}
|
|
|
|
void PostInitSoundStream()
|
|
{
|
|
// This needs to be called after AudioInterface::Init and SerialInterface::Init (for GBA devices)
|
|
// where input sample rates are set
|
|
UpdateSoundStream();
|
|
SetSoundStreamRunning(true);
|
|
|
|
if (Config::Get(Config::MAIN_DUMP_AUDIO) && !s_audio_dump_start)
|
|
StartAudioDump();
|
|
}
|
|
|
|
void ShutdownSoundStream()
|
|
{
|
|
INFO_LOG_FMT(AUDIO, "Shutting down sound stream");
|
|
|
|
if (Config::Get(Config::MAIN_DUMP_AUDIO) && s_audio_dump_start)
|
|
StopAudioDump();
|
|
|
|
SetSoundStreamRunning(false);
|
|
g_sound_stream.reset();
|
|
|
|
INFO_LOG_FMT(AUDIO, "Done shutting down sound stream");
|
|
}
|
|
|
|
std::string GetDefaultSoundBackend()
|
|
{
|
|
std::string backend = BACKEND_NULLSOUND;
|
|
#if defined ANDROID
|
|
backend = BACKEND_OPENSLES;
|
|
#elif defined __linux__
|
|
if (AlsaSound::IsValid())
|
|
backend = BACKEND_ALSA;
|
|
#elif defined(__APPLE__) || defined(_WIN32)
|
|
backend = BACKEND_CUBEB;
|
|
#endif
|
|
return backend;
|
|
}
|
|
|
|
DPL2Quality GetDefaultDPL2Quality()
|
|
{
|
|
return DPL2Quality::High;
|
|
}
|
|
|
|
std::vector<std::string> GetSoundBackends()
|
|
{
|
|
std::vector<std::string> backends;
|
|
|
|
backends.emplace_back(BACKEND_NULLSOUND);
|
|
backends.emplace_back(BACKEND_CUBEB);
|
|
if (AlsaSound::IsValid())
|
|
backends.emplace_back(BACKEND_ALSA);
|
|
if (PulseAudio::IsValid())
|
|
backends.emplace_back(BACKEND_PULSEAUDIO);
|
|
if (OpenALStream::IsValid())
|
|
backends.emplace_back(BACKEND_OPENAL);
|
|
if (OpenSLESStream::IsValid())
|
|
backends.emplace_back(BACKEND_OPENSLES);
|
|
if (WASAPIStream::IsValid())
|
|
backends.emplace_back(BACKEND_WASAPI);
|
|
|
|
return backends;
|
|
}
|
|
|
|
bool SupportsDPL2Decoder(std::string_view backend)
|
|
{
|
|
#ifndef __APPLE__
|
|
if (backend == BACKEND_OPENAL)
|
|
return true;
|
|
#endif
|
|
if (backend == BACKEND_CUBEB)
|
|
return true;
|
|
if (backend == BACKEND_PULSEAUDIO)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool SupportsLatencyControl(std::string_view backend)
|
|
{
|
|
return backend == BACKEND_OPENAL || backend == BACKEND_WASAPI;
|
|
}
|
|
|
|
bool SupportsVolumeChanges(std::string_view backend)
|
|
{
|
|
// FIXME: this one should ask the backend whether it supports it.
|
|
// but getting the backend from string etc. is probably
|
|
// too much just to enable/disable a stupid slider...
|
|
return backend == BACKEND_CUBEB || backend == BACKEND_OPENAL || backend == BACKEND_WASAPI;
|
|
}
|
|
|
|
void UpdateSoundStream()
|
|
{
|
|
if (g_sound_stream)
|
|
{
|
|
int volume = Config::Get(Config::MAIN_AUDIO_MUTED) ? 0 : Config::Get(Config::MAIN_AUDIO_VOLUME);
|
|
g_sound_stream->SetVolume(volume);
|
|
}
|
|
}
|
|
|
|
void SetSoundStreamRunning(bool running)
|
|
{
|
|
if (!g_sound_stream)
|
|
return;
|
|
|
|
if (s_sound_stream_running == running)
|
|
return;
|
|
s_sound_stream_running = running;
|
|
|
|
if (g_sound_stream->SetRunning(running))
|
|
return;
|
|
if (running)
|
|
ERROR_LOG_FMT(AUDIO, "Error starting stream.");
|
|
else
|
|
ERROR_LOG_FMT(AUDIO, "Error stopping stream.");
|
|
}
|
|
|
|
void SendAIBuffer(const short* samples, unsigned int num_samples)
|
|
{
|
|
if (!g_sound_stream)
|
|
return;
|
|
|
|
if (Config::Get(Config::MAIN_DUMP_AUDIO) && !s_audio_dump_start)
|
|
StartAudioDump();
|
|
else if (!Config::Get(Config::MAIN_DUMP_AUDIO) && s_audio_dump_start)
|
|
StopAudioDump();
|
|
|
|
Mixer* pMixer = g_sound_stream->GetMixer();
|
|
|
|
if (pMixer && samples)
|
|
{
|
|
pMixer->PushSamples(samples, num_samples);
|
|
}
|
|
}
|
|
|
|
void StartAudioDump()
|
|
{
|
|
std::string audio_file_name_dtk = File::GetUserPath(D_DUMPAUDIO_IDX) + "dtkdump.wav";
|
|
std::string audio_file_name_dsp = File::GetUserPath(D_DUMPAUDIO_IDX) + "dspdump.wav";
|
|
File::CreateFullPath(audio_file_name_dtk);
|
|
File::CreateFullPath(audio_file_name_dsp);
|
|
g_sound_stream->GetMixer()->StartLogDTKAudio(audio_file_name_dtk);
|
|
g_sound_stream->GetMixer()->StartLogDSPAudio(audio_file_name_dsp);
|
|
s_audio_dump_start = true;
|
|
}
|
|
|
|
void StopAudioDump()
|
|
{
|
|
if (!g_sound_stream)
|
|
return;
|
|
g_sound_stream->GetMixer()->StopLogDTKAudio();
|
|
g_sound_stream->GetMixer()->StopLogDSPAudio();
|
|
s_audio_dump_start = false;
|
|
}
|
|
|
|
void IncreaseVolume(unsigned short offset)
|
|
{
|
|
Config::SetBaseOrCurrent(Config::MAIN_AUDIO_MUTED, false);
|
|
int currentVolume = Config::Get(Config::MAIN_AUDIO_VOLUME);
|
|
currentVolume += offset;
|
|
if (currentVolume > AUDIO_VOLUME_MAX)
|
|
currentVolume = AUDIO_VOLUME_MAX;
|
|
Config::SetBaseOrCurrent(Config::MAIN_AUDIO_VOLUME, currentVolume);
|
|
UpdateSoundStream();
|
|
}
|
|
|
|
void DecreaseVolume(unsigned short offset)
|
|
{
|
|
Config::SetBaseOrCurrent(Config::MAIN_AUDIO_MUTED, false);
|
|
int currentVolume = Config::Get(Config::MAIN_AUDIO_VOLUME);
|
|
currentVolume -= offset;
|
|
if (currentVolume < AUDIO_VOLUME_MIN)
|
|
currentVolume = AUDIO_VOLUME_MIN;
|
|
Config::SetBaseOrCurrent(Config::MAIN_AUDIO_VOLUME, currentVolume);
|
|
UpdateSoundStream();
|
|
}
|
|
|
|
void ToggleMuteVolume()
|
|
{
|
|
bool isMuted = Config::Get(Config::MAIN_AUDIO_MUTED);
|
|
Config::SetBaseOrCurrent(Config::MAIN_AUDIO_MUTED, !isMuted);
|
|
UpdateSoundStream();
|
|
}
|
|
} // namespace AudioCommon
|