summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2021-07-03 00:24:33 -0700
committerGravatar GitHub2021-07-03 00:24:33 -0700
commit2fc0a760f09c4557d476204ef558743e6f42bd71 (patch)
tree87be7a47b82b30d3a2805f47a77b72ef28805af6 /src
parentMerge pull request #6459 from lat9nq/ubuntu-fixes (diff)
parentFix XC2/VOEZ crashing, add audio looping and a few misc fixes (diff)
downloadyuzu-2fc0a760f09c4557d476204ef558743e6f42bd71.tar.gz
yuzu-2fc0a760f09c4557d476204ef558743e6f42bd71.tar.xz
yuzu-2fc0a760f09c4557d476204ef558743e6f42bd71.zip
Merge pull request #6498 from Kelebek1/Audio
[audio_core] Decouple audio update and processing, and process at variable rate
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_renderer.cpp62
-rw-r--r--src/audio_core/audio_renderer.h6
-rw-r--r--src/audio_core/command_generator.cpp76
-rw-r--r--src/audio_core/command_generator.h8
-rw-r--r--src/audio_core/info_updater.cpp3
-rw-r--r--src/audio_core/voice_context.cpp88
-rw-r--r--src/audio_core/voice_context.h13
-rw-r--r--src/core/hle/service/audio/audren_u.cpp12
8 files changed, 180 insertions, 88 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 80ffddb10..ccd5ca6cc 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -12,6 +12,7 @@
12#include "audio_core/voice_context.h" 12#include "audio_core/voice_context.h"
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14#include "common/settings.h" 14#include "common/settings.h"
15#include "core/core_timing.h"
15#include "core/memory.h" 16#include "core/memory.h"
16 17
17namespace { 18namespace {
@@ -68,7 +69,9 @@ namespace {
68} // namespace 69} // namespace
69 70
70namespace AudioCore { 71namespace AudioCore {
71AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, 72constexpr s32 NUM_BUFFERS = 2;
73
74AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_,
72 AudioCommon::AudioRendererParameter params, 75 AudioCommon::AudioRendererParameter params,
73 Stream::ReleaseCallback&& release_callback, 76 Stream::ReleaseCallback&& release_callback,
74 std::size_t instance_number) 77 std::size_t instance_number)
@@ -77,7 +80,8 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory
77 sink_context(params.sink_count), splitter_context(), 80 sink_context(params.sink_count), splitter_context(),
78 voices(params.voice_count), memory{memory_}, 81 voices(params.voice_count), memory{memory_},
79 command_generator(worker_params, voice_context, mix_context, splitter_context, effect_context, 82 command_generator(worker_params, voice_context, mix_context, splitter_context, effect_context,
80 memory) { 83 memory),
84 core_timing{core_timing_} {
81 behavior_info.SetUserRevision(params.revision); 85 behavior_info.SetUserRevision(params.revision);
82 splitter_context.Initialize(behavior_info, params.splitter_count, 86 splitter_context.Initialize(behavior_info, params.splitter_count,
83 params.num_splitter_send_channels); 87 params.num_splitter_send_channels);
@@ -86,16 +90,27 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory
86 stream = audio_out->OpenStream( 90 stream = audio_out->OpenStream(
87 core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS, 91 core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
88 fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback)); 92 fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback));
89 audio_out->StartStream(stream); 93 process_event = Core::Timing::CreateEvent(
90 94 fmt::format("AudioRenderer-Instance{}-Process", instance_number),
91 QueueMixedBuffer(0); 95 [this](std::uintptr_t, std::chrono::nanoseconds) { ReleaseAndQueueBuffers(); });
92 QueueMixedBuffer(1); 96 for (s32 i = 0; i < NUM_BUFFERS; ++i) {
93 QueueMixedBuffer(2); 97 QueueMixedBuffer(i);
94 QueueMixedBuffer(3); 98 }
95} 99}
96 100
97AudioRenderer::~AudioRenderer() = default; 101AudioRenderer::~AudioRenderer() = default;
98 102
103ResultCode AudioRenderer::Start() {
104 audio_out->StartStream(stream);
105 ReleaseAndQueueBuffers();
106 return ResultSuccess;
107}
108
109ResultCode AudioRenderer::Stop() {
110 audio_out->StopStream(stream);
111 return ResultSuccess;
112}
113
99u32 AudioRenderer::GetSampleRate() const { 114u32 AudioRenderer::GetSampleRate() const {
100 return worker_params.sample_rate; 115 return worker_params.sample_rate;
101} 116}
@@ -114,7 +129,7 @@ Stream::State AudioRenderer::GetStreamState() const {
114 129
115ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params, 130ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params,
116 std::vector<u8>& output_params) { 131 std::vector<u8>& output_params) {
117 132 std::scoped_lock lock{mutex};
118 InfoUpdater info_updater{input_params, output_params, behavior_info}; 133 InfoUpdater info_updater{input_params, output_params, behavior_info};
119 134
120 if (!info_updater.UpdateBehaviorInfo(behavior_info)) { 135 if (!info_updater.UpdateBehaviorInfo(behavior_info)) {
@@ -194,9 +209,6 @@ ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_param
194 LOG_ERROR(Audio, "Audio buffers were not consumed!"); 209 LOG_ERROR(Audio, "Audio buffers were not consumed!");
195 return AudioCommon::Audren::ERR_INVALID_PARAMETERS; 210 return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
196 } 211 }
197
198 ReleaseAndQueueBuffers();
199
200 return ResultSuccess; 212 return ResultSuccess;
201} 213}
202 214
@@ -220,10 +232,8 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
220 command_generator.PostCommand(); 232 command_generator.PostCommand();
221 // Base sample size 233 // Base sample size
222 std::size_t BUFFER_SIZE{worker_params.sample_count}; 234 std::size_t BUFFER_SIZE{worker_params.sample_count};
223 // Samples 235 // Samples, making sure to clear
224 std::vector<s16> buffer(BUFFER_SIZE * stream->GetNumChannels()); 236 std::vector<s16> buffer(BUFFER_SIZE * stream->GetNumChannels(), 0);
225 // Make sure to clear our samples
226 std::memset(buffer.data(), 0, buffer.size() * sizeof(s16));
227 237
228 if (sink_context.InUse()) { 238 if (sink_context.InUse()) {
229 const auto stream_channel_count = stream->GetNumChannels(); 239 const auto stream_channel_count = stream->GetNumChannels();
@@ -315,10 +325,24 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
315} 325}
316 326
317void AudioRenderer::ReleaseAndQueueBuffers() { 327void AudioRenderer::ReleaseAndQueueBuffers() {
318 const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream)}; 328 if (!stream->IsPlaying()) {
319 for (const auto& tag : released_buffers) { 329 return;
320 QueueMixedBuffer(tag);
321 } 330 }
331
332 {
333 std::scoped_lock lock{mutex};
334 const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream)};
335 for (const auto& tag : released_buffers) {
336 QueueMixedBuffer(tag);
337 }
338 }
339
340 const f32 sample_rate = static_cast<f32>(GetSampleRate());
341 const f32 sample_count = static_cast<f32>(GetSampleCount());
342 const f32 consume_rate = sample_rate / (sample_count * (sample_count / 240));
343 const s32 ms = (1000 / static_cast<s32>(consume_rate)) - 1;
344 const std::chrono::milliseconds next_event_time(std::max(ms / NUM_BUFFERS, 1));
345 core_timing.ScheduleEvent(next_event_time, process_event, {});
322} 346}
323 347
324} // namespace AudioCore 348} // namespace AudioCore
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index 18567f618..88fdd13dd 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -6,6 +6,7 @@
6 6
7#include <array> 7#include <array>
8#include <memory> 8#include <memory>
9#include <mutex>
9#include <vector> 10#include <vector>
10 11
11#include "audio_core/behavior_info.h" 12#include "audio_core/behavior_info.h"
@@ -45,6 +46,8 @@ public:
45 46
46 [[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params, 47 [[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params,
47 std::vector<u8>& output_params); 48 std::vector<u8>& output_params);
49 [[nodiscard]] ResultCode Start();
50 [[nodiscard]] ResultCode Stop();
48 void QueueMixedBuffer(Buffer::Tag tag); 51 void QueueMixedBuffer(Buffer::Tag tag);
49 void ReleaseAndQueueBuffers(); 52 void ReleaseAndQueueBuffers();
50 [[nodiscard]] u32 GetSampleRate() const; 53 [[nodiscard]] u32 GetSampleRate() const;
@@ -68,6 +71,9 @@ private:
68 Core::Memory::Memory& memory; 71 Core::Memory::Memory& memory;
69 CommandGenerator command_generator; 72 CommandGenerator command_generator;
70 std::size_t elapsed_frame_count{}; 73 std::size_t elapsed_frame_count{};
74 Core::Timing::CoreTiming& core_timing;
75 std::shared_ptr<Core::Timing::EventType> process_event;
76 std::mutex mutex;
71}; 77};
72 78
73} // namespace AudioCore 79} // namespace AudioCore
diff --git a/src/audio_core/command_generator.cpp b/src/audio_core/command_generator.cpp
index 437cc5ccd..27437f1ea 100644
--- a/src/audio_core/command_generator.cpp
+++ b/src/audio_core/command_generator.cpp
@@ -795,7 +795,7 @@ void CommandGenerator::UpdateI3dl2Reverb(I3dl2ReverbParams& info, I3dl2ReverbSta
795 state.lowpass_1 = 0.0f; 795 state.lowpass_1 = 0.0f;
796 } else { 796 } else {
797 const auto a = 1.0f - hf_gain; 797 const auto a = 1.0f - hf_gain;
798 const auto b = 2.0f * (1.0f - hf_gain * CosD(256.0f * info.hf_reference / 798 const auto b = 2.0f * (2.0f - hf_gain * CosD(256.0f * info.hf_reference /
799 static_cast<f32>(info.sample_rate))); 799 static_cast<f32>(info.sample_rate)));
800 const auto c = std::sqrt(b * b - 4.0f * a * a); 800 const auto c = std::sqrt(b * b - 4.0f * a * a);
801 801
@@ -843,7 +843,7 @@ void CommandGenerator::UpdateI3dl2Reverb(I3dl2ReverbParams& info, I3dl2ReverbSta
843 } 843 }
844 844
845 const auto max_early_delay = state.early_delay_line.GetMaxDelay(); 845 const auto max_early_delay = state.early_delay_line.GetMaxDelay();
846 const auto reflection_time = 1000.0f * (0.0098f * info.reverb_delay + 0.02f); 846 const auto reflection_time = 1000.0f * (0.9998f * info.reverb_delay + 0.02f);
847 for (std::size_t tap = 0; tap < AudioCommon::I3DL2REVERB_TAPS; tap++) { 847 for (std::size_t tap = 0; tap < AudioCommon::I3DL2REVERB_TAPS; tap++) {
848 const auto length = AudioCommon::CalculateDelaySamples( 848 const auto length = AudioCommon::CalculateDelaySamples(
849 sample_rate, 1000.0f * info.reflection_delay + reflection_time * EARLY_TAP_TIMES[tap]); 849 sample_rate, 1000.0f * info.reflection_delay + reflection_time * EARLY_TAP_TIMES[tap]);
@@ -1004,7 +1004,8 @@ void CommandGenerator::GenerateFinalMixCommand() {
1004} 1004}
1005 1005
1006s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state, 1006s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
1007 s32 sample_count, s32 channel, std::size_t mix_offset) { 1007 s32 sample_start_offset, s32 sample_end_offset, s32 sample_count,
1008 s32 channel, std::size_t mix_offset) {
1008 const auto& in_params = voice_info.GetInParams(); 1009 const auto& in_params = voice_info.GetInParams();
1009 const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index]; 1010 const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index];
1010 if (wave_buffer.buffer_address == 0) { 1011 if (wave_buffer.buffer_address == 0) {
@@ -1013,14 +1014,12 @@ s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_s
1013 if (wave_buffer.buffer_size == 0) { 1014 if (wave_buffer.buffer_size == 0) {
1014 return 0; 1015 return 0;
1015 } 1016 }
1016 if (wave_buffer.end_sample_offset < wave_buffer.start_sample_offset) { 1017 if (sample_end_offset < sample_start_offset) {
1017 return 0; 1018 return 0;
1018 } 1019 }
1019 const auto samples_remaining = 1020 const auto samples_remaining = (sample_end_offset - sample_start_offset) - dsp_state.offset;
1020 (wave_buffer.end_sample_offset - wave_buffer.start_sample_offset) - dsp_state.offset;
1021 const auto start_offset = 1021 const auto start_offset =
1022 ((wave_buffer.start_sample_offset + dsp_state.offset) * in_params.channel_count) * 1022 ((dsp_state.offset + sample_start_offset) * in_params.channel_count) * sizeof(s16);
1023 sizeof(s16);
1024 const auto buffer_pos = wave_buffer.buffer_address + start_offset; 1023 const auto buffer_pos = wave_buffer.buffer_address + start_offset;
1025 const auto samples_processed = std::min(sample_count, samples_remaining); 1024 const auto samples_processed = std::min(sample_count, samples_remaining);
1026 1025
@@ -1044,8 +1043,8 @@ s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_s
1044} 1043}
1045 1044
1046s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, 1045s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
1047 s32 sample_count, [[maybe_unused]] s32 channel, 1046 s32 sample_start_offset, s32 sample_end_offset, s32 sample_count,
1048 std::size_t mix_offset) { 1047 [[maybe_unused]] s32 channel, std::size_t mix_offset) {
1049 const auto& in_params = voice_info.GetInParams(); 1048 const auto& in_params = voice_info.GetInParams();
1050 const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index]; 1049 const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index];
1051 if (wave_buffer.buffer_address == 0) { 1050 if (wave_buffer.buffer_address == 0) {
@@ -1054,7 +1053,7 @@ s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_s
1054 if (wave_buffer.buffer_size == 0) { 1053 if (wave_buffer.buffer_size == 0) {
1055 return 0; 1054 return 0;
1056 } 1055 }
1057 if (wave_buffer.end_sample_offset < wave_buffer.start_sample_offset) { 1056 if (sample_end_offset < sample_start_offset) {
1058 return 0; 1057 return 0;
1059 } 1058 }
1060 1059
@@ -1079,10 +1078,9 @@ s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_s
1079 s32 coef1 = coeffs[idx * 2]; 1078 s32 coef1 = coeffs[idx * 2];
1080 s32 coef2 = coeffs[idx * 2 + 1]; 1079 s32 coef2 = coeffs[idx * 2 + 1];
1081 1080
1082 const auto samples_remaining = 1081 const auto samples_remaining = (sample_end_offset - sample_start_offset) - dsp_state.offset;
1083 (wave_buffer.end_sample_offset - wave_buffer.start_sample_offset) - dsp_state.offset;
1084 const auto samples_processed = std::min(sample_count, samples_remaining); 1082 const auto samples_processed = std::min(sample_count, samples_remaining);
1085 const auto sample_pos = wave_buffer.start_sample_offset + dsp_state.offset; 1083 const auto sample_pos = dsp_state.offset + sample_start_offset;
1086 1084
1087 const auto samples_remaining_in_frame = sample_pos % SAMPLES_PER_FRAME; 1085 const auto samples_remaining_in_frame = sample_pos % SAMPLES_PER_FRAME;
1088 auto position_in_frame = ((sample_pos / SAMPLES_PER_FRAME) * NIBBLES_PER_SAMPLE) + 1086 auto position_in_frame = ((sample_pos / SAMPLES_PER_FRAME) * NIBBLES_PER_SAMPLE) +
@@ -1210,9 +1208,8 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* o
1210 } 1208 }
1211 1209
1212 std::size_t temp_mix_offset{}; 1210 std::size_t temp_mix_offset{};
1213 bool is_buffer_completed{false};
1214 auto samples_remaining = sample_count; 1211 auto samples_remaining = sample_count;
1215 while (samples_remaining > 0 && !is_buffer_completed) { 1212 while (samples_remaining > 0) {
1216 const auto samples_to_output = std::min(samples_remaining, min_required_samples); 1213 const auto samples_to_output = std::min(samples_remaining, min_required_samples);
1217 const auto samples_to_read = (samples_to_output * resample_rate + dsp_state.fraction) >> 15; 1214 const auto samples_to_read = (samples_to_output * resample_rate + dsp_state.fraction) >> 15;
1218 1215
@@ -1229,24 +1226,38 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* o
1229 const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index]; 1226 const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index];
1230 // No more data can be read 1227 // No more data can be read
1231 if (!dsp_state.is_wave_buffer_valid[dsp_state.wave_buffer_index]) { 1228 if (!dsp_state.is_wave_buffer_valid[dsp_state.wave_buffer_index]) {
1232 is_buffer_completed = true;
1233 break; 1229 break;
1234 } 1230 }
1235 1231
1236 if (in_params.sample_format == SampleFormat::Adpcm && dsp_state.offset == 0 && 1232 if (in_params.sample_format == SampleFormat::Adpcm && dsp_state.offset == 0 &&
1237 wave_buffer.context_address != 0 && wave_buffer.context_size != 0) { 1233 wave_buffer.context_address != 0 && wave_buffer.context_size != 0) {
1238 // TODO(ogniK): ADPCM loop context 1234 memory.ReadBlock(wave_buffer.context_address, &dsp_state.context,
1235 sizeof(ADPCMContext));
1236 }
1237
1238 s32 samples_offset_start;
1239 s32 samples_offset_end;
1240 if (dsp_state.loop_count > 0 && wave_buffer.loop_start_sample != 0 &&
1241 wave_buffer.loop_end_sample != 0 &&
1242 wave_buffer.loop_start_sample <= wave_buffer.loop_end_sample) {
1243 samples_offset_start = wave_buffer.loop_start_sample;
1244 samples_offset_end = wave_buffer.loop_end_sample;
1245 } else {
1246 samples_offset_start = wave_buffer.start_sample_offset;
1247 samples_offset_end = wave_buffer.end_sample_offset;
1239 } 1248 }
1240 1249
1241 s32 samples_decoded{0}; 1250 s32 samples_decoded{0};
1242 switch (in_params.sample_format) { 1251 switch (in_params.sample_format) {
1243 case SampleFormat::Pcm16: 1252 case SampleFormat::Pcm16:
1244 samples_decoded = DecodePcm16(voice_info, dsp_state, samples_to_read - samples_read, 1253 samples_decoded =
1245 channel, temp_mix_offset); 1254 DecodePcm16(voice_info, dsp_state, samples_offset_start, samples_offset_end,
1255 samples_to_read - samples_read, channel, temp_mix_offset);
1246 break; 1256 break;
1247 case SampleFormat::Adpcm: 1257 case SampleFormat::Adpcm:
1248 samples_decoded = DecodeAdpcm(voice_info, dsp_state, samples_to_read - samples_read, 1258 samples_decoded =
1249 channel, temp_mix_offset); 1259 DecodeAdpcm(voice_info, dsp_state, samples_offset_start, samples_offset_end,
1260 samples_to_read - samples_read, channel, temp_mix_offset);
1250 break; 1261 break;
1251 default: 1262 default:
1252 UNREACHABLE_MSG("Unimplemented sample format={}", in_params.sample_format); 1263 UNREACHABLE_MSG("Unimplemented sample format={}", in_params.sample_format);
@@ -1257,15 +1268,19 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* o
1257 dsp_state.offset += samples_decoded; 1268 dsp_state.offset += samples_decoded;
1258 dsp_state.played_sample_count += samples_decoded; 1269 dsp_state.played_sample_count += samples_decoded;
1259 1270
1260 if (dsp_state.offset >= 1271 if (dsp_state.offset >= (samples_offset_end - samples_offset_start) ||
1261 (wave_buffer.end_sample_offset - wave_buffer.start_sample_offset) ||
1262 samples_decoded == 0) { 1272 samples_decoded == 0) {
1263 // Reset our sample offset 1273 // Reset our sample offset
1264 dsp_state.offset = 0; 1274 dsp_state.offset = 0;
1265 if (wave_buffer.is_looping) { 1275 if (wave_buffer.is_looping) {
1266 if (samples_decoded == 0) { 1276 dsp_state.loop_count++;
1277 if (wave_buffer.loop_count > 0 &&
1278 (dsp_state.loop_count > wave_buffer.loop_count || samples_decoded == 0)) {
1267 // End of our buffer 1279 // End of our buffer
1268 is_buffer_completed = true; 1280 voice_info.SetWaveBufferCompleted(dsp_state, wave_buffer);
1281 }
1282
1283 if (samples_decoded == 0) {
1269 break; 1284 break;
1270 } 1285 }
1271 1286
@@ -1273,15 +1288,8 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* o
1273 dsp_state.played_sample_count = 0; 1288 dsp_state.played_sample_count = 0;
1274 } 1289 }
1275 } else { 1290 } else {
1276
1277 // Update our wave buffer states 1291 // Update our wave buffer states
1278 dsp_state.is_wave_buffer_valid[dsp_state.wave_buffer_index] = false; 1292 voice_info.SetWaveBufferCompleted(dsp_state, wave_buffer);
1279 dsp_state.wave_buffer_consumed++;
1280 dsp_state.wave_buffer_index =
1281 (dsp_state.wave_buffer_index + 1) % AudioCommon::MAX_WAVE_BUFFERS;
1282 if (wave_buffer.end_of_stream) {
1283 dsp_state.played_sample_count = 0;
1284 }
1285 } 1293 }
1286 } 1294 }
1287 } 1295 }
diff --git a/src/audio_core/command_generator.h b/src/audio_core/command_generator.h
index 2ebb755b0..673e4fbef 100644
--- a/src/audio_core/command_generator.h
+++ b/src/audio_core/command_generator.h
@@ -86,10 +86,10 @@ private:
86 std::vector<u8>& work_buffer); 86 std::vector<u8>& work_buffer);
87 void UpdateI3dl2Reverb(I3dl2ReverbParams& info, I3dl2ReverbState& state, bool should_clear); 87 void UpdateI3dl2Reverb(I3dl2ReverbParams& info, I3dl2ReverbState& state, bool should_clear);
88 // DSP Code 88 // DSP Code
89 s32 DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_count, 89 s32 DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_start_offset,
90 s32 channel, std::size_t mix_offset); 90 s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset);
91 s32 DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_count, 91 s32 DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_start_offset,
92 s32 channel, std::size_t mix_offset); 92 s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset);
93 void DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* output, VoiceState& dsp_state, 93 void DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* output, VoiceState& dsp_state,
94 s32 channel, s32 target_sample_rate, s32 sample_count, s32 node_id); 94 s32 channel, s32 target_sample_rate, s32 sample_count, s32 node_id);
95 95
diff --git a/src/audio_core/info_updater.cpp b/src/audio_core/info_updater.cpp
index 4a5b1b4ab..9b4ca1851 100644
--- a/src/audio_core/info_updater.cpp
+++ b/src/audio_core/info_updater.cpp
@@ -189,9 +189,6 @@ bool InfoUpdater::UpdateVoices(VoiceContext& voice_context,
189 if (voice_in_params.is_new) { 189 if (voice_in_params.is_new) {
190 // Default our values for our voice 190 // Default our values for our voice
191 voice_info.Initialize(); 191 voice_info.Initialize();
192 if (channel_count == 0 || channel_count > AudioCommon::MAX_CHANNEL_COUNT) {
193 continue;
194 }
195 192
196 // Zero out our voice states 193 // Zero out our voice states
197 for (std::size_t channel = 0; channel < channel_count; channel++) { 194 for (std::size_t channel = 0; channel < channel_count; channel++) {
diff --git a/src/audio_core/voice_context.cpp b/src/audio_core/voice_context.cpp
index 867b8fc6b..d8c954b60 100644
--- a/src/audio_core/voice_context.cpp
+++ b/src/audio_core/voice_context.cpp
@@ -66,7 +66,7 @@ void ServerVoiceInfo::Initialize() {
66 in_params.last_volume = 0.0f; 66 in_params.last_volume = 0.0f;
67 in_params.biquad_filter.fill({}); 67 in_params.biquad_filter.fill({});
68 in_params.wave_buffer_count = 0; 68 in_params.wave_buffer_count = 0;
69 in_params.wave_bufffer_head = 0; 69 in_params.wave_buffer_head = 0;
70 in_params.mix_id = AudioCommon::NO_MIX; 70 in_params.mix_id = AudioCommon::NO_MIX;
71 in_params.splitter_info_id = AudioCommon::NO_SPLITTER; 71 in_params.splitter_info_id = AudioCommon::NO_SPLITTER;
72 in_params.additional_params_address = 0; 72 in_params.additional_params_address = 0;
@@ -75,7 +75,7 @@ void ServerVoiceInfo::Initialize() {
75 out_params.played_sample_count = 0; 75 out_params.played_sample_count = 0;
76 out_params.wave_buffer_consumed = 0; 76 out_params.wave_buffer_consumed = 0;
77 in_params.voice_drop_flag = false; 77 in_params.voice_drop_flag = false;
78 in_params.buffer_mapped = false; 78 in_params.buffer_mapped = true;
79 in_params.wave_buffer_flush_request_count = 0; 79 in_params.wave_buffer_flush_request_count = 0;
80 in_params.was_biquad_filter_enabled.fill(false); 80 in_params.was_biquad_filter_enabled.fill(false);
81 81
@@ -126,7 +126,7 @@ void ServerVoiceInfo::UpdateParameters(const VoiceInfo::InParams& voice_in,
126 in_params.volume = voice_in.volume; 126 in_params.volume = voice_in.volume;
127 in_params.biquad_filter = voice_in.biquad_filter; 127 in_params.biquad_filter = voice_in.biquad_filter;
128 in_params.wave_buffer_count = voice_in.wave_buffer_count; 128 in_params.wave_buffer_count = voice_in.wave_buffer_count;
129 in_params.wave_bufffer_head = voice_in.wave_buffer_head; 129 in_params.wave_buffer_head = voice_in.wave_buffer_head;
130 if (behavior_info.IsFlushVoiceWaveBuffersSupported()) { 130 if (behavior_info.IsFlushVoiceWaveBuffersSupported()) {
131 const auto in_request_count = in_params.wave_buffer_flush_request_count; 131 const auto in_request_count = in_params.wave_buffer_flush_request_count;
132 const auto voice_request_count = voice_in.wave_buffer_flush_request_count; 132 const auto voice_request_count = voice_in.wave_buffer_flush_request_count;
@@ -185,14 +185,16 @@ void ServerVoiceInfo::UpdateWaveBuffers(
185 wave_buffer.buffer_size = 0; 185 wave_buffer.buffer_size = 0;
186 wave_buffer.context_address = 0; 186 wave_buffer.context_address = 0;
187 wave_buffer.context_size = 0; 187 wave_buffer.context_size = 0;
188 wave_buffer.loop_start_sample = 0;
189 wave_buffer.loop_end_sample = 0;
188 wave_buffer.sent_to_dsp = true; 190 wave_buffer.sent_to_dsp = true;
189 } 191 }
190 192
191 // Mark all our wave buffers as invalid 193 // Mark all our wave buffers as invalid
192 for (std::size_t channel = 0; channel < static_cast<std::size_t>(in_params.channel_count); 194 for (std::size_t channel = 0; channel < static_cast<std::size_t>(in_params.channel_count);
193 channel++) { 195 channel++) {
194 for (auto& is_valid : voice_states[channel]->is_wave_buffer_valid) { 196 for (std::size_t i = 0; i < AudioCommon::MAX_WAVE_BUFFERS; ++i) {
195 is_valid = false; 197 voice_states[channel]->is_wave_buffer_valid[i] = false;
196 } 198 }
197 } 199 }
198 } 200 }
@@ -211,7 +213,7 @@ void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer,
211 const WaveBuffer& in_wave_buffer, SampleFormat sample_format, 213 const WaveBuffer& in_wave_buffer, SampleFormat sample_format,
212 bool is_buffer_valid, 214 bool is_buffer_valid,
213 [[maybe_unused]] BehaviorInfo& behavior_info) { 215 [[maybe_unused]] BehaviorInfo& behavior_info) {
214 if (!is_buffer_valid && out_wavebuffer.sent_to_dsp) { 216 if (!is_buffer_valid && out_wavebuffer.sent_to_dsp && out_wavebuffer.buffer_address != 0) {
215 out_wavebuffer.buffer_address = 0; 217 out_wavebuffer.buffer_address = 0;
216 out_wavebuffer.buffer_size = 0; 218 out_wavebuffer.buffer_size = 0;
217 } 219 }
@@ -219,11 +221,40 @@ void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer,
219 if (!in_wave_buffer.sent_to_server || !in_params.buffer_mapped) { 221 if (!in_wave_buffer.sent_to_server || !in_params.buffer_mapped) {
220 // Validate sample offset sizings 222 // Validate sample offset sizings
221 if (sample_format == SampleFormat::Pcm16) { 223 if (sample_format == SampleFormat::Pcm16) {
222 const auto buffer_size = in_wave_buffer.buffer_size; 224 const s64 buffer_size = static_cast<s64>(in_wave_buffer.buffer_size);
223 if (in_wave_buffer.start_sample_offset < 0 || in_wave_buffer.end_sample_offset < 0 || 225 const s64 start = sizeof(s16) * in_wave_buffer.start_sample_offset;
224 (buffer_size < (sizeof(s16) * in_wave_buffer.start_sample_offset)) || 226 const s64 end = sizeof(s16) * in_wave_buffer.end_sample_offset;
225 (buffer_size < (sizeof(s16) * in_wave_buffer.end_sample_offset))) { 227 if (0 > start || start > buffer_size || 0 > end || end > buffer_size) {
226 // TODO(ogniK): Write error info 228 // TODO(ogniK): Write error info
229 LOG_ERROR(Audio,
230 "PCM16 wavebuffer has an invalid size. Buffer has size 0x{:08X}, but "
231 "offsets were "
232 "{:08X} - 0x{:08X}",
233 buffer_size, sizeof(s16) * in_wave_buffer.start_sample_offset,
234 sizeof(s16) * in_wave_buffer.end_sample_offset);
235 return;
236 }
237 } else if (sample_format == SampleFormat::Adpcm) {
238 const s64 buffer_size = static_cast<s64>(in_wave_buffer.buffer_size);
239 const s64 start_frames = in_wave_buffer.start_sample_offset / 14;
240 const s64 start_extra = in_wave_buffer.start_sample_offset % 14 == 0
241 ? 0
242 : (in_wave_buffer.start_sample_offset % 14) / 2 + 1 +
243 (in_wave_buffer.start_sample_offset % 2);
244 const s64 start = start_frames * 8 + start_extra;
245 const s64 end_frames = in_wave_buffer.end_sample_offset / 14;
246 const s64 end_extra = in_wave_buffer.end_sample_offset % 14 == 0
247 ? 0
248 : (in_wave_buffer.end_sample_offset % 14) / 2 + 1 +
249 (in_wave_buffer.end_sample_offset % 2);
250 const s64 end = end_frames * 8 + end_extra;
251 if (in_wave_buffer.start_sample_offset < 0 || start > buffer_size ||
252 in_wave_buffer.end_sample_offset < 0 || end > buffer_size) {
253 LOG_ERROR(Audio,
254 "ADPMC wavebuffer has an invalid size. Buffer has size 0x{:08X}, but "
255 "offsets were "
256 "{:08X} - 0x{:08X}",
257 in_wave_buffer.buffer_size, start, end);
227 return; 258 return;
228 } 259 }
229 } 260 }
@@ -239,29 +270,34 @@ void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer,
239 out_wavebuffer.buffer_size = in_wave_buffer.buffer_size; 270 out_wavebuffer.buffer_size = in_wave_buffer.buffer_size;
240 out_wavebuffer.context_address = in_wave_buffer.context_address; 271 out_wavebuffer.context_address = in_wave_buffer.context_address;
241 out_wavebuffer.context_size = in_wave_buffer.context_size; 272 out_wavebuffer.context_size = in_wave_buffer.context_size;
273 out_wavebuffer.loop_start_sample = in_wave_buffer.loop_start_sample;
274 out_wavebuffer.loop_end_sample = in_wave_buffer.loop_end_sample;
242 in_params.buffer_mapped = 275 in_params.buffer_mapped =
243 in_wave_buffer.buffer_address != 0 && in_wave_buffer.buffer_size != 0; 276 in_wave_buffer.buffer_address != 0 && in_wave_buffer.buffer_size != 0;
244 // TODO(ogniK): Pool mapper attachment 277 // TODO(ogniK): Pool mapper attachment
245 // TODO(ogniK): IsAdpcmLoopContextBugFixed 278 // TODO(ogniK): IsAdpcmLoopContextBugFixed
279 if (sample_format == SampleFormat::Adpcm && in_wave_buffer.context_address != 0 &&
280 in_wave_buffer.context_size != 0 && behavior_info.IsAdpcmLoopContextBugFixed()) {
281 } else {
282 out_wavebuffer.context_address = 0;
283 out_wavebuffer.context_size = 0;
284 }
246 } 285 }
247} 286}
248 287
249void ServerVoiceInfo::WriteOutStatus( 288void ServerVoiceInfo::WriteOutStatus(
250 VoiceInfo::OutParams& voice_out, VoiceInfo::InParams& voice_in, 289 VoiceInfo::OutParams& voice_out, VoiceInfo::InParams& voice_in,
251 std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& voice_states) { 290 std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& voice_states) {
252 if (voice_in.is_new) { 291 if (voice_in.is_new || in_params.is_new) {
253 in_params.is_new = true; 292 in_params.is_new = true;
254 voice_out.wave_buffer_consumed = 0; 293 voice_out.wave_buffer_consumed = 0;
255 voice_out.played_sample_count = 0; 294 voice_out.played_sample_count = 0;
256 voice_out.voice_dropped = false; 295 voice_out.voice_dropped = false;
257 } else if (!in_params.is_new) {
258 voice_out.wave_buffer_consumed = voice_states[0]->wave_buffer_consumed;
259 voice_out.played_sample_count = voice_states[0]->played_sample_count;
260 voice_out.voice_dropped = in_params.voice_drop_flag;
261 } else { 296 } else {
262 voice_out.wave_buffer_consumed = 0; 297 const auto& state = voice_states[0];
263 voice_out.played_sample_count = 0; 298 voice_out.wave_buffer_consumed = state->wave_buffer_consumed;
264 voice_out.voice_dropped = false; 299 voice_out.played_sample_count = state->played_sample_count;
300 voice_out.voice_dropped = state->voice_dropped;
265 } 301 }
266} 302}
267 303
@@ -283,7 +319,8 @@ ServerVoiceInfo::OutParams& ServerVoiceInfo::GetOutParams() {
283 319
284bool ServerVoiceInfo::ShouldSkip() const { 320bool ServerVoiceInfo::ShouldSkip() const {
285 // TODO(ogniK): Handle unmapped wave buffers or parameters 321 // TODO(ogniK): Handle unmapped wave buffers or parameters
286 return !in_params.in_use || (in_params.wave_buffer_count == 0) || in_params.voice_drop_flag; 322 return !in_params.in_use || in_params.wave_buffer_count == 0 || !in_params.buffer_mapped ||
323 in_params.voice_drop_flag;
287} 324}
288 325
289bool ServerVoiceInfo::UpdateForCommandGeneration(VoiceContext& voice_context) { 326bool ServerVoiceInfo::UpdateForCommandGeneration(VoiceContext& voice_context) {
@@ -381,7 +418,7 @@ bool ServerVoiceInfo::UpdateParametersForCommandGeneration(
381void ServerVoiceInfo::FlushWaveBuffers( 418void ServerVoiceInfo::FlushWaveBuffers(
382 u8 flush_count, std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& dsp_voice_states, 419 u8 flush_count, std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& dsp_voice_states,
383 s32 channel_count) { 420 s32 channel_count) {
384 auto wave_head = in_params.wave_bufffer_head; 421 auto wave_head = in_params.wave_buffer_head;
385 422
386 for (u8 i = 0; i < flush_count; i++) { 423 for (u8 i = 0; i < flush_count; i++) {
387 in_params.wave_buffer[wave_head].sent_to_dsp = true; 424 in_params.wave_buffer[wave_head].sent_to_dsp = true;
@@ -401,6 +438,17 @@ bool ServerVoiceInfo::HasValidWaveBuffer(const VoiceState* state) const {
401 return std::find(valid_wb.begin(), valid_wb.end(), true) != valid_wb.end(); 438 return std::find(valid_wb.begin(), valid_wb.end(), true) != valid_wb.end();
402} 439}
403 440
441void ServerVoiceInfo::SetWaveBufferCompleted(VoiceState& dsp_state,
442 const ServerWaveBuffer& wave_buffer) {
443 dsp_state.is_wave_buffer_valid[dsp_state.wave_buffer_index] = false;
444 dsp_state.wave_buffer_consumed++;
445 dsp_state.wave_buffer_index = (dsp_state.wave_buffer_index + 1) % AudioCommon::MAX_WAVE_BUFFERS;
446 dsp_state.loop_count = 0;
447 if (wave_buffer.end_of_stream) {
448 dsp_state.played_sample_count = 0;
449 }
450}
451
404VoiceContext::VoiceContext(std::size_t voice_count_) : voice_count{voice_count_} { 452VoiceContext::VoiceContext(std::size_t voice_count_) : voice_count{voice_count_} {
405 for (std::size_t i = 0; i < voice_count; i++) { 453 for (std::size_t i = 0; i < voice_count; i++) {
406 voice_channel_resources.emplace_back(static_cast<s32>(i)); 454 voice_channel_resources.emplace_back(static_cast<s32>(i));
diff --git a/src/audio_core/voice_context.h b/src/audio_core/voice_context.h
index 70359cadb..e1050897b 100644
--- a/src/audio_core/voice_context.h
+++ b/src/audio_core/voice_context.h
@@ -60,10 +60,12 @@ struct WaveBuffer {
60 u8 is_looping{}; 60 u8 is_looping{};
61 u8 end_of_stream{}; 61 u8 end_of_stream{};
62 u8 sent_to_server{}; 62 u8 sent_to_server{};
63 INSERT_PADDING_BYTES(5); 63 INSERT_PADDING_BYTES(1);
64 s32 loop_count{};
64 u64 context_address{}; 65 u64 context_address{};
65 u64 context_size{}; 66 u64 context_size{};
66 INSERT_PADDING_BYTES(8); 67 u32 loop_start_sample{};
68 u32 loop_end_sample{};
67}; 69};
68static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer is an invalid size"); 70static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer is an invalid size");
69 71
@@ -76,6 +78,9 @@ struct ServerWaveBuffer {
76 bool end_of_stream{}; 78 bool end_of_stream{};
77 VAddr context_address{}; 79 VAddr context_address{};
78 std::size_t context_size{}; 80 std::size_t context_size{};
81 s32 loop_count{};
82 u32 loop_start_sample{};
83 u32 loop_end_sample{};
79 bool sent_to_dsp{true}; 84 bool sent_to_dsp{true};
80}; 85};
81 86
@@ -108,6 +113,7 @@ struct VoiceState {
108 u32 external_context_size; 113 u32 external_context_size;
109 bool is_external_context_used; 114 bool is_external_context_used;
110 bool voice_dropped; 115 bool voice_dropped;
116 s32 loop_count;
111}; 117};
112 118
113class VoiceChannelResource { 119class VoiceChannelResource {
@@ -206,7 +212,7 @@ public:
206 float last_volume{}; 212 float last_volume{};
207 std::array<BiquadFilterParameter, AudioCommon::MAX_BIQUAD_FILTERS> biquad_filter{}; 213 std::array<BiquadFilterParameter, AudioCommon::MAX_BIQUAD_FILTERS> biquad_filter{};
208 s32 wave_buffer_count{}; 214 s32 wave_buffer_count{};
209 s16 wave_bufffer_head{}; 215 s16 wave_buffer_head{};
210 INSERT_PADDING_BYTES(2); 216 INSERT_PADDING_BYTES(2);
211 BehaviorFlags behavior_flags{}; 217 BehaviorFlags behavior_flags{};
212 VAddr additional_params_address{}; 218 VAddr additional_params_address{};
@@ -252,6 +258,7 @@ public:
252 void FlushWaveBuffers(u8 flush_count, 258 void FlushWaveBuffers(u8 flush_count,
253 std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& dsp_voice_states, 259 std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>& dsp_voice_states,
254 s32 channel_count); 260 s32 channel_count);
261 void SetWaveBufferCompleted(VoiceState& dsp_state, const ServerWaveBuffer& wave_buffer);
255 262
256private: 263private:
257 std::vector<s16> stored_samples; 264 std::vector<s16> stored_samples;
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 800feba6e..7583d68b2 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -96,7 +96,7 @@ private:
96 void RequestUpdateImpl(Kernel::HLERequestContext& ctx) { 96 void RequestUpdateImpl(Kernel::HLERequestContext& ctx) {
97 LOG_DEBUG(Service_Audio, "(STUBBED) called"); 97 LOG_DEBUG(Service_Audio, "(STUBBED) called");
98 98
99 std::vector<u8> output_params(ctx.GetWriteBufferSize()); 99 std::vector<u8> output_params(ctx.GetWriteBufferSize(), 0);
100 auto result = renderer->UpdateAudioRenderer(ctx.ReadBuffer(), output_params); 100 auto result = renderer->UpdateAudioRenderer(ctx.ReadBuffer(), output_params);
101 101
102 if (result.IsSuccess()) { 102 if (result.IsSuccess()) {
@@ -110,17 +110,19 @@ private:
110 void Start(Kernel::HLERequestContext& ctx) { 110 void Start(Kernel::HLERequestContext& ctx) {
111 LOG_WARNING(Service_Audio, "(STUBBED) called"); 111 LOG_WARNING(Service_Audio, "(STUBBED) called");
112 112
113 IPC::ResponseBuilder rb{ctx, 2}; 113 const auto result = renderer->Start();
114 114
115 rb.Push(ResultSuccess); 115 IPC::ResponseBuilder rb{ctx, 2};
116 rb.Push(result);
116 } 117 }
117 118
118 void Stop(Kernel::HLERequestContext& ctx) { 119 void Stop(Kernel::HLERequestContext& ctx) {
119 LOG_WARNING(Service_Audio, "(STUBBED) called"); 120 LOG_WARNING(Service_Audio, "(STUBBED) called");
120 121
121 IPC::ResponseBuilder rb{ctx, 2}; 122 const auto result = renderer->Stop();
122 123
123 rb.Push(ResultSuccess); 124 IPC::ResponseBuilder rb{ctx, 2};
125 rb.Push(result);
124 } 126 }
125 127
126 void QuerySystemEvent(Kernel::HLERequestContext& ctx) { 128 void QuerySystemEvent(Kernel::HLERequestContext& ctx) {