diff options
Diffstat (limited to 'Source/Core/AudioCommon')
| -rw-r--r-- | Source/Core/AudioCommon/CubebStream.cpp | 74 | ||||
| -rw-r--r-- | Source/Core/AudioCommon/CubebStream.h | 13 | ||||
| -rw-r--r-- | Source/Core/AudioCommon/Mixer.cpp | 19 | ||||
| -rw-r--r-- | Source/Core/AudioCommon/Mixer.h | 6 |
4 files changed, 109 insertions, 3 deletions
diff --git a/Source/Core/AudioCommon/CubebStream.cpp b/Source/Core/AudioCommon/CubebStream.cpp index 0cdf7f3b99..47f334d537 100644 --- a/Source/Core/AudioCommon/CubebStream.cpp +++ b/Source/Core/AudioCommon/CubebStream.cpp @@ -49,6 +49,19 @@ void CubebStream::WiimoteStateCallback(cubeb_stream* stream, void* user_data, cu { } +long CubebStream::GBADataCallback(cubeb_stream* stream, void* user_data, + const void* /*input_buffer*/, void* output_buffer, + long num_frames) +{ + const auto* data = static_cast<const GBAStreamData*>(user_data); + data->self->m_mixer->MixGBA(data->gba_index, static_cast<short*>(output_buffer), num_frames); + return num_frames; +} + +void CubebStream::GBAStateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) +{ +} + CubebStream::CubebStream() #ifdef _WIN32 : m_work_queue("Cubeb Worker") @@ -145,6 +158,48 @@ bool CubebStream::Init() } } } + + // Create per-GBA streams for audio routing when enabled + if (return_value && Config::Get(Config::MAIN_GBA_AUDIO_ROUTING_ENABLED)) + { + static const char* const GBA_STREAM_NAMES[4] = { + "Dolphin GBA 1 Audio", "Dolphin GBA 2 Audio", "Dolphin GBA 3 Audio", + "Dolphin GBA 4 Audio"}; + + cubeb_stream_params gba_params{}; + gba_params.rate = m_mixer->GetSampleRate(); + gba_params.channels = 2; + gba_params.format = CUBEB_SAMPLE_S16NE; + gba_params.layout = CUBEB_LAYOUT_STEREO; + + for (std::size_t i = 0; i < m_gba_streams.size(); ++i) + { + if (!Config::Get(Config::MAIN_GBA_AUDIO_OUTPUT_ENABLED[i])) + continue; + + const std::string device_id_str = Config::Get(Config::MAIN_GBA_AUDIO_OUTPUT_DEVICE[i]); + const cubeb_devid output_devid = + device_id_str.empty() ? + nullptr : + static_cast<cubeb_devid>(CubebUtils::GetOutputDeviceById(device_id_str)); + + u32 gba_min_latency = 0; + cubeb_get_min_latency(m_ctx.get(), &gba_params, &gba_min_latency); + + m_gba_stream_data[i] = {this, i}; + + const int result = cubeb_stream_init( + m_ctx.get(), &m_gba_streams[i], GBA_STREAM_NAMES[i], nullptr, nullptr, output_devid, + &gba_params, std::max(BUFFER_SAMPLES, gba_min_latency), GBADataCallback, + GBAStateCallback, &m_gba_stream_data[i]); + + if (result != CUBEB_OK) + { + ERROR_LOG_FMT(AUDIO, "Failed to create Cubeb stream for GBA {} audio split", i + 1); + m_gba_streams[i] = nullptr; + } + } + } } #ifdef _WIN32 @@ -171,6 +226,11 @@ bool CubebStream::SetRunning(bool running) if (ws) cubeb_stream_start(ws); } + for (auto& gs : m_gba_streams) + { + if (gs) + cubeb_stream_start(gs); + } } else { @@ -180,6 +240,11 @@ bool CubebStream::SetRunning(bool running) if (ws) cubeb_stream_stop(ws); } + for (auto& gs : m_gba_streams) + { + if (gs) + cubeb_stream_stop(gs); + } } #ifdef _WIN32 }); @@ -204,6 +269,15 @@ CubebStream::~CubebStream() ws = nullptr; } } + for (auto& gs : m_gba_streams) + { + if (gs) + { + cubeb_stream_stop(gs); + cubeb_stream_destroy(gs); + gs = nullptr; + } + } #ifdef _WIN32 if (m_should_couninit) { diff --git a/Source/Core/AudioCommon/CubebStream.h b/Source/Core/AudioCommon/CubebStream.h index 1c95fd50d8..4bc0070e88 100644 --- a/Source/Core/AudioCommon/CubebStream.h +++ b/Source/Core/AudioCommon/CubebStream.h @@ -16,6 +16,8 @@ #include <cubeb/cubeb.h> #endif +#include "Core/Config/MainSettings.h" + class CubebStream final : public SoundStream { #ifdef HAVE_CUBEB @@ -38,11 +40,19 @@ private: std::size_t wiimote_index; }; + struct GBAStreamData + { + CubebStream* self; + std::size_t gba_index; + }; + bool m_stereo = false; std::shared_ptr<cubeb> m_ctx; cubeb_stream* m_stream = nullptr; std::array<WiimoteStreamData, 4> m_wiimote_stream_data{}; std::array<cubeb_stream*, 4> m_wiimote_streams{}; + std::array<GBAStreamData, Config::GBA_SPEAKER_COUNT> m_gba_stream_data{}; + std::array<cubeb_stream*, Config::GBA_SPEAKER_COUNT> m_gba_streams{}; std::vector<short> m_short_buffer; std::vector<float> m_floatstereo_buffer; @@ -60,5 +70,8 @@ private: const void* /*input_buffer*/, void* output_buffer, long num_frames); static void WiimoteStateCallback(cubeb_stream* stream, void* user_data, cubeb_state state); + static long GBADataCallback(cubeb_stream* stream, void* user_data, const void* /*input_buffer*/, + void* output_buffer, long num_frames); + static void GBAStateCallback(cubeb_stream* stream, void* user_data, cubeb_state state); #endif }; diff --git a/Source/Core/AudioCommon/Mixer.cpp b/Source/Core/AudioCommon/Mixer.cpp index a57b6024b7..fe7f0e7349 100644 --- a/Source/Core/AudioCommon/Mixer.cpp +++ b/Source/Core/AudioCommon/Mixer.cpp @@ -176,8 +176,11 @@ std::size_t Mixer::Mix(s16* samples, std::size_t num_samples) m_wiimote_speaker_mixers[i].Mix(samples, num_samples); } m_skylander_portal_mixer.Mix(samples, num_samples); - for (auto& mixer : m_gba_mixers) - mixer.Mix(samples, num_samples); + for (std::size_t i = 0; i < m_gba_mixers.size(); ++i) + { + if (!m_config_gba_routing_enabled || !m_config_gba_output_enabled[i]) + m_gba_mixers[i].Mix(samples, num_samples); + } return num_samples; } @@ -317,6 +320,15 @@ void Mixer::PushGBASamples(std::size_t device_number, const s16* samples, std::s } } +std::size_t Mixer::MixGBA(std::size_t device_number, s16* samples, std::size_t num_samples) +{ + if (!samples || device_number >= m_gba_mixers.size()) + return 0; + memset(samples, 0, num_samples * 2 * sizeof(s16)); + m_gba_mixers[device_number].Mix(samples, num_samples); + return num_samples; +} + void Mixer::SetDMAInputSampleRateDivisor(u32 rate_divisor) { m_dma_mixer.SetInputSampleRateDivisor(rate_divisor); @@ -433,6 +445,9 @@ void Mixer::RefreshConfig() m_config_wiimote_routing_enabled = Config::Get(Config::MAIN_WIIMOTE_AUDIO_ROUTING_ENABLED); for (std::size_t i = 0; i < m_config_wiimote_output_enabled.size(); ++i) m_config_wiimote_output_enabled[i] = Config::Get(Config::MAIN_WIIMOTE_AUDIO_OUTPUT_ENABLED[i]); + m_config_gba_routing_enabled = Config::Get(Config::MAIN_GBA_AUDIO_ROUTING_ENABLED); + for (std::size_t i = 0; i < m_config_gba_output_enabled.size(); ++i) + m_config_gba_output_enabled[i] = Config::Get(Config::MAIN_GBA_AUDIO_OUTPUT_ENABLED[i]); } void Mixer::MixerFifo::DoState(PointerWrap& p) diff --git a/Source/Core/AudioCommon/Mixer.h b/Source/Core/AudioCommon/Mixer.h index aca334bcf8..26e179f03b 100644 --- a/Source/Core/AudioCommon/Mixer.h +++ b/Source/Core/AudioCommon/Mixer.h @@ -12,6 +12,7 @@ #include "Common/CommonTypes.h" #include "Common/Config/Config.h" #include "Common/Inline.h" +#include "Core/Config/MainSettings.h" class PointerWrap; @@ -49,6 +50,7 @@ public: void SetWiimoteSpeakerVolume(std::size_t wiimote_index, u32 lvolume, u32 rvolume); std::size_t MixWiimoteSpeaker(std::size_t wiimote_index, s16* samples, std::size_t num_samples); void SetGBAVolume(std::size_t device_number, u32 lvolume, u32 rvolume); + std::size_t MixGBA(std::size_t device_number, s16* samples, std::size_t num_samples); void StartLogDTKAudio(const std::string& filename); void StopLogDTKAudio(); @@ -178,7 +180,7 @@ private: // GBAs generally use a 65536 sample rate which is not a factor of our FIXED_SAMPLE_RATE_DIVIDEND. static constexpr u32 GBA_SAMPLE_RATE_DIVIDEND = 0x1000000; - std::array<MixerFifo, 4> m_gba_mixers{ + std::array<MixerFifo, Config::GBA_SPEAKER_COUNT> m_gba_mixers{ MixerFifo{this, GBA_SAMPLE_RATE_DIVIDEND / 65536, GBA_SAMPLE_RATE_DIVIDEND}, MixerFifo{this, GBA_SAMPLE_RATE_DIVIDEND / 65536, GBA_SAMPLE_RATE_DIVIDEND}, MixerFifo{this, GBA_SAMPLE_RATE_DIVIDEND / 65536, GBA_SAMPLE_RATE_DIVIDEND}, @@ -200,6 +202,8 @@ private: int m_config_audio_buffer_ms; bool m_config_wiimote_routing_enabled = false; std::array<bool, 4> m_config_wiimote_output_enabled{}; + bool m_config_gba_routing_enabled = false; + std::array<bool, Config::GBA_SPEAKER_COUNT> m_config_gba_output_enabled{}; Config::ConfigChangedCallbackID m_config_changed_callback_id; }; |
