summaryrefslogtreecommitdiff
path: root/Source/Core/AudioCommon
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core/AudioCommon')
-rw-r--r--Source/Core/AudioCommon/CubebStream.cpp74
-rw-r--r--Source/Core/AudioCommon/CubebStream.h13
-rw-r--r--Source/Core/AudioCommon/Mixer.cpp19
-rw-r--r--Source/Core/AudioCommon/Mixer.h6
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;
};