diff options
| -rw-r--r-- | src/audio_core/command_generator.cpp | 123 | ||||
| -rw-r--r-- | src/audio_core/command_generator.h | 8 |
2 files changed, 101 insertions, 30 deletions
diff --git a/src/audio_core/command_generator.cpp b/src/audio_core/command_generator.cpp index 0c3b278ea..8f89292be 100644 --- a/src/audio_core/command_generator.cpp +++ b/src/audio_core/command_generator.cpp | |||
| @@ -46,6 +46,24 @@ void ApplyGainWithoutDelta(s32* output, const s32* input, s32 gain, s32 sample_c | |||
| 46 | } | 46 | } |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | s32 ApplyMixDepop(s32* output, s32 first_sample, s32 delta, s32 sample_count) { | ||
| 50 | const bool positive = first_sample > 0; | ||
| 51 | auto final_sample = std::abs(first_sample); | ||
| 52 | for (s32 i = 0; i < sample_count; i++) { | ||
| 53 | final_sample = static_cast<s32>((static_cast<s64>(final_sample) * delta) >> 15); | ||
| 54 | if (positive) { | ||
| 55 | output[i] += final_sample; | ||
| 56 | } else { | ||
| 57 | output[i] -= final_sample; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | if (positive) { | ||
| 61 | return final_sample; | ||
| 62 | } else { | ||
| 63 | return -final_sample; | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 49 | } // namespace | 67 | } // namespace |
| 50 | 68 | ||
| 51 | CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_params, | 69 | CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_params, |
| @@ -55,12 +73,15 @@ CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_p | |||
| 55 | splitter_context(splitter_context), memory(memory), | 73 | splitter_context(splitter_context), memory(memory), |
| 56 | mix_buffer((worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT) * | 74 | mix_buffer((worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT) * |
| 57 | worker_params.sample_count), | 75 | worker_params.sample_count), |
| 58 | sample_buffer(MIX_BUFFER_SIZE) {} | 76 | sample_buffer(MIX_BUFFER_SIZE), |
| 77 | depop_buffer((worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT) * | ||
| 78 | worker_params.sample_count) {} | ||
| 59 | CommandGenerator::~CommandGenerator() = default; | 79 | CommandGenerator::~CommandGenerator() = default; |
| 60 | 80 | ||
| 61 | void CommandGenerator::ClearMixBuffers() { | 81 | void CommandGenerator::ClearMixBuffers() { |
| 62 | std::fill(mix_buffer.begin(), mix_buffer.end(), 0); | 82 | std::fill(mix_buffer.begin(), mix_buffer.end(), 0); |
| 63 | std::fill(sample_buffer.begin(), sample_buffer.end(), 0); | 83 | std::fill(sample_buffer.begin(), sample_buffer.end(), 0); |
| 84 | // std::fill(depop_buffer.begin(), depop_buffer.end(), 0); | ||
| 64 | } | 85 | } |
| 65 | 86 | ||
| 66 | void CommandGenerator::GenerateVoiceCommands() { | 87 | void CommandGenerator::GenerateVoiceCommands() { |
| @@ -195,32 +216,39 @@ void CommandGenerator::GenerateDataSourceCommand(ServerVoiceInfo& voice_info, Vo | |||
| 195 | auto& in_params = voice_info.GetInParams(); | 216 | auto& in_params = voice_info.GetInParams(); |
| 196 | const auto depop = in_params.should_depop; | 217 | const auto depop = in_params.should_depop; |
| 197 | 218 | ||
| 198 | if (in_params.mix_id != AudioCommon::NO_MIX) { | ||
| 199 | [[maybe_unused]] auto& mix_info = mix_context.GetInfo(in_params.mix_id); | ||
| 200 | // mix_info. | ||
| 201 | // TODO(ogniK): Depop to destination mix | ||
| 202 | } else if (in_params.splitter_info_id != AudioCommon::NO_SPLITTER) { | ||
| 203 | // TODO(ogniK): Depop to splitter | ||
| 204 | } | ||
| 205 | |||
| 206 | if (depop) { | 219 | if (depop) { |
| 207 | return; | 220 | if (in_params.mix_id != AudioCommon::NO_MIX) { |
| 208 | } | 221 | auto& mix_info = mix_context.GetInfo(in_params.mix_id); |
| 209 | 222 | const auto& mix_in = mix_info.GetInParams(); | |
| 210 | switch (in_params.sample_format) { | 223 | GenerateDepopPrepareCommand(dsp_state, mix_in.buffer_count, mix_in.buffer_offset); |
| 211 | case SampleFormat::Pcm16: | 224 | } else if (in_params.splitter_info_id != AudioCommon::NO_SPLITTER) { |
| 212 | DecodeFromWaveBuffers(voice_info, GetChannelMixBuffer(channel), dsp_state, channel, | 225 | s32 index{}; |
| 213 | worker_params.sample_rate, worker_params.sample_count, | 226 | while (const auto* destination = |
| 214 | in_params.node_id); | 227 | GetDestinationData(in_params.splitter_info_id, index++)) { |
| 215 | break; | 228 | if (!destination->IsConfigured()) { |
| 216 | case SampleFormat::Adpcm: | 229 | continue; |
| 217 | ASSERT(channel == 0 && in_params.channel_count == 1); | 230 | } |
| 218 | DecodeFromWaveBuffers(voice_info, GetChannelMixBuffer(0), dsp_state, 0, | 231 | auto& mix_info = mix_context.GetInfo(destination->GetMixId()); |
| 219 | worker_params.sample_rate, worker_params.sample_count, | 232 | const auto& mix_in = mix_info.GetInParams(); |
| 220 | in_params.node_id); | 233 | GenerateDepopPrepareCommand(dsp_state, mix_in.buffer_count, mix_in.buffer_offset); |
| 221 | break; | 234 | } |
| 222 | default: | 235 | } |
| 223 | UNREACHABLE_MSG("Unimplemented sample format={}", in_params.sample_format); | 236 | } else { |
| 237 | switch (in_params.sample_format) { | ||
| 238 | case SampleFormat::Pcm16: | ||
| 239 | DecodeFromWaveBuffers(voice_info, GetChannelMixBuffer(channel), dsp_state, channel, | ||
| 240 | worker_params.sample_rate, worker_params.sample_count, | ||
| 241 | in_params.node_id); | ||
| 242 | break; | ||
| 243 | case SampleFormat::Adpcm: | ||
| 244 | ASSERT(channel == 0 && in_params.channel_count == 1); | ||
| 245 | DecodeFromWaveBuffers(voice_info, GetChannelMixBuffer(0), dsp_state, 0, | ||
| 246 | worker_params.sample_rate, worker_params.sample_count, | ||
| 247 | in_params.node_id); | ||
| 248 | break; | ||
| 249 | default: | ||
| 250 | UNREACHABLE_MSG("Unimplemented sample format={}", in_params.sample_format); | ||
| 251 | } | ||
| 224 | } | 252 | } |
| 225 | } | 253 | } |
| 226 | 254 | ||
| @@ -281,6 +309,34 @@ void AudioCore::CommandGenerator::GenerateBiquadFilterCommand( | |||
| 281 | state = {s0, s1}; | 309 | state = {s0, s1}; |
| 282 | } | 310 | } |
| 283 | 311 | ||
| 312 | void CommandGenerator::GenerateDepopPrepareCommand(VoiceState& dsp_state, | ||
| 313 | std::size_t mix_buffer_count, | ||
| 314 | std::size_t mix_buffer_offset) { | ||
| 315 | for (std::size_t i = 0; i < mix_buffer_count; i++) { | ||
| 316 | auto& sample = dsp_state.previous_samples[i]; | ||
| 317 | if (sample != 0) { | ||
| 318 | depop_buffer[mix_buffer_offset + i] += sample; | ||
| 319 | sample = 0; | ||
| 320 | } | ||
| 321 | } | ||
| 322 | } | ||
| 323 | |||
| 324 | void CommandGenerator::GenerateDepopForMixBuffersCommand(std::size_t mix_buffer_count, | ||
| 325 | std::size_t mix_buffer_offset, | ||
| 326 | s32 sample_rate) { | ||
| 327 | const std::size_t end_offset = | ||
| 328 | std::min(mix_buffer_offset + mix_buffer_count, GetTotalMixBufferCount()); | ||
| 329 | const s32 delta = sample_rate == 48000 ? 0x7B29 : 0x78CB; | ||
| 330 | for (std::size_t i = mix_buffer_offset; i < end_offset; i++) { | ||
| 331 | if (depop_buffer[i] == 0) { | ||
| 332 | continue; | ||
| 333 | } | ||
| 334 | |||
| 335 | depop_buffer[i] = | ||
| 336 | ApplyMixDepop(GetMixBuffer(i), depop_buffer[i], delta, worker_params.sample_count); | ||
| 337 | } | ||
| 338 | } | ||
| 339 | |||
| 284 | ServerSplitterDestinationData* CommandGenerator::GetDestinationData(s32 splitter_id, s32 index) { | 340 | ServerSplitterDestinationData* CommandGenerator::GetDestinationData(s32 splitter_id, s32 index) { |
| 285 | if (splitter_id == AudioCommon::NO_SPLITTER) { | 341 | if (splitter_id == AudioCommon::NO_SPLITTER) { |
| 286 | return nullptr; | 342 | return nullptr; |
| @@ -338,7 +394,9 @@ void CommandGenerator::GenerateSubMixCommand(ServerMixInfo& mix_info) { | |||
| 338 | if (dumping_frame) { | 394 | if (dumping_frame) { |
| 339 | LOG_DEBUG(Audio, "(DSP_TRACE) GenerateSubMixCommand"); | 395 | LOG_DEBUG(Audio, "(DSP_TRACE) GenerateSubMixCommand"); |
| 340 | } | 396 | } |
| 341 | // TODO(ogniK): Depop | 397 | auto& in_params = mix_info.GetInParams(); |
| 398 | GenerateDepopForMixBuffersCommand(in_params.buffer_count, in_params.buffer_offset, | ||
| 399 | in_params.sample_rate); | ||
| 342 | // TODO(ogniK): Effects | 400 | // TODO(ogniK): Effects |
| 343 | GenerateMixCommands(mix_info); | 401 | GenerateMixCommands(mix_info); |
| 344 | } | 402 | } |
| @@ -412,10 +470,13 @@ void CommandGenerator::GenerateFinalMixCommand() { | |||
| 412 | if (dumping_frame) { | 470 | if (dumping_frame) { |
| 413 | LOG_DEBUG(Audio, "(DSP_TRACE) GenerateFinalMixCommand"); | 471 | LOG_DEBUG(Audio, "(DSP_TRACE) GenerateFinalMixCommand"); |
| 414 | } | 472 | } |
| 415 | // TODO(ogniK): Depop | ||
| 416 | // TODO(ogniK): Effects | ||
| 417 | auto& mix_info = mix_context.GetFinalMixInfo(); | 473 | auto& mix_info = mix_context.GetFinalMixInfo(); |
| 418 | const auto in_params = mix_info.GetInParams(); | 474 | const auto in_params = mix_info.GetInParams(); |
| 475 | |||
| 476 | GenerateDepopForMixBuffersCommand(in_params.buffer_count, in_params.buffer_offset, | ||
| 477 | in_params.sample_rate); | ||
| 478 | // TODO(ogniK): Effects | ||
| 479 | |||
| 419 | for (s32 i = 0; i < in_params.buffer_count; i++) { | 480 | for (s32 i = 0; i < in_params.buffer_count; i++) { |
| 420 | const s32 gain = static_cast<s32>(in_params.volume * 32768.0f); | 481 | const s32 gain = static_cast<s32>(in_params.volume * 32768.0f); |
| 421 | if (dumping_frame) { | 482 | if (dumping_frame) { |
| @@ -541,6 +602,10 @@ std::size_t CommandGenerator::GetMixChannelBufferOffset(s32 channel) const { | |||
| 541 | return worker_params.mix_buffer_count + channel; | 602 | return worker_params.mix_buffer_count + channel; |
| 542 | } | 603 | } |
| 543 | 604 | ||
| 605 | std::size_t CommandGenerator::GetTotalMixBufferCount() const { | ||
| 606 | return worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT; | ||
| 607 | } | ||
| 608 | |||
| 544 | s32* CommandGenerator::GetChannelMixBuffer(s32 channel) { | 609 | s32* CommandGenerator::GetChannelMixBuffer(s32 channel) { |
| 545 | return GetMixBuffer(worker_params.mix_buffer_count + channel); | 610 | return GetMixBuffer(worker_params.mix_buffer_count + channel); |
| 546 | } | 611 | } |
diff --git a/src/audio_core/command_generator.h b/src/audio_core/command_generator.h index 3f49c1303..656ad8143 100644 --- a/src/audio_core/command_generator.h +++ b/src/audio_core/command_generator.h | |||
| @@ -43,6 +43,8 @@ public: | |||
| 43 | const s32* GetMixBuffer(std::size_t index) const; | 43 | const s32* GetMixBuffer(std::size_t index) const; |
| 44 | std::size_t GetMixChannelBufferOffset(s32 channel) const; | 44 | std::size_t GetMixChannelBufferOffset(s32 channel) const; |
| 45 | 45 | ||
| 46 | std::size_t GetTotalMixBufferCount() const; | ||
| 47 | |||
| 46 | private: | 48 | private: |
| 47 | void GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 channel); | 49 | void GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 channel); |
| 48 | void GenerateBiquadFilterCommandForVoice(ServerVoiceInfo& voice_info, VoiceState& dsp_state, | 50 | void GenerateBiquadFilterCommandForVoice(ServerVoiceInfo& voice_info, VoiceState& dsp_state, |
| @@ -61,7 +63,10 @@ private: | |||
| 61 | void GenerateBiquadFilterCommand(s32 mix_buffer, const BiquadFilterParameter& params, | 63 | void GenerateBiquadFilterCommand(s32 mix_buffer, const BiquadFilterParameter& params, |
| 62 | std::array<s64, 2>& state, std::size_t input_offset, | 64 | std::array<s64, 2>& state, std::size_t input_offset, |
| 63 | std::size_t output_offset, s32 sample_count, s32 node_id); | 65 | std::size_t output_offset, s32 sample_count, s32 node_id); |
| 64 | void GenerateDepopPrepareCommand(VoiceState& dsp_state); | 66 | void GenerateDepopPrepareCommand(VoiceState& dsp_state, std::size_t mix_buffer_count, |
| 67 | std::size_t mix_buffer_offset); | ||
| 68 | void GenerateDepopForMixBuffersCommand(std::size_t mix_buffer_count, | ||
| 69 | std::size_t mix_buffer_offset, s32 sample_rate); | ||
| 65 | ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index); | 70 | ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index); |
| 66 | 71 | ||
| 67 | // DSP Code | 72 | // DSP Code |
| @@ -79,6 +84,7 @@ private: | |||
| 79 | Core::Memory::Memory& memory; | 84 | Core::Memory::Memory& memory; |
| 80 | std::vector<s32> mix_buffer{}; | 85 | std::vector<s32> mix_buffer{}; |
| 81 | std::vector<s32> sample_buffer{}; | 86 | std::vector<s32> sample_buffer{}; |
| 87 | std::vector<s32> depop_buffer{}; | ||
| 82 | bool dumping_frame{false}; | 88 | bool dumping_frame{false}; |
| 83 | }; | 89 | }; |
| 84 | } // namespace AudioCore | 90 | } // namespace AudioCore |