summaryrefslogtreecommitdiffstats
path: root/src/audio_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio_core')
-rw-r--r--src/audio_core/algorithm/interpolate.cpp5
-rw-r--r--src/audio_core/audio_out.cpp6
-rw-r--r--src/audio_core/audio_renderer.cpp17
-rw-r--r--src/audio_core/audio_renderer.h7
-rw-r--r--src/audio_core/cubeb_sink.cpp2
-rw-r--r--src/audio_core/cubeb_sink.h2
-rw-r--r--src/audio_core/null_sink.h2
-rw-r--r--src/audio_core/sink_details.cpp53
-rw-r--r--src/audio_core/sink_details.h25
-rw-r--r--src/audio_core/stream.cpp9
-rw-r--r--src/audio_core/time_stretch.cpp4
11 files changed, 78 insertions, 54 deletions
diff --git a/src/audio_core/algorithm/interpolate.cpp b/src/audio_core/algorithm/interpolate.cpp
index 3aea9b0f2..5005ba519 100644
--- a/src/audio_core/algorithm/interpolate.cpp
+++ b/src/audio_core/algorithm/interpolate.cpp
@@ -54,8 +54,9 @@ std::vector<s16> Interpolate(InterpolationState& state, std::vector<s16> input,
double l = 0.0;
double r = 0.0;
for (std::size_t j = 0; j < h.size(); j++) {
- l += Lanczos(taps, pos + j - taps + 1) * h[j][0];
- r += Lanczos(taps, pos + j - taps + 1) * h[j][1];
+ const double lanczos_calc = Lanczos(taps, pos + j - taps + 1);
+ l += lanczos_calc * h[j][0];
+ r += lanczos_calc * h[j][1];
}
output.emplace_back(static_cast<s16>(std::clamp(l, -32768.0, 32767.0)));
output.emplace_back(static_cast<s16>(std::clamp(r, -32768.0, 32767.0)));
diff --git a/src/audio_core/audio_out.cpp b/src/audio_core/audio_out.cpp
index 0c8f5b18e..50d2a1ed3 100644
--- a/src/audio_core/audio_out.cpp
+++ b/src/audio_core/audio_out.cpp
@@ -22,16 +22,14 @@ static Stream::Format ChannelsToStreamFormat(u32 num_channels) {
return Stream::Format::Multi51Channel16;
}
- LOG_CRITICAL(Audio, "Unimplemented num_channels={}", num_channels);
- UNREACHABLE();
+ UNIMPLEMENTED_MSG("Unimplemented num_channels={}", num_channels);
return {};
}
StreamPtr AudioOut::OpenStream(u32 sample_rate, u32 num_channels, std::string&& name,
Stream::ReleaseCallback&& release_callback) {
if (!sink) {
- const SinkDetails& sink_details = GetSinkDetails(Settings::values.sink_id);
- sink = sink_details.factory(Settings::values.audio_device_id);
+ sink = CreateSinkFromID(Settings::values.sink_id, Settings::values.audio_device_id);
}
return std::make_shared<Stream>(
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 23e5d3f10..00c026511 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -8,7 +8,7 @@
#include "audio_core/codec.h"
#include "common/assert.h"
#include "common/logging/log.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/memory.h"
namespace AudioCore {
@@ -72,7 +72,7 @@ private:
EffectInStatus info{};
};
AudioRenderer::AudioRenderer(AudioRendererParameter params,
- Kernel::SharedPtr<Kernel::Event> buffer_event)
+ Kernel::SharedPtr<Kernel::WritableEvent> buffer_event)
: worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count),
effects(params.effect_count) {
@@ -260,8 +260,7 @@ void AudioRenderer::VoiceState::RefreshBuffer() {
break;
}
default:
- LOG_CRITICAL(Audio, "Unimplemented sample_format={}", info.sample_format);
- UNREACHABLE();
+ UNIMPLEMENTED_MSG("Unimplemented sample_format={}", info.sample_format);
break;
}
@@ -280,13 +279,15 @@ void AudioRenderer::VoiceState::RefreshBuffer() {
break;
}
default:
- LOG_CRITICAL(Audio, "Unimplemented channel_count={}", info.channel_count);
- UNREACHABLE();
+ UNIMPLEMENTED_MSG("Unimplemented channel_count={}", info.channel_count);
break;
}
- samples =
- Interpolate(interp_state, std::move(samples), GetInfo().sample_rate, STREAM_SAMPLE_RATE);
+ // Only interpolate when necessary, expensive.
+ if (GetInfo().sample_rate != STREAM_SAMPLE_RATE) {
+ samples = Interpolate(interp_state, std::move(samples), GetInfo().sample_rate,
+ STREAM_SAMPLE_RATE);
+ }
is_refresh_pending = false;
}
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index 71ba4be40..7826881bf 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -15,7 +15,7 @@
#include "core/hle/kernel/object.h"
namespace Kernel {
-class Event;
+class WritableEvent;
}
namespace AudioCore {
@@ -208,7 +208,8 @@ static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size
class AudioRenderer {
public:
- AudioRenderer(AudioRendererParameter params, Kernel::SharedPtr<Kernel::Event> buffer_event);
+ AudioRenderer(AudioRendererParameter params,
+ Kernel::SharedPtr<Kernel::WritableEvent> buffer_event);
~AudioRenderer();
std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params);
@@ -224,7 +225,7 @@ private:
class VoiceState;
AudioRendererParameter worker_params;
- Kernel::SharedPtr<Kernel::Event> buffer_event;
+ Kernel::SharedPtr<Kernel::WritableEvent> buffer_event;
std::vector<VoiceState> voices;
std::vector<EffectState> effects;
std::unique_ptr<AudioOut> audio_out;
diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp
index d31a1c844..097328901 100644
--- a/src/audio_core/cubeb_sink.cpp
+++ b/src/audio_core/cubeb_sink.cpp
@@ -107,7 +107,7 @@ private:
static void StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state);
};
-CubebSink::CubebSink(std::string target_device_name) {
+CubebSink::CubebSink(std::string_view target_device_name) {
if (cubeb_init(&ctx, "yuzu", nullptr) != CUBEB_OK) {
LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
return;
diff --git a/src/audio_core/cubeb_sink.h b/src/audio_core/cubeb_sink.h
index 59cbf05e9..efb9d1634 100644
--- a/src/audio_core/cubeb_sink.h
+++ b/src/audio_core/cubeb_sink.h
@@ -15,7 +15,7 @@ namespace AudioCore {
class CubebSink final : public Sink {
public:
- explicit CubebSink(std::string device_id);
+ explicit CubebSink(std::string_view device_id);
~CubebSink() override;
SinkStream& AcquireSinkStream(u32 sample_rate, u32 num_channels,
diff --git a/src/audio_core/null_sink.h b/src/audio_core/null_sink.h
index a78d78893..61a28d542 100644
--- a/src/audio_core/null_sink.h
+++ b/src/audio_core/null_sink.h
@@ -10,7 +10,7 @@ namespace AudioCore {
class NullSink final : public Sink {
public:
- explicit NullSink(std::string){};
+ explicit NullSink(std::string_view) {}
~NullSink() override = default;
SinkStream& AcquireSinkStream(u32 /*sample_rate*/, u32 /*num_channels*/,
diff --git a/src/audio_core/sink_details.cpp b/src/audio_core/sink_details.cpp
index 67cf1f3b2..a848eb1c9 100644
--- a/src/audio_core/sink_details.cpp
+++ b/src/audio_core/sink_details.cpp
@@ -14,31 +14,68 @@
#include "common/logging/log.h"
namespace AudioCore {
+namespace {
+struct SinkDetails {
+ using FactoryFn = std::unique_ptr<Sink> (*)(std::string_view);
+ using ListDevicesFn = std::vector<std::string> (*)();
-// g_sink_details is ordered in terms of desirability, with the best choice at the top.
-const std::vector<SinkDetails> g_sink_details = {
+ /// Name for this sink.
+ const char* id;
+ /// A method to call to construct an instance of this type of sink.
+ FactoryFn factory;
+ /// A method to call to list available devices.
+ ListDevicesFn list_devices;
+};
+
+// sink_details is ordered in terms of desirability, with the best choice at the top.
+constexpr SinkDetails sink_details[] = {
#ifdef HAVE_CUBEB
- SinkDetails{"cubeb", &std::make_unique<CubebSink, std::string>, &ListCubebSinkDevices},
+ SinkDetails{"cubeb",
+ [](std::string_view device_id) -> std::unique_ptr<Sink> {
+ return std::make_unique<CubebSink>(device_id);
+ },
+ &ListCubebSinkDevices},
#endif
- SinkDetails{"null", &std::make_unique<NullSink, std::string>,
+ SinkDetails{"null",
+ [](std::string_view device_id) -> std::unique_ptr<Sink> {
+ return std::make_unique<NullSink>(device_id);
+ },
[] { return std::vector<std::string>{"null"}; }},
};
const SinkDetails& GetSinkDetails(std::string_view sink_id) {
auto iter =
- std::find_if(g_sink_details.begin(), g_sink_details.end(),
+ std::find_if(std::begin(sink_details), std::end(sink_details),
[sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; });
- if (sink_id == "auto" || iter == g_sink_details.end()) {
+ if (sink_id == "auto" || iter == std::end(sink_details)) {
if (sink_id != "auto") {
LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id {}", sink_id);
}
// Auto-select.
- // g_sink_details is ordered in terms of desirability, with the best choice at the front.
- iter = g_sink_details.begin();
+ // sink_details is ordered in terms of desirability, with the best choice at the front.
+ iter = std::begin(sink_details);
}
return *iter;
}
+} // Anonymous namespace
+
+std::vector<const char*> GetSinkIDs() {
+ std::vector<const char*> sink_ids(std::size(sink_details));
+
+ std::transform(std::begin(sink_details), std::end(sink_details), std::begin(sink_ids),
+ [](const auto& sink) { return sink.id; });
+
+ return sink_ids;
+}
+
+std::vector<std::string> GetDeviceListForSink(std::string_view sink_id) {
+ return GetSinkDetails(sink_id).list_devices();
+}
+
+std::unique_ptr<Sink> CreateSinkFromID(std::string_view sink_id, std::string_view device_id) {
+ return GetSinkDetails(sink_id).factory(device_id);
+}
} // namespace AudioCore
diff --git a/src/audio_core/sink_details.h b/src/audio_core/sink_details.h
index 03534b187..bc8786270 100644
--- a/src/audio_core/sink_details.h
+++ b/src/audio_core/sink_details.h
@@ -4,34 +4,21 @@
#pragma once
-#include <functional>
-#include <memory>
#include <string>
#include <string_view>
-#include <utility>
#include <vector>
namespace AudioCore {
class Sink;
-struct SinkDetails {
- using FactoryFn = std::function<std::unique_ptr<Sink>(std::string)>;
- using ListDevicesFn = std::function<std::vector<std::string>()>;
+/// Retrieves the IDs for all available audio sinks.
+std::vector<const char*> GetSinkIDs();
- SinkDetails(const char* id_, FactoryFn factory_, ListDevicesFn list_devices_)
- : id(id_), factory(std::move(factory_)), list_devices(std::move(list_devices_)) {}
+/// Gets the list of devices for a particular sink identified by the given ID.
+std::vector<std::string> GetDeviceListForSink(std::string_view sink_id);
- /// Name for this sink.
- const char* id;
- /// A method to call to construct an instance of this type of sink.
- FactoryFn factory;
- /// A method to call to list available devices.
- ListDevicesFn list_devices;
-};
-
-extern const std::vector<SinkDetails> g_sink_details;
-
-const SinkDetails& GetSinkDetails(std::string_view sink_id);
+/// Creates an audio sink identified by the given device ID.
+std::unique_ptr<Sink> CreateSinkFromID(std::string_view sink_id, std::string_view device_id);
} // namespace AudioCore
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index f35628e45..4ce2d374e 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -28,8 +28,7 @@ u32 Stream::GetNumChannels() const {
case Format::Multi51Channel16:
return 6;
}
- LOG_CRITICAL(Audio, "Unimplemented format={}", static_cast<u32>(format));
- UNREACHABLE();
+ UNIMPLEMENTED_MSG("Unimplemented format={}", static_cast<u32>(format));
return {};
}
@@ -49,7 +48,7 @@ void Stream::Play() {
void Stream::Stop() {
state = State::Stopped;
- ASSERT_MSG(false, "Unimplemented");
+ UNIMPLEMENTED();
}
Stream::State Stream::GetState() const {
@@ -69,7 +68,7 @@ static void VolumeAdjustSamples(std::vector<s16>& samples) {
}
// Implementation of a volume slider with a dynamic range of 60 dB
- const float volume_scale_factor{std::exp(6.90775f * volume) * 0.001f};
+ const float volume_scale_factor = volume == 0 ? 0 : std::exp(6.90775f * volume) * 0.001f;
for (auto& sample : samples) {
sample = static_cast<s16>(sample * volume_scale_factor);
}
@@ -120,7 +119,7 @@ bool Stream::QueueBuffer(BufferPtr&& buffer) {
}
bool Stream::ContainsBuffer(Buffer::Tag tag) const {
- ASSERT_MSG(false, "Unimplemented");
+ UNIMPLEMENTED();
return {};
}
diff --git a/src/audio_core/time_stretch.cpp b/src/audio_core/time_stretch.cpp
index 2fe0b3aef..726591fce 100644
--- a/src/audio_core/time_stretch.cpp
+++ b/src/audio_core/time_stretch.cpp
@@ -53,8 +53,8 @@ std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out,
const double lpf_gain = 1.0 - std::exp(-time_delta / lpf_time_scale);
m_stretch_ratio += lpf_gain * (current_ratio - m_stretch_ratio);
- // Place a lower limit of 5% speed. When a game boots up, there will be
- // many silence samples. These do not need to be timestretched.
+ // Place a lower limit of 5% speed. When a game boots up, there will be
+ // many silence samples. These do not need to be timestretched.
m_stretch_ratio = std::max(m_stretch_ratio, 0.05);
m_sound_touch.setTempo(m_stretch_ratio);