Line data Source code
1 : #include "audio/engine/audio_command_dispatcher.h"
2 :
3 : #include <iostream>
4 :
5 : #include "audio/effects/core/effect.h"
6 : #include "audio/engine/audio_graph.h"
7 : #include "audio/engine/audio_graph_executor.h"
8 :
9 : namespace Amplitron {
10 :
11 30 : void AudioCommandDispatcher::push_param_change(int effect_index, int param_index, float value) {
12 30 : AudioCommand cmd{};
13 30 : cmd.type = AudioCommand::SetEffectParam;
14 30 : cmd.effect_index = effect_index;
15 30 : cmd.param_index = param_index;
16 30 : cmd.value = value;
17 30 : command_queue_.try_push(cmd);
18 30 : }
19 :
20 0 : void AudioCommandDispatcher::push_mixer_gain_change(int node_id, int pin_index, float gain) {
21 0 : AudioCommand cmd{};
22 0 : cmd.type = AudioCommand::SetMixerGain;
23 0 : cmd.effect_index = node_id; // Overload effect_index to mean node_id
24 0 : cmd.param_index = pin_index; // Overload param_index to mean pin_index
25 0 : cmd.value = gain;
26 0 : command_queue_.try_push(cmd);
27 0 : }
28 :
29 21 : void AudioCommandDispatcher::push_effect_enabled(int effect_index, float enabled) {
30 21 : AudioCommand cmd{};
31 21 : cmd.type = AudioCommand::SetEffectEnabled;
32 21 : cmd.effect_index = effect_index;
33 21 : cmd.value = enabled;
34 21 : command_queue_.try_push(cmd);
35 21 : }
36 :
37 6 : void AudioCommandDispatcher::push_effect_mix(int effect_index, float mix) {
38 6 : AudioCommand cmd{};
39 6 : cmd.type = AudioCommand::SetEffectMix;
40 6 : cmd.effect_index = effect_index;
41 6 : cmd.value = mix;
42 6 : command_queue_.try_push(cmd);
43 6 : }
44 :
45 285 : void AudioCommandDispatcher::push_input_gain(float gain) {
46 285 : AudioCommand cmd{};
47 285 : cmd.type = AudioCommand::SetInputGain;
48 285 : cmd.value = gain;
49 285 : command_queue_.try_push(cmd);
50 285 : }
51 :
52 237 : void AudioCommandDispatcher::push_output_gain(float gain) {
53 237 : AudioCommand cmd{};
54 237 : cmd.type = AudioCommand::SetOutputGain;
55 237 : cmd.value = gain;
56 237 : command_queue_.try_push(cmd);
57 237 : }
58 :
59 4625 : void AudioCommandDispatcher::drain_gain_commands(std::atomic<float>& input_gain,
60 : std::atomic<float>& output_gain,
61 : std::shared_ptr<AudioGraphExecutor>& executor) {
62 1147 : AudioCommand cmd;
63 4676 : while (command_queue_.try_peek(cmd)) {
64 60 : if (cmd.type == AudioCommand::SetInputGain) {
65 27 : command_queue_.try_pop(cmd);
66 27 : input_gain.store(cmd.value, std::memory_order_relaxed);
67 42 : } else if (cmd.type == AudioCommand::SetOutputGain) {
68 24 : command_queue_.try_pop(cmd);
69 24 : output_gain.store(cmd.value, std::memory_order_relaxed);
70 17 : } else if (cmd.type == AudioCommand::SetMixerGain) {
71 0 : command_queue_.try_pop(cmd);
72 0 : if (executor) {
73 0 : executor->update_mixer_gain(cmd.effect_index, cmd.param_index, cmd.value);
74 0 : }
75 0 : } else {
76 6 : break;
77 : }
78 : }
79 4625 : }
80 :
81 4618 : void AudioCommandDispatcher::drain_commands(std::atomic<float>& input_gain,
82 : std::atomic<float>& output_gain,
83 : std::shared_ptr<AudioGraphExecutor>& executor,
84 : AudioGraph& main_graph,
85 : std::vector<std::shared_ptr<Effect>>& dummy_effects) {
86 1147 : AudioCommand cmd;
87 4642 : while (command_queue_.try_pop(cmd)) {
88 : // Helper to find the effect pointer safely in the compiled executor by node_id, with
89 : // fallback
90 37 : auto get_effect_by_id = [&](int node_id) -> std::shared_ptr<Effect> {
91 21 : if (executor) {
92 21 : if (auto fx = executor->get_effect_by_node_id(node_id)) {
93 0 : return fx;
94 14 : }
95 7 : }
96 63 : for (const auto& node : main_graph.get_nodes()) {
97 42 : if (node.id == node_id) {
98 0 : return node.pedal;
99 : }
100 : }
101 21 : if (node_id >= 0 && node_id < static_cast<int>(dummy_effects.size())) {
102 : // Comments on node_id semantics: node_id is used as a 0-based linear index fallback
103 : // for the GUI and tests
104 12 : std::cerr << "[AudioCommandDispatcher] Node ID " << node_id
105 12 : << " not found in executor or graph; falling back to dummy_effects index."
106 12 : << std::endl;
107 12 : return dummy_effects[node_id];
108 : }
109 9 : std::cerr << "[AudioCommandDispatcher] Node ID " << node_id
110 9 : << " lookup failed completely." << std::endl;
111 9 : return nullptr;
112 23 : };
113 :
114 24 : switch (cmd.type) {
115 4 : case AudioCommand::SetEffectParam: {
116 7 : if (auto fx = get_effect_by_id(cmd.effect_index)) {
117 3 : auto& params = fx->params();
118 3 : if (cmd.param_index >= 0 && cmd.param_index < static_cast<int>(params.size())) {
119 3 : params[cmd.param_index].value = cmd.value;
120 1 : }
121 5 : }
122 6 : break;
123 : }
124 6 : case AudioCommand::SetEffectEnabled: {
125 11 : if (auto fx = get_effect_by_id(cmd.effect_index)) {
126 6 : fx->set_enabled(cmd.value > 0.5f);
127 8 : }
128 9 : break;
129 : }
130 4 : case AudioCommand::SetEffectMix: {
131 7 : if (auto fx = get_effect_by_id(cmd.effect_index)) {
132 3 : fx->set_mix(cmd.value);
133 5 : }
134 6 : break;
135 : }
136 0 : case AudioCommand::SetMixerGain:
137 : // Skip SetMixerGain in the mutex-gated path, it is handled lock-free
138 0 : break;
139 2 : case AudioCommand::SetInputGain:
140 3 : input_gain.store(cmd.value, std::memory_order_relaxed);
141 3 : break;
142 0 : case AudioCommand::SetOutputGain:
143 0 : output_gain.store(cmd.value, std::memory_order_relaxed);
144 0 : break;
145 0 : default:
146 0 : break;
147 : }
148 : }
149 4618 : }
150 :
151 : } // namespace Amplitron
|