LCOV - code coverage report
Current view: top level - src/gui/pedalboard - pedal_widget_knobs.cpp (source / functions) Coverage Total Hit
Test: merged.info Lines: 77.6 % 76 59
Test Date: 2026-06-01 11:15:25 Functions: 14.3 % 7 1

            Line data    Source code
       1              : #include "gui/pedalboard/pedal_widget.h"
       2              : #include "gui/views/gui_midi.h"
       3              : #include "midi/midi_manager.h"
       4              : #include "audio/engine/audio_engine.h"
       5              : #include "gui/theme/theme.h"
       6              : #include "gui/components/knob.h"
       7              : 
       8              : #include <cmath>
       9              : #include <algorithm>
      10              : 
      11              : namespace Amplitron {
      12              : 
      13          195 : void PedalWidget::render_knobs(ImDrawList* dl, ImVec2 p0, float pedal_width, bool is_amp, bool is_tuner, bool is_ir_cab, float zoom) {
      14          195 :     float knob_y_start = p0.y + Theme::KNOB_Y_START * zoom;
      15          195 :     if (is_ir_cab) knob_y_start = p0.y + 180 * zoom;
      16          195 :     auto& params = effect_->params();
      17          258 :     int num_params = is_tuner ? 0 : static_cast<int>(params.size());
      18          195 :     int param_offset = 0;
      19          195 :     if (is_amp) {
      20           15 :         param_offset = 1;
      21           15 :         num_params = std::max(0, num_params - 1);
      22            5 :     }
      23              : 
      24          195 :     float knob_radius    = Theme::KNOB_RADIUS * zoom;
      25          195 :     float knob_spacing_x = Theme::KNOB_SPACING_X * zoom;
      26          195 :     float knob_spacing_y = Theme::KNOB_SPACING_Y * zoom;
      27              : 
      28          195 :     float knob_grid_left = p0.x + (pedal_width - 2.0f * knob_spacing_x) * 0.5f;
      29              : 
      30          786 :     for (int i = 0; i < num_params && i < 6; ++i) {
      31          591 :         int pi = i + param_offset;
      32          591 :         int col = i % 2;
      33          591 :         int row = i / 2;
      34              : 
      35          591 :         bool is_last_alone = (i == num_params - 1) && (num_params % 2 == 1);
      36          591 :         float kx = is_last_alone
      37          319 :             ? p0.x + (pedal_width - knob_spacing_x) * 0.5f
      38          408 :             : knob_grid_left + col * knob_spacing_x;
      39          591 :         float ky = knob_y_start + row * knob_spacing_y;
      40              : 
      41          591 :         ImVec2 knob_center = ImVec2(kx + knob_spacing_x * 0.5f, ky + knob_radius + 2 * zoom);
      42              : 
      43          197 :         char label[64];
      44          591 :         snprintf(label, sizeof(label), "##knob_%s_%d_%d", effect_->name(), index_, pi);
      45              : 
      46          591 :         KnobProps props;
      47          591 :         props.name = params[pi].name;
      48          591 :         props.value = params[pi].value;
      49          591 :         props.min_val = params[pi].min_val;
      50          591 :         props.max_val = params[pi].max_val;
      51          591 :         props.default_val = params[pi].default_val;
      52          591 :         props.unit = params[pi].unit;
      53          591 :         props.tooltip = params[pi].tooltip;
      54              : 
      55              :         // MIDI learn integration
      56          591 :         if (gui_midi_) {
      57          549 :             props.is_learning = gui_midi_->midi().is_learning() &&
      58          370 :                                 gui_midi_->midi().learn_effect_name() == effect_->name() &&
      59           18 :                                 gui_midi_->midi().learn_param_name() == params[pi].name;
      60          895 :             props.midi_info = gui_midi_->get_mapping_info(effect_->name(), params[pi].name);
      61              : 
      62              :             // Capture pointers for lambda closures
      63          537 :             std::string eff_name = effect_->name();
      64          537 :             std::string param_name = params[pi].name;
      65          537 :             GuiMidi* gm = gui_midi_;
      66              : 
      67         1253 :             props.on_midi_learn_param = [gm, eff_name, param_name]() {
      68            0 :                 gm->manager().start_learn(MidiTargetType::EffectParam, eff_name, param_name);
      69          358 :             };
      70         1253 :             props.on_midi_clear_param = [gm, eff_name, param_name]() {
      71            0 :                 gm->manager().remove_mapping_for_param(eff_name, param_name);
      72          358 :             };
      73         1253 :             props.on_midi_learn_bypass = [gm, eff_name]() {
      74            0 :                 gm->manager().start_learn(MidiTargetType::EffectBypass, eff_name, "");
      75          358 :             };
      76         1253 :             props.on_midi_clear_bypass = [gm, eff_name]() {
      77            0 :                 int remove_idx = -1;
      78            0 :                 const auto& mappings = gm->manager().mappings();
      79            0 :                 for (int i = 0; i < static_cast<int>(mappings.size()); ++i) {
      80            0 :                     if (mappings[i].target_type == MidiTargetType::EffectBypass &&
      81            0 :                         mappings[i].effect_name == eff_name) {
      82            0 :                         remove_idx = i;
      83            0 :                         break;
      84              :                     }
      85            0 :                 }
      86            0 :                 if (remove_idx >= 0) {
      87            0 :                     gm->manager().remove_mapping(remove_idx);
      88            0 :                 }
      89          358 :             };
      90          537 :         }
      91              : 
      92          591 :         props.led_color = led_color_;
      93              : 
      94              :         // Events committed back to effect and engine
      95          985 :         props.on_value_changed = [this, pi](float new_val) {
      96            0 :             effect_->params()[pi].value = new_val;
      97            0 :             engine_.push_param_change(index_, pi, new_val);
      98          394 :         };
      99          985 :         props.on_value_committed = [this, pi](float old_val, float new_val) {
     100            0 :             commit_param_change(pi, old_val, new_val);
     101          394 :         };
     102              : 
     103          591 :         KnobComponent::render(label, props, zoom, knob_center);
     104          591 :     }
     105          195 : }
     106              : 
     107              : } // namespace Amplitron
        

Generated by: LCOV version 2.0-1