summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/audio_core/audio_renderer.cpp9
-rw-r--r--src/audio_core/command_generator.cpp187
-rw-r--r--src/audio_core/command_generator.h17
-rw-r--r--src/audio_core/common.h1
-rw-r--r--src/audio_core/effect_context.cpp271
-rw-r--r--src/audio_core/effect_context.h215
-rw-r--r--src/audio_core/info_updater.cpp18
-rw-r--r--src/audio_core/info_updater.h2
-rw-r--r--src/audio_core/mix_context.cpp35
-rw-r--r--src/audio_core/mix_context.h11
10 files changed, 731 insertions, 35 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index a3ff819e1..56dc892b1 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -27,12 +27,13 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory
27 voice_context(params.voice_count), effect_context(params.effect_count), mix_context(), 27 voice_context(params.voice_count), effect_context(params.effect_count), mix_context(),
28 sink_context(params.sink_count), splitter_context(), 28 sink_context(params.sink_count), splitter_context(),
29 voices(params.voice_count), memory{memory_}, 29 voices(params.voice_count), memory{memory_},
30 command_generator(worker_params, voice_context, mix_context, splitter_context, memory), 30 command_generator(worker_params, voice_context, mix_context, splitter_context, effect_context,
31 memory),
31 temp_mix_buffer(AudioCommon::TOTAL_TEMP_MIX_SIZE) { 32 temp_mix_buffer(AudioCommon::TOTAL_TEMP_MIX_SIZE) {
32 behavior_info.SetUserRevision(params.revision); 33 behavior_info.SetUserRevision(params.revision);
33 splitter_context.Initialize(behavior_info, params.splitter_count, 34 splitter_context.Initialize(behavior_info, params.splitter_count,
34 params.num_splitter_send_channels); 35 params.num_splitter_send_channels);
35 mix_context.Initialize(behavior_info, params.submix_count + 1); 36 mix_context.Initialize(behavior_info, params.submix_count + 1, params.effect_count);
36 audio_out = std::make_unique<AudioCore::AudioOut>(); 37 audio_out = std::make_unique<AudioCore::AudioOut>();
37 stream = 38 stream =
38 audio_out->OpenStream(core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS, 39 audio_out->OpenStream(core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
@@ -106,8 +107,8 @@ ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_param
106 } 107 }
107 } 108 }
108 109
109 auto mix_result = 110 auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count,
110 info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count, splitter_context); 111 splitter_context, effect_context);
111 112
112 if (mix_result.IsError()) { 113 if (mix_result.IsError()) {
113 LOG_ERROR(Audio, "Failed to update mix parameters"); 114 LOG_ERROR(Audio, "Failed to update mix parameters");
diff --git a/src/audio_core/command_generator.cpp b/src/audio_core/command_generator.cpp
index 73608c9ed..84782cde6 100644
--- a/src/audio_core/command_generator.cpp
+++ b/src/audio_core/command_generator.cpp
@@ -4,6 +4,7 @@
4 4
5#include "audio_core/algorithm/interpolate.h" 5#include "audio_core/algorithm/interpolate.h"
6#include "audio_core/command_generator.h" 6#include "audio_core/command_generator.h"
7#include "audio_core/effect_context.h"
7#include "audio_core/mix_context.h" 8#include "audio_core/mix_context.h"
8#include "audio_core/voice_context.h" 9#include "audio_core/voice_context.h"
9#include "core/memory.h" 10#include "core/memory.h"
@@ -68,9 +69,10 @@ s32 ApplyMixDepop(s32* output, s32 first_sample, s32 delta, s32 sample_count) {
68 69
69CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_params, 70CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_params,
70 VoiceContext& voice_context, MixContext& mix_context, 71 VoiceContext& voice_context, MixContext& mix_context,
71 SplitterContext& splitter_context, Core::Memory::Memory& memory) 72 SplitterContext& splitter_context, EffectContext& effect_context,
73 Core::Memory::Memory& memory)
72 : worker_params(worker_params), voice_context(voice_context), mix_context(mix_context), 74 : worker_params(worker_params), voice_context(voice_context), mix_context(mix_context),
73 splitter_context(splitter_context), memory(memory), 75 splitter_context(splitter_context), effect_context(effect_context), memory(memory),
74 mix_buffer((worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT) * 76 mix_buffer((worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT) *
75 worker_params.sample_count), 77 worker_params.sample_count),
76 sample_buffer(MIX_BUFFER_SIZE), 78 sample_buffer(MIX_BUFFER_SIZE),
@@ -338,6 +340,120 @@ void CommandGenerator::GenerateDepopForMixBuffersCommand(std::size_t mix_buffer_
338 } 340 }
339} 341}
340 342
343void CommandGenerator::GenerateEffectCommand(ServerMixInfo& mix_info) {
344 const std::size_t effect_count = effect_context.GetCount();
345 const auto buffer_offset = mix_info.GetInParams().buffer_offset;
346 for (std::size_t i = 0; i < effect_count; i++) {
347 const auto index = mix_info.GetEffectOrder(i);
348 if (index == AudioCommon::NO_EFFECT_ORDER) {
349 break;
350 }
351 auto* info = effect_context.GetInfo(index);
352 const auto type = info->GetType();
353
354 // TODO(ogniK): Finish remaining effects
355 switch (type) {
356 case EffectType::Aux:
357 GenerateAuxCommand(buffer_offset, info, info->IsEnabled());
358 break;
359 case EffectType::I3dl2Reverb:
360 GenerateI3dl2ReverbEffectCommand(buffer_offset, info, info->IsEnabled());
361 break;
362 case EffectType::BiquadFilter:
363 GenerateBiquadFilterEffectCommand(buffer_offset, info, info->IsEnabled());
364 break;
365 default:
366 break;
367 }
368
369 info->UpdateForCommandGeneration();
370 }
371}
372
373void CommandGenerator::GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, EffectBase* info,
374 bool enabled) {
375 if (!enabled) {
376 return;
377 }
378 const auto& params = dynamic_cast<EffectI3dl2Reverb*>(info)->GetParams();
379 const auto channel_count = params.channel_count;
380 for (s32 i = 0; i < channel_count; i++) {
381 // TODO(ogniK): Actually implement reverb
382 if (params.input[i] != params.output[i]) {
383 const auto* input = GetMixBuffer(mix_buffer_offset + params.input[i]);
384 auto* output = GetMixBuffer(mix_buffer_offset + params.output[i]);
385 ApplyMix<1>(output, input, 32768, worker_params.sample_count);
386 }
387 }
388}
389
390void CommandGenerator::GenerateBiquadFilterEffectCommand(s32 mix_buffer_offset, EffectBase* info,
391 bool enabled) {
392 if (!enabled) {
393 return;
394 }
395 const auto& params = dynamic_cast<EffectBiquadFilter*>(info)->GetParams();
396 const auto channel_count = params.channel_count;
397 for (s32 i = 0; i < channel_count; i++) {
398 // TODO(ogniK): Actually implement biquad filter
399 if (params.input[i] != params.output[i]) {
400 const auto* input = GetMixBuffer(mix_buffer_offset + params.input[i]);
401 auto* output = GetMixBuffer(mix_buffer_offset + params.output[i]);
402 ApplyMix<1>(output, input, 32768, worker_params.sample_count);
403 }
404 }
405}
406
407void CommandGenerator::GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled) {
408 auto aux = dynamic_cast<EffectAuxInfo*>(info);
409 const auto& params = aux->GetParams();
410 if (aux->GetSendBuffer() != 0 && aux->GetRecvBuffer() != 0) {
411 const auto max_channels = params.count;
412 u32 offset{};
413 for (u32 channel = 0; channel < max_channels; channel++) {
414 u32 write_count = 0;
415 if (channel == (max_channels - 1)) {
416 write_count = offset + worker_params.sample_count;
417 }
418
419 const auto input_index = params.input_mix_buffers[channel] + mix_buffer_offset;
420 const auto output_index = params.output_mix_buffers[channel] + mix_buffer_offset;
421
422 if (enabled) {
423 AuxInfoDSP send_info{};
424 AuxInfoDSP recv_info{};
425 memory.ReadBlock(aux->GetSendInfo(), &send_info, sizeof(AuxInfoDSP));
426 memory.ReadBlock(aux->GetRecvInfo(), &recv_info, sizeof(AuxInfoDSP));
427
428 WriteAuxBuffer(send_info, aux->GetSendBuffer(), params.sample_count,
429 GetMixBuffer(input_index), worker_params.sample_count, offset,
430 write_count);
431 memory.WriteBlock(aux->GetSendInfo(), &send_info, sizeof(AuxInfoDSP));
432
433 const auto samples_read = ReadAuxBuffer(
434 recv_info, aux->GetRecvBuffer(), params.sample_count,
435 GetMixBuffer(output_index), worker_params.sample_count, offset, write_count);
436 memory.WriteBlock(aux->GetRecvInfo(), &recv_info, sizeof(AuxInfoDSP));
437
438 if (samples_read != worker_params.sample_count &&
439 samples_read <= params.sample_count) {
440 std::memset(GetMixBuffer(output_index), 0, params.sample_count - samples_read);
441 }
442 } else {
443 AuxInfoDSP empty{};
444 memory.WriteBlock(aux->GetSendInfo(), &empty, sizeof(AuxInfoDSP));
445 memory.WriteBlock(aux->GetRecvInfo(), &empty, sizeof(AuxInfoDSP));
446 if (output_index != input_index) {
447 std::memcpy(GetMixBuffer(output_index), GetMixBuffer(input_index),
448 worker_params.sample_count * sizeof(s32));
449 }
450 }
451
452 offset += worker_params.sample_count;
453 }
454 }
455}
456
341ServerSplitterDestinationData* CommandGenerator::GetDestinationData(s32 splitter_id, s32 index) { 457ServerSplitterDestinationData* CommandGenerator::GetDestinationData(s32 splitter_id, s32 index) {
342 if (splitter_id == AudioCommon::NO_SPLITTER) { 458 if (splitter_id == AudioCommon::NO_SPLITTER) {
343 return nullptr; 459 return nullptr;
@@ -345,6 +461,66 @@ ServerSplitterDestinationData* CommandGenerator::GetDestinationData(s32 splitter
345 return splitter_context.GetDestinationData(splitter_id, index); 461 return splitter_context.GetDestinationData(splitter_id, index);
346} 462}
347 463
464s32 CommandGenerator::WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples,
465 const s32* data, u32 sample_count, u32 write_offset,
466 u32 write_count) {
467 if (max_samples == 0) {
468 return 0;
469 }
470 u32 offset = dsp_info.write_offset + write_offset;
471 if (send_buffer == 0 || offset > max_samples) {
472 return 0;
473 }
474
475 std::size_t data_offset{};
476 u32 remaining = sample_count;
477 while (remaining > 0) {
478 // Get position in buffer
479 const auto base = send_buffer + (offset * sizeof(u32));
480 const auto samples_to_grab = std::min(max_samples - offset, remaining);
481 // Write to output
482 memory.WriteBlock(base, (data + data_offset), samples_to_grab * sizeof(u32));
483 offset = (offset + samples_to_grab) % max_samples;
484 remaining -= samples_to_grab;
485 data_offset += samples_to_grab;
486 }
487
488 if (write_count != 0) {
489 dsp_info.write_offset = (dsp_info.write_offset + write_count) % max_samples;
490 }
491 return sample_count;
492}
493
494s32 CommandGenerator::ReadAuxBuffer(AuxInfoDSP& recv_info, VAddr recv_buffer, u32 max_samples,
495 s32* out_data, u32 sample_count, u32 read_offset,
496 u32 read_count) {
497 if (max_samples == 0) {
498 return 0;
499 }
500
501 u32 offset = recv_info.read_offset + read_offset;
502 if (recv_buffer == 0 || offset > max_samples) {
503 return 0;
504 }
505
506 u32 remaining = sample_count;
507 while (remaining > 0) {
508 const auto base = recv_buffer + (offset * sizeof(u32));
509 const auto samples_to_grab = std::min(max_samples - offset, remaining);
510 std::vector<s32> buffer(samples_to_grab);
511 memory.ReadBlock(base, buffer.data(), buffer.size() * sizeof(u32));
512 std::memcpy(out_data, buffer.data(), buffer.size() * sizeof(u32));
513 out_data += samples_to_grab;
514 offset = (offset + samples_to_grab) % max_samples;
515 remaining -= samples_to_grab;
516 }
517
518 if (read_count != 0) {
519 recv_info.read_offset = (recv_info.read_offset + read_count) % max_samples;
520 }
521 return sample_count;
522}
523
348void CommandGenerator::GenerateVolumeRampCommand(float last_volume, float current_volume, 524void CommandGenerator::GenerateVolumeRampCommand(float last_volume, float current_volume,
349 s32 channel, s32 node_id) { 525 s32 channel, s32 node_id) {
350 const auto last = static_cast<s32>(last_volume * 32768.0f); 526 const auto last = static_cast<s32>(last_volume * 32768.0f);
@@ -398,7 +574,9 @@ void CommandGenerator::GenerateSubMixCommand(ServerMixInfo& mix_info) {
398 auto& in_params = mix_info.GetInParams(); 574 auto& in_params = mix_info.GetInParams();
399 GenerateDepopForMixBuffersCommand(in_params.buffer_count, in_params.buffer_offset, 575 GenerateDepopForMixBuffersCommand(in_params.buffer_count, in_params.buffer_offset,
400 in_params.sample_rate); 576 in_params.sample_rate);
401 // TODO(ogniK): Effects 577
578 GenerateEffectCommand(mix_info);
579
402 GenerateMixCommands(mix_info); 580 GenerateMixCommands(mix_info);
403} 581}
404 582
@@ -476,7 +654,8 @@ void CommandGenerator::GenerateFinalMixCommand() {
476 654
477 GenerateDepopForMixBuffersCommand(in_params.buffer_count, in_params.buffer_offset, 655 GenerateDepopForMixBuffersCommand(in_params.buffer_count, in_params.buffer_offset,
478 in_params.sample_rate); 656 in_params.sample_rate);
479 // TODO(ogniK): Effects 657
658 GenerateEffectCommand(mix_info);
480 659
481 for (s32 i = 0; i < in_params.buffer_count; i++) { 660 for (s32 i = 0; i < in_params.buffer_count; i++) {
482 const s32 gain = static_cast<s32>(in_params.volume * 32768.0f); 661 const s32 gain = static_cast<s32>(in_params.volume * 32768.0f);
diff --git a/src/audio_core/command_generator.h b/src/audio_core/command_generator.h
index 656ad8143..967d24078 100644
--- a/src/audio_core/command_generator.h
+++ b/src/audio_core/command_generator.h
@@ -19,14 +19,17 @@ class MixContext;
19class SplitterContext; 19class SplitterContext;
20class ServerSplitterDestinationData; 20class ServerSplitterDestinationData;
21class ServerMixInfo; 21class ServerMixInfo;
22 22class EffectContext;
23class EffectBase;
24struct AuxInfoDSP;
23using MixVolumeBuffer = std::array<float, AudioCommon::MAX_MIX_BUFFERS>; 25using MixVolumeBuffer = std::array<float, AudioCommon::MAX_MIX_BUFFERS>;
24 26
25class CommandGenerator { 27class CommandGenerator {
26public: 28public:
27 explicit CommandGenerator(AudioCommon::AudioRendererParameter& worker_params, 29 explicit CommandGenerator(AudioCommon::AudioRendererParameter& worker_params,
28 VoiceContext& voice_context, MixContext& mix_context, 30 VoiceContext& voice_context, MixContext& mix_context,
29 SplitterContext& splitter_context, Core::Memory::Memory& memory); 31 SplitterContext& splitter_context, EffectContext& effect_context,
32 Core::Memory::Memory& memory);
30 ~CommandGenerator(); 33 ~CommandGenerator();
31 34
32 void ClearMixBuffers(); 35 void ClearMixBuffers();
@@ -67,8 +70,17 @@ private:
67 std::size_t mix_buffer_offset); 70 std::size_t mix_buffer_offset);
68 void GenerateDepopForMixBuffersCommand(std::size_t mix_buffer_count, 71 void GenerateDepopForMixBuffersCommand(std::size_t mix_buffer_count,
69 std::size_t mix_buffer_offset, s32 sample_rate); 72 std::size_t mix_buffer_offset, s32 sample_rate);
73 void GenerateEffectCommand(ServerMixInfo& mix_info);
74 void GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled);
75 void GenerateBiquadFilterEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled);
76 void GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled);
70 ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index); 77 ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index);
71 78
79 s32 WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples, const s32* data,
80 u32 sample_count, u32 write_offset, u32 write_count);
81 s32 ReadAuxBuffer(AuxInfoDSP& recv_info, VAddr recv_buffer, u32 max_samples, s32* out_data,
82 u32 sample_count, u32 read_offset, u32 read_count);
83
72 // DSP Code 84 // DSP Code
73 s32 DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_count, 85 s32 DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_count,
74 s32 channel, std::size_t mix_offset); 86 s32 channel, std::size_t mix_offset);
@@ -81,6 +93,7 @@ private:
81 VoiceContext& voice_context; 93 VoiceContext& voice_context;
82 MixContext& mix_context; 94 MixContext& mix_context;
83 SplitterContext& splitter_context; 95 SplitterContext& splitter_context;
96 EffectContext& effect_context;
84 Core::Memory::Memory& memory; 97 Core::Memory::Memory& memory;
85 std::vector<s32> mix_buffer{}; 98 std::vector<s32> mix_buffer{};
86 std::vector<s32> sample_buffer{}; 99 std::vector<s32> sample_buffer{};
diff --git a/src/audio_core/common.h b/src/audio_core/common.h
index 0731d3eb3..72ebce221 100644
--- a/src/audio_core/common.h
+++ b/src/audio_core/common.h
@@ -26,6 +26,7 @@ constexpr s32 NO_SPLITTER = -1;
26constexpr s32 NO_MIX = 0x7fffffff; 26constexpr s32 NO_MIX = 0x7fffffff;
27constexpr s32 NO_FINAL_MIX = std::numeric_limits<s32>::min(); 27constexpr s32 NO_FINAL_MIX = std::numeric_limits<s32>::min();
28constexpr s32 FINAL_MIX = 0; 28constexpr s32 FINAL_MIX = 0;
29constexpr s32 NO_EFFECT_ORDER = -1;
29constexpr std::size_t TEMP_MIX_BASE_SIZE = 0x3f00; // TODO(ogniK): Work out this constant 30constexpr std::size_t TEMP_MIX_BASE_SIZE = 0x3f00; // TODO(ogniK): Work out this constant
30// Any size checks seem to take the sample history into account 31// Any size checks seem to take the sample history into account
31// and our const ends up being 0x3f04, the 4 bytes are most 32// and our const ends up being 0x3f04, the 4 bytes are most
diff --git a/src/audio_core/effect_context.cpp b/src/audio_core/effect_context.cpp
index 2497d2f32..adfec3df5 100644
--- a/src/audio_core/effect_context.cpp
+++ b/src/audio_core/effect_context.cpp
@@ -6,6 +6,12 @@
6#include "audio_core/effect_context.h" 6#include "audio_core/effect_context.h"
7 7
8namespace AudioCore { 8namespace AudioCore {
9namespace {
10bool ValidChannelCountForEffect(s32 channel_count) {
11 return channel_count == 1 || channel_count == 2 || channel_count == 4 || channel_count == 6;
12}
13} // namespace
14
9EffectContext::EffectContext(std::size_t effect_count) : effect_count(effect_count) { 15EffectContext::EffectContext(std::size_t effect_count) : effect_count(effect_count) {
10 effects.reserve(effect_count); 16 effects.reserve(effect_count);
11 std::generate_n(std::back_inserter(effects), effect_count, 17 std::generate_n(std::back_inserter(effects), effect_count,
@@ -21,24 +27,273 @@ EffectBase* EffectContext::GetInfo(std::size_t i) {
21 return effects.at(i).get(); 27 return effects.at(i).get();
22} 28}
23 29
30EffectBase* EffectContext::RetargetEffect(std::size_t i, EffectType effect) {
31 switch (effect) {
32 case EffectType::Invalid:
33 effects[i] = std::make_unique<EffectStubbed>();
34 break;
35 case EffectType::BufferMixer:
36 effects[i] = std::make_unique<EffectBufferMixer>();
37 break;
38 case EffectType::Aux:
39 effects[i] = std::make_unique<EffectAuxInfo>();
40 break;
41 case EffectType::Delay:
42 effects[i] = std::make_unique<EffectDelay>();
43 break;
44 case EffectType::Reverb:
45 effects[i] = std::make_unique<EffectReverb>();
46 break;
47 case EffectType::I3dl2Reverb:
48 effects[i] = std::make_unique<EffectI3dl2Reverb>();
49 break;
50 case EffectType::BiquadFilter:
51 effects[i] = std::make_unique<EffectBiquadFilter>();
52 break;
53 default:
54 UNREACHABLE_MSG("Unimplemented effect {}", effect);
55 effects[i] = std::make_unique<EffectStubbed>();
56 }
57 return GetInfo(i);
58}
59
24const EffectBase* EffectContext::GetInfo(std::size_t i) const { 60const EffectBase* EffectContext::GetInfo(std::size_t i) const {
25 return effects.at(i).get(); 61 return effects.at(i).get();
26} 62}
27 63
28EffectStubbed::EffectStubbed() : EffectBase::EffectBase() {} 64EffectStubbed::EffectStubbed() : EffectBase::EffectBase(EffectType::Invalid) {}
29EffectStubbed::~EffectStubbed() = default; 65EffectStubbed::~EffectStubbed() = default;
30 66
31void EffectStubbed::Update(EffectInfo::InParams& in_params) { 67void EffectStubbed::Update(EffectInfo::InParams& in_params) {}
32 if (in_params.is_new) { 68void EffectStubbed::UpdateForCommandGeneration() {}
33 usage = UsageStatus::New;
34 }
35}
36 69
37EffectBase::EffectBase() = default; 70EffectBase::EffectBase(EffectType effect_type) : effect_type(effect_type) {}
38EffectBase::~EffectBase() = default; 71EffectBase::~EffectBase() = default;
39 72
40UsageStatus EffectBase::GetUsage() const { 73UsageState EffectBase::GetUsage() const {
41 return usage; 74 return usage;
42} 75}
43 76
77EffectType EffectBase::GetType() const {
78 return effect_type;
79}
80
81bool EffectBase::IsEnabled() const {
82 return enabled;
83}
84
85s32 EffectBase::GetMixID() const {
86 return mix_id;
87}
88
89s32 EffectBase::GetProcessingOrder() const {
90 return processing_order;
91}
92
93EffectI3dl2Reverb::EffectI3dl2Reverb() : EffectGeneric::EffectGeneric(EffectType::I3dl2Reverb) {}
94EffectI3dl2Reverb::~EffectI3dl2Reverb() = default;
95
96void EffectI3dl2Reverb::Update(EffectInfo::InParams& in_params) {
97 auto& internal_params = GetParams();
98 const auto* reverb_params = reinterpret_cast<I3dl2ReverbParams*>(in_params.raw.data());
99 if (!ValidChannelCountForEffect(reverb_params->max_channels)) {
100 UNREACHABLE_MSG("Invalid reverb max channel count {}", reverb_params->max_channels);
101 return;
102 }
103
104 const auto last_status = internal_params.status;
105 mix_id = in_params.mix_id;
106 processing_order = in_params.processing_order;
107 internal_params = *reverb_params;
108 if (!ValidChannelCountForEffect(reverb_params->channel_count)) {
109 internal_params.channel_count = internal_params.max_channels;
110 }
111 enabled = in_params.is_enabled;
112 if (last_status != ParameterStatus::Updated) {
113 internal_params.status = last_status;
114 }
115
116 if (in_params.is_new || skipped) {
117 usage = UsageState::Initialized;
118 internal_params.status = ParameterStatus::Initialized;
119 skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0;
120 }
121}
122
123void EffectI3dl2Reverb::UpdateForCommandGeneration() {
124 if (enabled) {
125 usage = UsageState::Running;
126 } else {
127 usage = UsageState::Stopped;
128 }
129 GetParams().status = ParameterStatus::Updated;
130}
131
132EffectBiquadFilter::EffectBiquadFilter() : EffectGeneric::EffectGeneric(EffectType::BiquadFilter) {}
133EffectBiquadFilter::~EffectBiquadFilter() = default;
134
135void EffectBiquadFilter::Update(EffectInfo::InParams& in_params) {
136 auto& internal_params = GetParams();
137 const auto* biquad_params = reinterpret_cast<BiquadFilterParams*>(in_params.raw.data());
138 mix_id = in_params.mix_id;
139 processing_order = in_params.processing_order;
140 internal_params = *biquad_params;
141 enabled = in_params.is_enabled;
142}
143
144void EffectBiquadFilter::UpdateForCommandGeneration() {
145 if (enabled) {
146 usage = UsageState::Running;
147 } else {
148 usage = UsageState::Stopped;
149 }
150 GetParams().status = ParameterStatus::Updated;
151}
152
153EffectAuxInfo::EffectAuxInfo() : EffectGeneric::EffectGeneric(EffectType::Aux) {}
154EffectAuxInfo::~EffectAuxInfo() = default;
155
156void EffectAuxInfo::Update(EffectInfo::InParams& in_params) {
157 const auto* aux_params = reinterpret_cast<AuxInfo*>(in_params.raw.data());
158 mix_id = in_params.mix_id;
159 processing_order = in_params.processing_order;
160 GetParams() = *aux_params;
161 enabled = in_params.is_enabled;
162
163 if (in_params.is_new || skipped) {
164 skipped = aux_params->send_buffer_info == 0 || aux_params->return_buffer_info == 0;
165 if (skipped) {
166 return;
167 }
168
169 // There's two AuxInfos which are an identical size, the first one is managed by the cpu,
170 // the second is managed by the dsp. All we care about is managing the DSP one
171 send_info = aux_params->send_buffer_info + sizeof(AuxInfoDSP);
172 send_buffer = aux_params->send_buffer_info + (sizeof(AuxInfoDSP) * 2);
173
174 recv_info = aux_params->return_buffer_info + sizeof(AuxInfoDSP);
175 recv_buffer = aux_params->return_buffer_info + (sizeof(AuxInfoDSP) * 2);
176 }
177}
178
179void EffectAuxInfo::UpdateForCommandGeneration() {
180 if (enabled) {
181 usage = UsageState::Running;
182 } else {
183 usage = UsageState::Stopped;
184 }
185}
186
187const VAddr EffectAuxInfo::GetSendInfo() const {
188 return send_info;
189}
190
191const VAddr EffectAuxInfo::GetSendBuffer() const {
192 return send_buffer;
193}
194
195const VAddr EffectAuxInfo::GetRecvInfo() const {
196 return recv_info;
197}
198
199const VAddr EffectAuxInfo::GetRecvBuffer() const {
200 return recv_buffer;
201}
202
203EffectDelay::EffectDelay() : EffectGeneric::EffectGeneric(EffectType::Delay) {}
204EffectDelay::~EffectDelay() = default;
205
206void EffectDelay::Update(EffectInfo::InParams& in_params) {
207 const auto* delay_params = reinterpret_cast<DelayParams*>(in_params.raw.data());
208 auto& internal_params = GetParams();
209 if (!ValidChannelCountForEffect(delay_params->max_channels)) {
210 return;
211 }
212
213 const auto last_status = internal_params.status;
214 mix_id = in_params.mix_id;
215 processing_order = in_params.processing_order;
216 internal_params = *delay_params;
217 if (!ValidChannelCountForEffect(delay_params->channels)) {
218 internal_params.channels = internal_params.max_channels;
219 }
220 enabled = in_params.is_enabled;
221
222 if (last_status != ParameterStatus::Updated) {
223 internal_params.status = last_status;
224 }
225
226 if (in_params.is_new || skipped) {
227 usage = UsageState::Initialized;
228 internal_params.status = ParameterStatus::Initialized;
229 skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0;
230 }
231}
232
233void EffectDelay::UpdateForCommandGeneration() {
234 if (enabled) {
235 usage = UsageState::Running;
236 } else {
237 usage = UsageState::Stopped;
238 }
239 GetParams().status = ParameterStatus::Updated;
240}
241
242EffectBufferMixer::EffectBufferMixer() : EffectGeneric::EffectGeneric(EffectType::BufferMixer) {}
243EffectBufferMixer::~EffectBufferMixer() = default;
244
245void EffectBufferMixer::Update(EffectInfo::InParams& in_params) {
246 mix_id = in_params.mix_id;
247 processing_order = in_params.processing_order;
248 GetParams() = *reinterpret_cast<BufferMixerParams*>(in_params.raw.data());
249 enabled = in_params.is_enabled;
250}
251
252void EffectBufferMixer::UpdateForCommandGeneration() {
253 if (enabled) {
254 usage = UsageState::Running;
255 } else {
256 usage = UsageState::Stopped;
257 }
258}
259
260EffectReverb::EffectReverb() : EffectGeneric::EffectGeneric(EffectType::Reverb) {}
261EffectReverb::~EffectReverb() = default;
262
263void EffectReverb::Update(EffectInfo::InParams& in_params) {
264 const auto* reverb_params = reinterpret_cast<ReverbParams*>(in_params.raw.data());
265 auto& internal_params = GetParams();
266 if (!ValidChannelCountForEffect(reverb_params->max_channels)) {
267 return;
268 }
269
270 const auto last_status = internal_params.status;
271 mix_id = in_params.mix_id;
272 processing_order = in_params.processing_order;
273 internal_params = *reverb_params;
274 if (!ValidChannelCountForEffect(reverb_params->channels)) {
275 internal_params.channels = internal_params.max_channels;
276 }
277 enabled = in_params.is_enabled;
278
279 if (last_status != ParameterStatus::Updated) {
280 internal_params.status = last_status;
281 }
282
283 if (in_params.is_new || skipped) {
284 usage = UsageState::Initialized;
285 internal_params.status = ParameterStatus::Initialized;
286 skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0;
287 }
288}
289
290void EffectReverb::UpdateForCommandGeneration() {
291 if (enabled) {
292 usage = UsageState::Running;
293 } else {
294 usage = UsageState::Stopped;
295 }
296 GetParams().status = ParameterStatus::Updated;
297}
298
44} // namespace AudioCore 299} // namespace AudioCore
diff --git a/src/audio_core/effect_context.h b/src/audio_core/effect_context.h
index e3c367296..2f2da72dd 100644
--- a/src/audio_core/effect_context.h
+++ b/src/audio_core/effect_context.h
@@ -31,6 +31,19 @@ enum class UsageStatus : u8 {
31 Removed = 4, 31 Removed = 4,
32}; 32};
33 33
34enum class UsageState {
35 Invalid = 0,
36 Initialized = 1,
37 Running = 2,
38 Stopped = 3,
39};
40
41enum class ParameterStatus : u8 {
42 Initialized = 0,
43 Updating = 1,
44 Updated = 2,
45};
46
34struct BufferMixerParams { 47struct BufferMixerParams {
35 std::array<s8, AudioCommon::MAX_MIX_BUFFERS> input{}; 48 std::array<s8, AudioCommon::MAX_MIX_BUFFERS> input{};
36 std::array<s8, AudioCommon::MAX_MIX_BUFFERS> output{}; 49 std::array<s8, AudioCommon::MAX_MIX_BUFFERS> output{};
@@ -39,6 +52,14 @@ struct BufferMixerParams {
39}; 52};
40static_assert(sizeof(BufferMixerParams) == 0x94, "BufferMixerParams is an invalid size"); 53static_assert(sizeof(BufferMixerParams) == 0x94, "BufferMixerParams is an invalid size");
41 54
55struct AuxInfoDSP {
56 u32_le read_offset{};
57 u32_le write_offset{};
58 u32_le remaining{};
59 INSERT_PADDING_WORDS(13);
60};
61static_assert(sizeof(AuxInfoDSP) == 0x40, "AuxInfoDSP is an invalid size");
62
42struct AuxInfo { 63struct AuxInfo {
43 std::array<s8, AudioCommon::MAX_MIX_BUFFERS> input_mix_buffers{}; 64 std::array<s8, AudioCommon::MAX_MIX_BUFFERS> input_mix_buffers{};
44 std::array<s8, AudioCommon::MAX_MIX_BUFFERS> output_mix_buffers{}; 65 std::array<s8, AudioCommon::MAX_MIX_BUFFERS> output_mix_buffers{};
@@ -54,6 +75,81 @@ struct AuxInfo {
54}; 75};
55static_assert(sizeof(AuxInfo) == 0x60, "AuxInfo is an invalid size"); 76static_assert(sizeof(AuxInfo) == 0x60, "AuxInfo is an invalid size");
56 77
78struct I3dl2ReverbParams {
79 std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> input{};
80 std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> output{};
81 u16_le max_channels{};
82 u16_le channel_count{};
83 INSERT_PADDING_BYTES(1);
84 u32_le sample_rate{};
85 f32 room_hf{};
86 f32 hf_reference{};
87 f32 decay_time{};
88 f32 hf_decay_ratio{};
89 f32 room{};
90 f32 reflection{};
91 f32 reverb{};
92 f32 diffusion{};
93 f32 reflection_delay{};
94 f32 reverb_delay{};
95 f32 density{};
96 f32 dry_gain{};
97 ParameterStatus status{};
98 INSERT_PADDING_BYTES(3);
99};
100static_assert(sizeof(I3dl2ReverbParams) == 0x4c, "I3dl2ReverbParams is an invalid size");
101
102struct BiquadFilterParams {
103 std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> input{};
104 std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> output{};
105 std::array<s16_le, 3> numerator;
106 std::array<s16_le, 2> denominator;
107 s8 channel_count{};
108 ParameterStatus status{};
109};
110static_assert(sizeof(BiquadFilterParams) == 0x18, "BiquadFilterParams is an invalid size");
111
112struct DelayParams {
113 std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> input{};
114 std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> output{};
115 u16_le max_channels{};
116 u16_le channels{};
117 s32_le max_delay{};
118 s32_le delay{};
119 s32_le sample_rate{};
120 s32_le gain{};
121 s32_le feedback_gain{};
122 s32_le out_gain{};
123 s32_le dry_gain{};
124 s32_le channel_spread{};
125 s32_le low_pass{};
126 ParameterStatus status{};
127 INSERT_PADDING_BYTES(3);
128};
129static_assert(sizeof(DelayParams) == 0x38, "DelayParams is an invalid size");
130
131struct ReverbParams {
132 std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> input{};
133 std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> output{};
134 u16_le max_channels{};
135 u16_le channels{};
136 s32_le sample_rate{};
137 s32_le mode0{};
138 s32_le mode0_gain{};
139 s32_le pre_delay{};
140 s32_le mode1{};
141 s32_le mode1_gain{};
142 s32_le decay{};
143 s32_le hf_decay_ratio{};
144 s32_le coloration{};
145 s32_le reverb_gain{};
146 s32_le out_gain{};
147 s32_le dry_gain{};
148 ParameterStatus status{};
149 INSERT_PADDING_BYTES(3);
150};
151static_assert(sizeof(ReverbParams) == 0x44, "ReverbParams is an invalid size");
152
57class EffectInfo { 153class EffectInfo {
58public: 154public:
59 struct InParams { 155 struct InParams {
@@ -64,7 +160,7 @@ public:
64 s32_le mix_id{}; 160 s32_le mix_id{};
65 u64_le buffer_address{}; 161 u64_le buffer_address{};
66 u64_le buffer_size{}; 162 u64_le buffer_size{};
67 s32_le priority{}; 163 s32_le processing_order{};
68 INSERT_PADDING_BYTES(4); 164 INSERT_PADDING_BYTES(4);
69 union { 165 union {
70 std::array<u8, 0xa0> raw; 166 std::array<u8, 0xa0> raw;
@@ -79,16 +175,50 @@ public:
79 static_assert(sizeof(EffectInfo::OutParams) == 0x10, "OutParams is an invalid size"); 175 static_assert(sizeof(EffectInfo::OutParams) == 0x10, "OutParams is an invalid size");
80}; 176};
81 177
178struct AuxAddress {
179 VAddr send_dsp_info{};
180 VAddr send_buffer_base{};
181 VAddr return_dsp_info{};
182 VAddr return_buffer_base{};
183};
184
82class EffectBase { 185class EffectBase {
83public: 186public:
84 EffectBase(); 187 EffectBase(EffectType effect_type);
85 ~EffectBase(); 188 ~EffectBase();
86 189
87 virtual void Update(EffectInfo::InParams& in_params) = 0; 190 virtual void Update(EffectInfo::InParams& in_params) = 0;
88 UsageStatus GetUsage() const; 191 virtual void UpdateForCommandGeneration() = 0;
192 UsageState GetUsage() const;
193 EffectType GetType() const;
194 bool IsEnabled() const;
195 s32 GetMixID() const;
196 s32 GetProcessingOrder() const;
89 197
90protected: 198protected:
91 UsageStatus usage{UsageStatus::Invalid}; 199 UsageState usage{UsageState::Invalid};
200 EffectType effect_type{};
201 s32 mix_id{};
202 s32 processing_order{};
203 bool enabled = false;
204};
205
206template <typename T>
207class EffectGeneric : public EffectBase {
208public:
209 EffectGeneric(EffectType effect_type) : EffectBase::EffectBase(effect_type) {}
210 ~EffectGeneric() = default;
211
212 T& GetParams() {
213 return internal_params;
214 }
215
216 const I3dl2ReverbParams& GetParams() const {
217 return internal_params;
218 }
219
220private:
221 T internal_params{};
92}; 222};
93 223
94class EffectStubbed : public EffectBase { 224class EffectStubbed : public EffectBase {
@@ -97,6 +227,82 @@ public:
97 ~EffectStubbed(); 227 ~EffectStubbed();
98 228
99 void Update(EffectInfo::InParams& in_params) override; 229 void Update(EffectInfo::InParams& in_params) override;
230 void UpdateForCommandGeneration() override;
231};
232
233class EffectI3dl2Reverb : public EffectGeneric<I3dl2ReverbParams> {
234public:
235 explicit EffectI3dl2Reverb();
236 ~EffectI3dl2Reverb();
237
238 void Update(EffectInfo::InParams& in_params) override;
239 void UpdateForCommandGeneration() override;
240
241private:
242 bool skipped = false;
243};
244
245class EffectBiquadFilter : public EffectGeneric<BiquadFilterParams> {
246public:
247 explicit EffectBiquadFilter();
248 ~EffectBiquadFilter();
249
250 void Update(EffectInfo::InParams& in_params) override;
251 void UpdateForCommandGeneration() override;
252};
253
254class EffectAuxInfo : public EffectGeneric<AuxInfo> {
255public:
256 explicit EffectAuxInfo();
257 ~EffectAuxInfo();
258
259 void Update(EffectInfo::InParams& in_params) override;
260 void UpdateForCommandGeneration() override;
261 const VAddr GetSendInfo() const;
262 const VAddr GetSendBuffer() const;
263 const VAddr GetRecvInfo() const;
264 const VAddr GetRecvBuffer() const;
265
266private:
267 VAddr send_info{};
268 VAddr send_buffer{};
269 VAddr recv_info{};
270 VAddr recv_buffer{};
271 bool skipped = false;
272 AuxAddress addresses{};
273};
274
275class EffectDelay : public EffectGeneric<DelayParams> {
276public:
277 explicit EffectDelay();
278 ~EffectDelay();
279
280 void Update(EffectInfo::InParams& in_params) override;
281 void UpdateForCommandGeneration() override;
282
283private:
284 bool skipped = false;
285};
286
287class EffectBufferMixer : public EffectGeneric<BufferMixerParams> {
288public:
289 explicit EffectBufferMixer();
290 ~EffectBufferMixer();
291
292 void Update(EffectInfo::InParams& in_params) override;
293 void UpdateForCommandGeneration() override;
294};
295
296class EffectReverb : public EffectGeneric<ReverbParams> {
297public:
298 explicit EffectReverb();
299 ~EffectReverb();
300
301 void Update(EffectInfo::InParams& in_params) override;
302 void UpdateForCommandGeneration() override;
303
304private:
305 bool skipped = false;
100}; 306};
101 307
102class EffectContext { 308class EffectContext {
@@ -106,6 +312,7 @@ public:
106 312
107 std::size_t GetCount() const; 313 std::size_t GetCount() const;
108 EffectBase* GetInfo(std::size_t i); 314 EffectBase* GetInfo(std::size_t i);
315 EffectBase* RetargetEffect(std::size_t i, EffectType effect);
109 const EffectBase* GetInfo(std::size_t i) const; 316 const EffectBase* GetInfo(std::size_t i) const;
110 317
111private: 318private:
diff --git a/src/audio_core/info_updater.cpp b/src/audio_core/info_updater.cpp
index 286aa0321..f53ce21a5 100644
--- a/src/audio_core/info_updater.cpp
+++ b/src/audio_core/info_updater.cpp
@@ -244,14 +244,15 @@ bool InfoUpdater::UpdateEffects(EffectContext& effect_context, bool is_active) {
244 // Update effects 244 // Update effects
245 for (std::size_t i = 0; i < effect_count; i++) { 245 for (std::size_t i = 0; i < effect_count; i++) {
246 auto* info = effect_context.GetInfo(i); 246 auto* info = effect_context.GetInfo(i);
247 if (effect_in[i].type != info->GetType()) {
248 info = effect_context.RetargetEffect(i, effect_in[i].type);
249 }
250
247 info->Update(effect_in[i]); 251 info->Update(effect_in[i]);
248 252
249 // TODO(ogniK): Update individual effects 253 if ((!is_active && info->GetUsage() != UsageState::Initialized) ||
250 if ((!is_active && info->GetUsage() != UsageStatus::New) || 254 info->GetUsage() == UsageState::Stopped) {
251 info->GetUsage() == UsageStatus::Removed) {
252 effect_out[i].status = UsageStatus::Removed; 255 effect_out[i].status = UsageStatus::Removed;
253 } else if (info->GetUsage() == UsageStatus::New) {
254 effect_out[i].status = UsageStatus::New;
255 } else { 256 } else {
256 effect_out[i].status = UsageStatus::Used; 257 effect_out[i].status = UsageStatus::Used;
257 } 258 }
@@ -290,7 +291,8 @@ bool InfoUpdater::UpdateSplitterInfo(SplitterContext& splitter_context) {
290} 291}
291 292
292ResultCode InfoUpdater::UpdateMixes(MixContext& mix_context, std::size_t mix_buffer_count, 293ResultCode InfoUpdater::UpdateMixes(MixContext& mix_context, std::size_t mix_buffer_count,
293 SplitterContext& splitter_context) { 294 SplitterContext& splitter_context,
295 EffectContext& effect_context) {
294 std::vector<MixInfo::InParams> mix_in_params; 296 std::vector<MixInfo::InParams> mix_in_params;
295 297
296 if (!behavior_info.IsMixInParameterDirtyOnlyUpdateSupported()) { 298 if (!behavior_info.IsMixInParameterDirtyOnlyUpdateSupported()) {
@@ -387,13 +389,13 @@ ResultCode InfoUpdater::UpdateMixes(MixContext& mix_context, std::size_t mix_buf
387 auto& mix_info_params = mix_info.GetInParams(); 389 auto& mix_info_params = mix_info.GetInParams();
388 if (mix_info_params.in_use != mix_in.in_use) { 390 if (mix_info_params.in_use != mix_in.in_use) {
389 mix_info_params.in_use = mix_in.in_use; 391 mix_info_params.in_use = mix_in.in_use;
390 // TODO(ogniK): Update effect processing order 392 mix_info.ResetEffectProcessingOrder();
391 should_sort = true; 393 should_sort = true;
392 } 394 }
393 395
394 if (mix_in.in_use) { 396 if (mix_in.in_use) {
395 should_sort |= mix_info.Update(mix_context.GetEdgeMatrix(), mix_in, behavior_info, 397 should_sort |= mix_info.Update(mix_context.GetEdgeMatrix(), mix_in, behavior_info,
396 splitter_context); 398 splitter_context, effect_context);
397 } 399 }
398 } 400 }
399 401
diff --git a/src/audio_core/info_updater.h b/src/audio_core/info_updater.h
index 6969de67d..06f9d770f 100644
--- a/src/audio_core/info_updater.h
+++ b/src/audio_core/info_updater.h
@@ -34,7 +34,7 @@ public:
34 bool UpdateEffects(EffectContext& effect_context, bool is_active); 34 bool UpdateEffects(EffectContext& effect_context, bool is_active);
35 bool UpdateSplitterInfo(SplitterContext& splitter_context); 35 bool UpdateSplitterInfo(SplitterContext& splitter_context);
36 ResultCode UpdateMixes(MixContext& mix_context, std::size_t mix_buffer_count, 36 ResultCode UpdateMixes(MixContext& mix_context, std::size_t mix_buffer_count,
37 SplitterContext& splitter_context); 37 SplitterContext& splitter_context, EffectContext& effect_context);
38 bool UpdateSinks(SinkContext& sink_context); 38 bool UpdateSinks(SinkContext& sink_context);
39 bool UpdatePerformanceBuffer(); 39 bool UpdatePerformanceBuffer();
40 bool UpdateErrorInfo(BehaviorInfo& in_behavior_info); 40 bool UpdateErrorInfo(BehaviorInfo& in_behavior_info);
diff --git a/src/audio_core/mix_context.cpp b/src/audio_core/mix_context.cpp
index f6f119a11..042891490 100644
--- a/src/audio_core/mix_context.cpp
+++ b/src/audio_core/mix_context.cpp
@@ -4,6 +4,7 @@
4 4
5#include "audio_core/behavior_info.h" 5#include "audio_core/behavior_info.h"
6#include "audio_core/common.h" 6#include "audio_core/common.h"
7#include "audio_core/effect_context.h"
7#include "audio_core/mix_context.h" 8#include "audio_core/mix_context.h"
8#include "audio_core/splitter_context.h" 9#include "audio_core/splitter_context.h"
9 10
@@ -11,7 +12,8 @@ namespace AudioCore {
11MixContext::MixContext() = default; 12MixContext::MixContext() = default;
12MixContext::~MixContext() = default; 13MixContext::~MixContext() = default;
13 14
14void MixContext::Initialize(const BehaviorInfo& behavior_info, std::size_t mix_count) { 15void MixContext::Initialize(const BehaviorInfo& behavior_info, std::size_t mix_count,
16 std::size_t effect_count) {
15 info_count = mix_count; 17 info_count = mix_count;
16 infos.resize(info_count); 18 infos.resize(info_count);
17 auto& final_mix = GetInfo(AudioCommon::FINAL_MIX); 19 auto& final_mix = GetInfo(AudioCommon::FINAL_MIX);
@@ -21,6 +23,10 @@ void MixContext::Initialize(const BehaviorInfo& behavior_info, std::size_t mix_c
21 sorted_info.push_back(&info); 23 sorted_info.push_back(&info);
22 } 24 }
23 25
26 for (auto& info : infos) {
27 info.SetEffectCount(effect_count);
28 }
29
24 // Only initialize our edge matrix and node states if splitters are supported 30 // Only initialize our edge matrix and node states if splitters are supported
25 if (behavior_info.IsSplitterSupported()) { 31 if (behavior_info.IsSplitterSupported()) {
26 node_states.Initialize(mix_count); 32 node_states.Initialize(mix_count);
@@ -185,7 +191,8 @@ ServerMixInfo::InParams& ServerMixInfo::GetInParams() {
185} 191}
186 192
187bool ServerMixInfo::Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in, 193bool ServerMixInfo::Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in,
188 BehaviorInfo& behavior_info, SplitterContext& splitter_context) { 194 BehaviorInfo& behavior_info, SplitterContext& splitter_context,
195 EffectContext& effect_context) {
189 in_params.volume = mix_in.volume; 196 in_params.volume = mix_in.volume;
190 in_params.sample_rate = mix_in.sample_rate; 197 in_params.sample_rate = mix_in.sample_rate;
191 in_params.buffer_count = mix_in.buffer_count; 198 in_params.buffer_count = mix_in.buffer_count;
@@ -206,6 +213,15 @@ bool ServerMixInfo::Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix
206 in_params.splitter_id = AudioCommon::NO_SPLITTER; 213 in_params.splitter_id = AudioCommon::NO_SPLITTER;
207 } 214 }
208 215
216 ResetEffectProcessingOrder();
217 const auto effect_count = effect_context.GetCount();
218 for (std::size_t i = 0; i < effect_count; i++) {
219 auto* effect_info = effect_context.GetInfo(i);
220 if (effect_info->GetMixID() == in_params.mix_id) {
221 effect_processing_order[effect_info->GetProcessingOrder()] = static_cast<s32>(i);
222 }
223 }
224
209 // TODO(ogniK): Update effect processing order 225 // TODO(ogniK): Update effect processing order
210 return require_sort; 226 return require_sort;
211} 227}
@@ -228,6 +244,21 @@ void ServerMixInfo::Cleanup() {
228 std::memset(in_params.mix_volume.data(), 0, sizeof(float) * in_params.mix_volume.size()); 244 std::memset(in_params.mix_volume.data(), 0, sizeof(float) * in_params.mix_volume.size());
229} 245}
230 246
247void ServerMixInfo::SetEffectCount(std::size_t count) {
248 effect_processing_order.resize(count);
249 ResetEffectProcessingOrder();
250}
251
252void ServerMixInfo::ResetEffectProcessingOrder() {
253 for (auto& order : effect_processing_order) {
254 order = AudioCommon::NO_EFFECT_ORDER;
255 }
256}
257
258s32 ServerMixInfo::GetEffectOrder(std::size_t i) const {
259 return effect_processing_order.at(i);
260}
261
231bool ServerMixInfo::UpdateConnection(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in, 262bool ServerMixInfo::UpdateConnection(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in,
232 SplitterContext& splitter_context) { 263 SplitterContext& splitter_context) {
233 // Mixes are identical 264 // Mixes are identical
diff --git a/src/audio_core/mix_context.h b/src/audio_core/mix_context.h
index 381566699..6a588eeb4 100644
--- a/src/audio_core/mix_context.h
+++ b/src/audio_core/mix_context.h
@@ -13,6 +13,7 @@
13 13
14namespace AudioCore { 14namespace AudioCore {
15class BehaviorInfo; 15class BehaviorInfo;
16class EffectContext;
16 17
17class MixInfo { 18class MixInfo {
18public: 19public:
@@ -65,11 +66,16 @@ public:
65 ServerMixInfo::InParams& GetInParams(); 66 ServerMixInfo::InParams& GetInParams();
66 67
67 bool Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in, 68 bool Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in,
68 BehaviorInfo& behavior_info, SplitterContext& splitter_context); 69 BehaviorInfo& behavior_info, SplitterContext& splitter_context,
70 EffectContext& effect_context);
69 bool HasAnyConnection() const; 71 bool HasAnyConnection() const;
70 void Cleanup(); 72 void Cleanup();
73 void SetEffectCount(std::size_t count);
74 void ResetEffectProcessingOrder();
75 s32 GetEffectOrder(std::size_t i) const;
71 76
72private: 77private:
78 std::vector<s32> effect_processing_order;
73 InParams in_params{}; 79 InParams in_params{};
74 bool UpdateConnection(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in, 80 bool UpdateConnection(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in,
75 SplitterContext& splitter_context); 81 SplitterContext& splitter_context);
@@ -80,7 +86,8 @@ public:
80 MixContext(); 86 MixContext();
81 ~MixContext(); 87 ~MixContext();
82 88
83 void Initialize(const BehaviorInfo& behavior_info, std::size_t mix_count); 89 void Initialize(const BehaviorInfo& behavior_info, std::size_t mix_count,
90 std::size_t effect_count);
84 void SortInfo(); 91 void SortInfo();
85 bool TsortInfo(SplitterContext& splitter_context); 92 bool TsortInfo(SplitterContext& splitter_context);
86 93