LCOV - code coverage report
Current view: top level - src/audio/engine - audio_command_dispatcher.cpp (source / functions) Coverage Total Hit
Test: merged.info Lines: 80.0 % 110 88
Test Date: 2026-06-07 15:51:50 Functions: 88.9 % 9 8

            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
        

Generated by: LCOV version 2.0-1