summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/audio_core/audio_out.cpp4
-rw-r--r--src/audio_core/audio_out.h3
-rw-r--r--src/audio_core/audio_renderer.cpp110
-rw-r--r--src/audio_core/audio_renderer.h20
-rw-r--r--src/audio_core/behavior_info.h30
-rw-r--r--src/audio_core/command_generator.h14
-rw-r--r--src/audio_core/common.h2
-rw-r--r--src/audio_core/effect_context.h26
-rw-r--r--src/audio_core/mix_context.h26
-rw-r--r--src/audio_core/sink_context.cpp18
-rw-r--r--src/audio_core/sink_context.h13
-rw-r--r--src/audio_core/stream.cpp9
-rw-r--r--src/audio_core/stream.h21
13 files changed, 194 insertions, 102 deletions
diff --git a/src/audio_core/audio_out.cpp b/src/audio_core/audio_out.cpp
index 8619a3f03..fe3a898ad 100644
--- a/src/audio_core/audio_out.cpp
+++ b/src/audio_core/audio_out.cpp
@@ -43,6 +43,10 @@ std::vector<Buffer::Tag> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream,
43 return stream->GetTagsAndReleaseBuffers(max_count); 43 return stream->GetTagsAndReleaseBuffers(max_count);
44} 44}
45 45
46std::vector<Buffer::Tag> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream) {
47 return stream->GetTagsAndReleaseBuffers();
48}
49
46void AudioOut::StartStream(StreamPtr stream) { 50void AudioOut::StartStream(StreamPtr stream) {
47 stream->Play(); 51 stream->Play();
48} 52}
diff --git a/src/audio_core/audio_out.h b/src/audio_core/audio_out.h
index b07588287..6ce08cd0d 100644
--- a/src/audio_core/audio_out.h
+++ b/src/audio_core/audio_out.h
@@ -31,6 +31,9 @@ public:
31 /// Returns a vector of recently released buffers specified by tag for the specified stream 31 /// Returns a vector of recently released buffers specified by tag for the specified stream
32 std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream, std::size_t max_count); 32 std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream, std::size_t max_count);
33 33
34 /// Returns a vector of all recently released buffers specified by tag for the specified stream
35 std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream);
36
34 /// Starts an audio stream for playback 37 /// Starts an audio stream for playback
35 void StartStream(StreamPtr stream); 38 void StartStream(StreamPtr stream);
36 39
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index a7e851bb8..03a133640 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <limits>
5#include <vector> 6#include <vector>
6 7
7#include "audio_core/audio_out.h" 8#include "audio_core/audio_out.h"
@@ -14,6 +15,59 @@
14#include "core/memory.h" 15#include "core/memory.h"
15#include "core/settings.h" 16#include "core/settings.h"
16 17
18namespace {
19[[nodiscard]] static constexpr s16 ClampToS16(s32 value) {
20 return static_cast<s16>(std::clamp(value, static_cast<s32>(std::numeric_limits<s16>::min()),
21 static_cast<s32>(std::numeric_limits<s16>::max())));
22}
23
24[[nodiscard]] static constexpr s16 Mix2To1(s16 l_channel, s16 r_channel) {
25 // Mix 50% from left and 50% from right channel
26 constexpr float l_mix_amount = 50.0f / 100.0f;
27 constexpr float r_mix_amount = 50.0f / 100.0f;
28 return ClampToS16(static_cast<s32>((static_cast<float>(l_channel) * l_mix_amount) +
29 (static_cast<float>(r_channel) * r_mix_amount)));
30}
31
32[[nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2(s16 fl_channel, s16 fr_channel,
33 s16 fc_channel,
34 [[maybe_unused]] s16 lf_channel,
35 s16 bl_channel, s16 br_channel) {
36 // Front channels are mixed 36.94%, Center channels are mixed to be 26.12% & the back channels
37 // are mixed to be 36.94%
38
39 constexpr float front_mix_amount = 36.94f / 100.0f;
40 constexpr float center_mix_amount = 26.12f / 100.0f;
41 constexpr float back_mix_amount = 36.94f / 100.0f;
42
43 // Mix 50% from left and 50% from right channel
44 const auto left = front_mix_amount * static_cast<float>(fl_channel) +
45 center_mix_amount * static_cast<float>(fc_channel) +
46 back_mix_amount * static_cast<float>(bl_channel);
47
48 const auto right = front_mix_amount * static_cast<float>(fr_channel) +
49 center_mix_amount * static_cast<float>(fc_channel) +
50 back_mix_amount * static_cast<float>(br_channel);
51
52 return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))};
53}
54
55[[nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2WithCoefficients(
56 s16 fl_channel, s16 fr_channel, s16 fc_channel, s16 lf_channel, s16 bl_channel, s16 br_channel,
57 const std::array<float_le, 4>& coeff) {
58 const auto left =
59 static_cast<float>(fl_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] +
60 static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(bl_channel) * coeff[0];
61
62 const auto right =
63 static_cast<float>(fr_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] +
64 static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(br_channel) * coeff[0];
65
66 return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))};
67}
68
69} // namespace
70
17namespace AudioCore { 71namespace AudioCore {
18AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, 72AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
19 AudioCommon::AudioRendererParameter params, 73 AudioCommon::AudioRendererParameter params,
@@ -62,10 +116,6 @@ Stream::State AudioRenderer::GetStreamState() const {
62 return stream->GetState(); 116 return stream->GetState();
63} 117}
64 118
65static constexpr s16 ClampToS16(s32 value) {
66 return static_cast<s16>(std::clamp(value, -32768, 32767));
67}
68
69ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params, 119ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params,
70 std::vector<u8>& output_params) { 120 std::vector<u8>& output_params) {
71 121
@@ -104,8 +154,8 @@ ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_param
104 } 154 }
105 } 155 }
106 156
107 auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count, 157 const auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count,
108 splitter_context, effect_context); 158 splitter_context, effect_context);
109 159
110 if (mix_result.IsError()) { 160 if (mix_result.IsError()) {
111 LOG_ERROR(Audio, "Failed to update mix parameters"); 161 LOG_ERROR(Audio, "Failed to update mix parameters");
@@ -194,20 +244,22 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
194 for (std::size_t i = 0; i < BUFFER_SIZE; i++) { 244 for (std::size_t i = 0; i < BUFFER_SIZE; i++) {
195 if (channel_count == 1) { 245 if (channel_count == 1) {
196 const auto sample = ClampToS16(mix_buffers[0][i]); 246 const auto sample = ClampToS16(mix_buffers[0][i]);
197 buffer[i * stream_channel_count + 0] = sample; 247
198 if (stream_channel_count > 1) { 248 // Place sample in all channels
199 buffer[i * stream_channel_count + 1] = sample; 249 for (u32 channel = 0; channel < stream_channel_count; channel++) {
250 buffer[i * stream_channel_count + channel] = sample;
200 } 251 }
252
201 if (stream_channel_count == 6) { 253 if (stream_channel_count == 6) {
202 buffer[i * stream_channel_count + 2] = sample; 254 // Output stream has a LF channel, mute it!
203 buffer[i * stream_channel_count + 4] = sample; 255 buffer[i * stream_channel_count + 3] = 0;
204 buffer[i * stream_channel_count + 5] = sample;
205 } 256 }
257
206 } else if (channel_count == 2) { 258 } else if (channel_count == 2) {
207 const auto l_sample = ClampToS16(mix_buffers[0][i]); 259 const auto l_sample = ClampToS16(mix_buffers[0][i]);
208 const auto r_sample = ClampToS16(mix_buffers[1][i]); 260 const auto r_sample = ClampToS16(mix_buffers[1][i]);
209 if (stream_channel_count == 1) { 261 if (stream_channel_count == 1) {
210 buffer[i * stream_channel_count + 0] = l_sample; 262 buffer[i * stream_channel_count + 0] = Mix2To1(l_sample, r_sample);
211 } else if (stream_channel_count == 2) { 263 } else if (stream_channel_count == 2) {
212 buffer[i * stream_channel_count + 0] = l_sample; 264 buffer[i * stream_channel_count + 0] = l_sample;
213 buffer[i * stream_channel_count + 1] = r_sample; 265 buffer[i * stream_channel_count + 1] = r_sample;
@@ -215,8 +267,8 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
215 buffer[i * stream_channel_count + 0] = l_sample; 267 buffer[i * stream_channel_count + 0] = l_sample;
216 buffer[i * stream_channel_count + 1] = r_sample; 268 buffer[i * stream_channel_count + 1] = r_sample;
217 269
218 buffer[i * stream_channel_count + 2] = 270 // Combine both left and right channels to the center channel
219 ClampToS16((static_cast<s32>(l_sample) + static_cast<s32>(r_sample)) / 2); 271 buffer[i * stream_channel_count + 2] = Mix2To1(l_sample, r_sample);
220 272
221 buffer[i * stream_channel_count + 4] = l_sample; 273 buffer[i * stream_channel_count + 4] = l_sample;
222 buffer[i * stream_channel_count + 5] = r_sample; 274 buffer[i * stream_channel_count + 5] = r_sample;
@@ -231,17 +283,25 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
231 const auto br_sample = ClampToS16(mix_buffers[5][i]); 283 const auto br_sample = ClampToS16(mix_buffers[5][i]);
232 284
233 if (stream_channel_count == 1) { 285 if (stream_channel_count == 1) {
234 buffer[i * stream_channel_count + 0] = fc_sample; 286 // Games seem to ignore the center channel half the time, we use the front left
287 // and right channel for mixing as that's where majority of the audio goes
288 buffer[i * stream_channel_count + 0] = Mix2To1(fl_sample, fr_sample);
235 } else if (stream_channel_count == 2) { 289 } else if (stream_channel_count == 2) {
236 buffer[i * stream_channel_count + 0] = 290 // Mix all channels into 2 channels
237 static_cast<s16>(0.3694f * static_cast<float>(fl_sample) + 291 if (sink_context.HasDownMixingCoefficients()) {
238 0.2612f * static_cast<float>(fc_sample) + 292 const auto [left, right] = Mix6To2WithCoefficients(
239 0.3694f * static_cast<float>(bl_sample)); 293 fl_sample, fr_sample, fc_sample, lf_sample, bl_sample, br_sample,
240 buffer[i * stream_channel_count + 1] = 294 sink_context.GetDownmixCoefficients());
241 static_cast<s16>(0.3694f * static_cast<float>(fr_sample) + 295 buffer[i * stream_channel_count + 0] = left;
242 0.2612f * static_cast<float>(fc_sample) + 296 buffer[i * stream_channel_count + 1] = right;
243 0.3694f * static_cast<float>(br_sample)); 297 } else {
298 const auto [left, right] = Mix6To2(fl_sample, fr_sample, fc_sample,
299 lf_sample, bl_sample, br_sample);
300 buffer[i * stream_channel_count + 0] = left;
301 buffer[i * stream_channel_count + 1] = right;
302 }
244 } else if (stream_channel_count == 6) { 303 } else if (stream_channel_count == 6) {
304 // Pass through
245 buffer[i * stream_channel_count + 0] = fl_sample; 305 buffer[i * stream_channel_count + 0] = fl_sample;
246 buffer[i * stream_channel_count + 1] = fr_sample; 306 buffer[i * stream_channel_count + 1] = fr_sample;
247 buffer[i * stream_channel_count + 2] = fc_sample; 307 buffer[i * stream_channel_count + 2] = fc_sample;
@@ -259,7 +319,7 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
259} 319}
260 320
261void AudioRenderer::ReleaseAndQueueBuffers() { 321void AudioRenderer::ReleaseAndQueueBuffers() {
262 const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream, 2)}; 322 const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream)};
263 for (const auto& tag : released_buffers) { 323 for (const auto& tag : released_buffers) {
264 QueueMixedBuffer(tag); 324 QueueMixedBuffer(tag);
265 } 325 }
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index 2fd93e058..a85219045 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -36,16 +36,10 @@ class Memory;
36} 36}
37 37
38namespace AudioCore { 38namespace AudioCore {
39using DSPStateHolder = std::array<VoiceState*, 6>; 39using DSPStateHolder = std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>;
40 40
41class AudioOut; 41class AudioOut;
42 42
43struct RendererInfo {
44 u64_le elasped_frame_count{};
45 INSERT_PADDING_WORDS(2);
46};
47static_assert(sizeof(RendererInfo) == 0x10, "RendererInfo is an invalid size");
48
49class AudioRenderer { 43class AudioRenderer {
50public: 44public:
51 AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, 45 AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
@@ -53,14 +47,14 @@ public:
53 std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number); 47 std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number);
54 ~AudioRenderer(); 48 ~AudioRenderer();
55 49
56 ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params, 50 [[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params,
57 std::vector<u8>& output_params); 51 std::vector<u8>& output_params);
58 void QueueMixedBuffer(Buffer::Tag tag); 52 void QueueMixedBuffer(Buffer::Tag tag);
59 void ReleaseAndQueueBuffers(); 53 void ReleaseAndQueueBuffers();
60 u32 GetSampleRate() const; 54 [[nodiscard]] u32 GetSampleRate() const;
61 u32 GetSampleCount() const; 55 [[nodiscard]] u32 GetSampleCount() const;
62 u32 GetMixBufferCount() const; 56 [[nodiscard]] u32 GetMixBufferCount() const;
63 Stream::State GetStreamState() const; 57 [[nodiscard]] Stream::State GetStreamState() const;
64 58
65private: 59private:
66 BehaviorInfo behavior_info{}; 60 BehaviorInfo behavior_info{};
diff --git a/src/audio_core/behavior_info.h b/src/audio_core/behavior_info.h
index 512a4ebe3..5a96bf75e 100644
--- a/src/audio_core/behavior_info.h
+++ b/src/audio_core/behavior_info.h
@@ -43,22 +43,22 @@ public:
43 void ClearError(); 43 void ClearError();
44 void UpdateFlags(u64_le dest_flags); 44 void UpdateFlags(u64_le dest_flags);
45 void SetUserRevision(u32_le revision); 45 void SetUserRevision(u32_le revision);
46 u32_le GetUserRevision() const; 46 [[nodiscard]] u32_le GetUserRevision() const;
47 u32_le GetProcessRevision() const; 47 [[nodiscard]] u32_le GetProcessRevision() const;
48 48
49 bool IsAdpcmLoopContextBugFixed() const; 49 [[nodiscard]] bool IsAdpcmLoopContextBugFixed() const;
50 bool IsSplitterSupported() const; 50 [[nodiscard]] bool IsSplitterSupported() const;
51 bool IsLongSizePreDelaySupported() const; 51 [[nodiscard]] bool IsLongSizePreDelaySupported() const;
52 bool IsAudioRendererProcessingTimeLimit80PercentSupported() const; 52 [[nodiscard]] bool IsAudioRendererProcessingTimeLimit80PercentSupported() const;
53 bool IsAudioRendererProcessingTimeLimit75PercentSupported() const; 53 [[nodiscard]] bool IsAudioRendererProcessingTimeLimit75PercentSupported() const;
54 bool IsAudioRendererProcessingTimeLimit70PercentSupported() const; 54 [[nodiscard]] bool IsAudioRendererProcessingTimeLimit70PercentSupported() const;
55 bool IsElapsedFrameCountSupported() const; 55 [[nodiscard]] bool IsElapsedFrameCountSupported() const;
56 bool IsMemoryPoolForceMappingEnabled() const; 56 [[nodiscard]] bool IsMemoryPoolForceMappingEnabled() const;
57 bool IsFlushVoiceWaveBuffersSupported() const; 57 [[nodiscard]] bool IsFlushVoiceWaveBuffersSupported() const;
58 bool IsVoicePlayedSampleCountResetAtLoopPointSupported() const; 58 [[nodiscard]] bool IsVoicePlayedSampleCountResetAtLoopPointSupported() const;
59 bool IsVoicePitchAndSrcSkippedSupported() const; 59 [[nodiscard]] bool IsVoicePitchAndSrcSkippedSupported() const;
60 bool IsMixInParameterDirtyOnlyUpdateSupported() const; 60 [[nodiscard]] bool IsMixInParameterDirtyOnlyUpdateSupported() const;
61 bool IsSplitterBugFixed() const; 61 [[nodiscard]] bool IsSplitterBugFixed() const;
62 void CopyErrorInfo(OutParams& dst); 62 void CopyErrorInfo(OutParams& dst);
63 63
64private: 64private:
diff --git a/src/audio_core/command_generator.h b/src/audio_core/command_generator.h
index 53e57748b..87ece00c4 100644
--- a/src/audio_core/command_generator.h
+++ b/src/audio_core/command_generator.h
@@ -39,13 +39,13 @@ public:
39 void PreCommand(); 39 void PreCommand();
40 void PostCommand(); 40 void PostCommand();
41 41
42 s32* GetChannelMixBuffer(s32 channel); 42 [[nodiscard]] s32* GetChannelMixBuffer(s32 channel);
43 const s32* GetChannelMixBuffer(s32 channel) const; 43 [[nodiscard]] const s32* GetChannelMixBuffer(s32 channel) const;
44 s32* GetMixBuffer(std::size_t index); 44 [[nodiscard]] s32* GetMixBuffer(std::size_t index);
45 const s32* GetMixBuffer(std::size_t index) const; 45 [[nodiscard]] const s32* GetMixBuffer(std::size_t index) const;
46 std::size_t GetMixChannelBufferOffset(s32 channel) const; 46 [[nodiscard]] std::size_t GetMixChannelBufferOffset(s32 channel) const;
47 47
48 std::size_t GetTotalMixBufferCount() const; 48 [[nodiscard]] std::size_t GetTotalMixBufferCount() const;
49 49
50private: 50private:
51 void GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 channel); 51 void GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 channel);
@@ -73,7 +73,7 @@ private:
73 void GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); 73 void GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled);
74 void GenerateBiquadFilterEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); 74 void GenerateBiquadFilterEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled);
75 void GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); 75 void GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled);
76 ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index); 76 [[nodiscard]] ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index);
77 77
78 s32 WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples, const s32* data, 78 s32 WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples, const s32* data,
79 u32 sample_count, u32 write_offset, u32 write_count); 79 u32 sample_count, u32 write_offset, u32 write_count);
diff --git a/src/audio_core/common.h b/src/audio_core/common.h
index 7b4a1e9e8..ec59a3ba9 100644
--- a/src/audio_core/common.h
+++ b/src/audio_core/common.h
@@ -22,7 +22,7 @@ constexpr std::size_t MAX_CHANNEL_COUNT = 6;
22constexpr std::size_t MAX_WAVE_BUFFERS = 4; 22constexpr std::size_t MAX_WAVE_BUFFERS = 4;
23constexpr std::size_t MAX_SAMPLE_HISTORY = 4; 23constexpr std::size_t MAX_SAMPLE_HISTORY = 4;
24constexpr u32 STREAM_SAMPLE_RATE = 48000; 24constexpr u32 STREAM_SAMPLE_RATE = 48000;
25constexpr u32 STREAM_NUM_CHANNELS = 6; 25constexpr u32 STREAM_NUM_CHANNELS = 2;
26constexpr s32 NO_SPLITTER = -1; 26constexpr s32 NO_SPLITTER = -1;
27constexpr s32 NO_MIX = 0x7fffffff; 27constexpr s32 NO_MIX = 0x7fffffff;
28constexpr s32 NO_FINAL_MIX = std::numeric_limits<s32>::min(); 28constexpr s32 NO_FINAL_MIX = std::numeric_limits<s32>::min();
diff --git a/src/audio_core/effect_context.h b/src/audio_core/effect_context.h
index 2c4ce53ef..03c5a0f04 100644
--- a/src/audio_core/effect_context.h
+++ b/src/audio_core/effect_context.h
@@ -189,11 +189,11 @@ public:
189 189
190 virtual void Update(EffectInfo::InParams& in_params) = 0; 190 virtual void Update(EffectInfo::InParams& in_params) = 0;
191 virtual void UpdateForCommandGeneration() = 0; 191 virtual void UpdateForCommandGeneration() = 0;
192 UsageState GetUsage() const; 192 [[nodiscard]] UsageState GetUsage() const;
193 EffectType GetType() const; 193 [[nodiscard]] EffectType GetType() const;
194 bool IsEnabled() const; 194 [[nodiscard]] bool IsEnabled() const;
195 s32 GetMixID() const; 195 [[nodiscard]] s32 GetMixID() const;
196 s32 GetProcessingOrder() const; 196 [[nodiscard]] s32 GetProcessingOrder() const;
197 197
198protected: 198protected:
199 UsageState usage{UsageState::Invalid}; 199 UsageState usage{UsageState::Invalid};
@@ -257,10 +257,10 @@ public:
257 257
258 void Update(EffectInfo::InParams& in_params) override; 258 void Update(EffectInfo::InParams& in_params) override;
259 void UpdateForCommandGeneration() override; 259 void UpdateForCommandGeneration() override;
260 VAddr GetSendInfo() const; 260 [[nodiscard]] VAddr GetSendInfo() const;
261 VAddr GetSendBuffer() const; 261 [[nodiscard]] VAddr GetSendBuffer() const;
262 VAddr GetRecvInfo() const; 262 [[nodiscard]] VAddr GetRecvInfo() const;
263 VAddr GetRecvBuffer() const; 263 [[nodiscard]] VAddr GetRecvBuffer() const;
264 264
265private: 265private:
266 VAddr send_info{}; 266 VAddr send_info{};
@@ -309,10 +309,10 @@ public:
309 explicit EffectContext(std::size_t effect_count); 309 explicit EffectContext(std::size_t effect_count);
310 ~EffectContext(); 310 ~EffectContext();
311 311
312 std::size_t GetCount() const; 312 [[nodiscard]] std::size_t GetCount() const;
313 EffectBase* GetInfo(std::size_t i); 313 [[nodiscard]] EffectBase* GetInfo(std::size_t i);
314 EffectBase* RetargetEffect(std::size_t i, EffectType effect); 314 [[nodiscard]] EffectBase* RetargetEffect(std::size_t i, EffectType effect);
315 const EffectBase* GetInfo(std::size_t i) const; 315 [[nodiscard]] const EffectBase* GetInfo(std::size_t i) const;
316 316
317private: 317private:
318 std::size_t effect_count{}; 318 std::size_t effect_count{};
diff --git a/src/audio_core/mix_context.h b/src/audio_core/mix_context.h
index 6a588eeb4..68bc673c6 100644
--- a/src/audio_core/mix_context.h
+++ b/src/audio_core/mix_context.h
@@ -62,17 +62,17 @@ public:
62 ServerMixInfo(); 62 ServerMixInfo();
63 ~ServerMixInfo(); 63 ~ServerMixInfo();
64 64
65 const ServerMixInfo::InParams& GetInParams() const; 65 [[nodiscard]] const ServerMixInfo::InParams& GetInParams() const;
66 ServerMixInfo::InParams& GetInParams(); 66 [[nodiscard]] ServerMixInfo::InParams& GetInParams();
67 67
68 bool Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in, 68 bool Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in,
69 BehaviorInfo& behavior_info, SplitterContext& splitter_context, 69 BehaviorInfo& behavior_info, SplitterContext& splitter_context,
70 EffectContext& effect_context); 70 EffectContext& effect_context);
71 bool HasAnyConnection() const; 71 [[nodiscard]] bool HasAnyConnection() const;
72 void Cleanup(); 72 void Cleanup();
73 void SetEffectCount(std::size_t count); 73 void SetEffectCount(std::size_t count);
74 void ResetEffectProcessingOrder(); 74 void ResetEffectProcessingOrder();
75 s32 GetEffectOrder(std::size_t i) const; 75 [[nodiscard]] s32 GetEffectOrder(std::size_t i) const;
76 76
77private: 77private:
78 std::vector<s32> effect_processing_order; 78 std::vector<s32> effect_processing_order;
@@ -91,15 +91,15 @@ public:
91 void SortInfo(); 91 void SortInfo();
92 bool TsortInfo(SplitterContext& splitter_context); 92 bool TsortInfo(SplitterContext& splitter_context);
93 93
94 std::size_t GetCount() const; 94 [[nodiscard]] std::size_t GetCount() const;
95 ServerMixInfo& GetInfo(std::size_t i); 95 [[nodiscard]] ServerMixInfo& GetInfo(std::size_t i);
96 const ServerMixInfo& GetInfo(std::size_t i) const; 96 [[nodiscard]] const ServerMixInfo& GetInfo(std::size_t i) const;
97 ServerMixInfo& GetSortedInfo(std::size_t i); 97 [[nodiscard]] ServerMixInfo& GetSortedInfo(std::size_t i);
98 const ServerMixInfo& GetSortedInfo(std::size_t i) const; 98 [[nodiscard]] const ServerMixInfo& GetSortedInfo(std::size_t i) const;
99 ServerMixInfo& GetFinalMixInfo(); 99 [[nodiscard]] ServerMixInfo& GetFinalMixInfo();
100 const ServerMixInfo& GetFinalMixInfo() const; 100 [[nodiscard]] const ServerMixInfo& GetFinalMixInfo() const;
101 EdgeMatrix& GetEdgeMatrix(); 101 [[nodiscard]] EdgeMatrix& GetEdgeMatrix();
102 const EdgeMatrix& GetEdgeMatrix() const; 102 [[nodiscard]] const EdgeMatrix& GetEdgeMatrix() const;
103 103
104private: 104private:
105 void CalcMixBufferOffset(); 105 void CalcMixBufferOffset();
diff --git a/src/audio_core/sink_context.cpp b/src/audio_core/sink_context.cpp
index 0882b411a..cdb47ba81 100644
--- a/src/audio_core/sink_context.cpp
+++ b/src/audio_core/sink_context.cpp
@@ -12,10 +12,16 @@ std::size_t SinkContext::GetCount() const {
12 return sink_count; 12 return sink_count;
13} 13}
14 14
15void SinkContext::UpdateMainSink(SinkInfo::InParams& in) { 15void SinkContext::UpdateMainSink(const SinkInfo::InParams& in) {
16 ASSERT(in.type == SinkTypes::Device);
17
18 downmix = in.device.down_matrix_enabled;
19 if (downmix) {
20 downmix_coefficients = in.device.down_matrix_coef;
21 }
16 in_use = in.in_use; 22 in_use = in.in_use;
17 use_count = in.device.input_count; 23 use_count = in.device.input_count;
18 std::memcpy(buffers.data(), in.device.input.data(), AudioCommon::MAX_CHANNEL_COUNT); 24 buffers = in.device.input;
19} 25}
20 26
21bool SinkContext::InUse() const { 27bool SinkContext::InUse() const {
@@ -28,4 +34,12 @@ std::vector<u8> SinkContext::OutputBuffers() const {
28 return buffer_ret; 34 return buffer_ret;
29} 35}
30 36
37bool SinkContext::HasDownMixingCoefficients() const {
38 return downmix;
39}
40
41const std::array<float_le, 4>& SinkContext::GetDownmixCoefficients() const {
42 return downmix_coefficients;
43}
44
31} // namespace AudioCore 45} // namespace AudioCore
diff --git a/src/audio_core/sink_context.h b/src/audio_core/sink_context.h
index d7aa72ba7..5a757a4ef 100644
--- a/src/audio_core/sink_context.h
+++ b/src/audio_core/sink_context.h
@@ -74,16 +74,21 @@ public:
74 explicit SinkContext(std::size_t sink_count); 74 explicit SinkContext(std::size_t sink_count);
75 ~SinkContext(); 75 ~SinkContext();
76 76
77 std::size_t GetCount() const; 77 [[nodiscard]] std::size_t GetCount() const;
78 78
79 void UpdateMainSink(SinkInfo::InParams& in); 79 void UpdateMainSink(const SinkInfo::InParams& in);
80 bool InUse() const; 80 [[nodiscard]] bool InUse() const;
81 std::vector<u8> OutputBuffers() const; 81 [[nodiscard]] std::vector<u8> OutputBuffers() const;
82
83 [[nodiscard]] bool HasDownMixingCoefficients() const;
84 [[nodiscard]] const std::array<float_le, 4>& GetDownmixCoefficients() const;
82 85
83private: 86private:
84 bool in_use{false}; 87 bool in_use{false};
85 s32 use_count{}; 88 s32 use_count{};
86 std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> buffers{}; 89 std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> buffers{};
87 std::size_t sink_count{}; 90 std::size_t sink_count{};
91 bool downmix{false};
92 std::array<float_le, 4> downmix_coefficients{};
88}; 93};
89} // namespace AudioCore 94} // namespace AudioCore
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index 4bbb1e0c4..3f11b84ae 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -136,4 +136,13 @@ std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers(std::size_t max_count)
136 return tags; 136 return tags;
137} 137}
138 138
139std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers() {
140 std::vector<Buffer::Tag> tags;
141 while (!released_buffers.empty()) {
142 tags.push_back(released_buffers.front()->GetTag());
143 released_buffers.pop();
144 }
145 return tags;
146}
147
139} // namespace AudioCore 148} // namespace AudioCore
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h
index 6437b8591..71c2d0b4f 100644
--- a/src/audio_core/stream.h
+++ b/src/audio_core/stream.h
@@ -57,37 +57,40 @@ public:
57 bool QueueBuffer(BufferPtr&& buffer); 57 bool QueueBuffer(BufferPtr&& buffer);
58 58
59 /// Returns true if the audio stream contains a buffer with the specified tag 59 /// Returns true if the audio stream contains a buffer with the specified tag
60 bool ContainsBuffer(Buffer::Tag tag) const; 60 [[nodiscard]] bool ContainsBuffer(Buffer::Tag tag) const;
61 61
62 /// Returns a vector of recently released buffers specified by tag 62 /// Returns a vector of recently released buffers specified by tag
63 std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(std::size_t max_count); 63 [[nodiscard]] std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(std::size_t max_count);
64
65 /// Returns a vector of all recently released buffers specified by tag
66 [[nodiscard]] std::vector<Buffer::Tag> GetTagsAndReleaseBuffers();
64 67
65 void SetVolume(float volume); 68 void SetVolume(float volume);
66 69
67 float GetVolume() const { 70 [[nodiscard]] float GetVolume() const {
68 return game_volume; 71 return game_volume;
69 } 72 }
70 73
71 /// Returns true if the stream is currently playing 74 /// Returns true if the stream is currently playing
72 bool IsPlaying() const { 75 [[nodiscard]] bool IsPlaying() const {
73 return state == State::Playing; 76 return state == State::Playing;
74 } 77 }
75 78
76 /// Returns the number of queued buffers 79 /// Returns the number of queued buffers
77 std::size_t GetQueueSize() const { 80 [[nodiscard]] std::size_t GetQueueSize() const {
78 return queued_buffers.size(); 81 return queued_buffers.size();
79 } 82 }
80 83
81 /// Gets the sample rate 84 /// Gets the sample rate
82 u32 GetSampleRate() const { 85 [[nodiscard]] u32 GetSampleRate() const {
83 return sample_rate; 86 return sample_rate;
84 } 87 }
85 88
86 /// Gets the number of channels 89 /// Gets the number of channels
87 u32 GetNumChannels() const; 90 [[nodiscard]] u32 GetNumChannels() const;
88 91
89 /// Get the state 92 /// Get the state
90 State GetState() const; 93 [[nodiscard]] State GetState() const;
91 94
92private: 95private:
93 /// Plays the next queued buffer in the audio stream, starting playback if necessary 96 /// Plays the next queued buffer in the audio stream, starting playback if necessary
@@ -97,7 +100,7 @@ private:
97 void ReleaseActiveBuffer(std::chrono::nanoseconds ns_late = {}); 100 void ReleaseActiveBuffer(std::chrono::nanoseconds ns_late = {});
98 101
99 /// Gets the number of core cycles when the specified buffer will be released 102 /// Gets the number of core cycles when the specified buffer will be released
100 std::chrono::nanoseconds GetBufferReleaseNS(const Buffer& buffer) const; 103 [[nodiscard]] std::chrono::nanoseconds GetBufferReleaseNS(const Buffer& buffer) const;
101 104
102 u32 sample_rate; ///< Sample rate of the stream 105 u32 sample_rate; ///< Sample rate of the stream
103 Format format; ///< Format of the stream 106 Format format; ///< Format of the stream