LCOV - code coverage report
Current view: top level - src/audio/effects - effect.h (source / functions) Coverage Total Hit
Test: merged.info Lines: 98.4 % 61 60
Test Date: 2026-06-03 09:13:19 Functions: 88.9 % 18 16

            Line data    Source code
       1              : #pragma once
       2              : 
       3              : #include "common.h"
       4              : #include <cstring>
       5              : #include <vector>
       6              : #include <string>
       7              : #include <memory>
       8              : #include <atomic>
       9              : #include <nlohmann/json.hpp>
      10              : 
      11              : namespace Amplitron {
      12              : 
      13              : // Runtime-editable effect parameter exposed to the UI and preset system.
      14         2368 : struct EffectParam {
      15              :     std::string name;
      16              :     float value;
      17              :     float min_val;
      18              :     float max_val;
      19              :     float default_val;
      20              :     std::string unit;
      21              :     std::string tooltip;
      22              : };
      23              : 
      24              : // Common interface for all mono/stereo audio effects in the pedal chain.
      25         1242 : class Effect {
      26              : public:
      27         1329 :     virtual ~Effect() = default;
      28              : 
      29              :     // Process a mono buffer in place.
      30              :     virtual void process(float* buffer, int num_samples) = 0;
      31              : 
      32              :     // Stereo processing. Default fans mono left channel to both outputs.
      33              :     // Stereo-capable effects override this to produce true stereo.
      34            6 :     virtual void process_stereo(float* left, float* right, int num_samples) {
      35            6 :         process(left, num_samples);
      36            6 :         std::memcpy(right, left, static_cast<size_t>(num_samples) * sizeof(float));
      37            6 :     }
      38              : 
      39              :     // Update the processing sample rate before audio starts or after device changes.
      40         2188 :     virtual void set_sample_rate(int sample_rate) { sample_rate_ = sample_rate; }
      41              : 
      42              :     // Clear delay lines, envelopes, filters, and other effect state.
      43              :     virtual void reset() = 0;
      44              : 
      45              :     // Tempo broadcast receiver.
      46            9 :     virtual void set_transport_state(float /*bpm*/) {}
      47              : 
      48              :     // Display name used by the pedal board and preset serialization.
      49              :     virtual const char* name() const = 0;
      50              : 
      51            0 :     virtual const char* type_id() const { return name(); }
      52              : 
      53              :     // Mutable parameter list used by controls and automation.
      54              :     virtual std::vector<EffectParam>& params() = 0;
      55              : 
      56          642 :     void set_enabled(bool enabled) { enabled_ = enabled; }
      57         1472 :     bool is_enabled() const { return enabled_; }
      58              : 
      59          543 :     void set_mix(float mix) { mix_ = clamp(mix, 0.0f, 1.0f); }
      60         1026 :     float get_mix() const { return mix_; }
      61              : 
      62              :     virtual std::shared_ptr<Effect> clone() const;
      63              : 
      64            6 :     std::vector<std::string> get_param_names() {
      65            6 :         std::vector<std::string> names;
      66           24 :         for (const auto& p : params()) {
      67           18 :             names.push_back(p.name);
      68              :         }
      69            6 :         return names;
      70            2 :     }
      71              : 
      72           48 :     float get_param_value(const std::string& name) {
      73           75 :         for (const auto& p : params()) {
      74           69 :             if (p.name == name) {
      75           42 :                 return p.value;
      76              :             }
      77              :         }
      78            4 :         return 0.0f;
      79           16 :     }
      80              : 
      81           27 :     void set_param_by_name(const std::string& name, float value) {
      82           36 :         for (auto& p : params()) {
      83           33 :             if (p.name == name) {
      84           24 :                 p.value = clamp(value, p.min_val, p.max_val);
      85           24 :                 return;
      86              :             }
      87              :         }
      88            9 :     }
      89              : 
      90            3 :     virtual const char* get_display_name() const {
      91            3 :         return name();
      92              :     }
      93              : 
      94              :     // --- AUTOMATED SERIALIZATION LOGIC ---
      95              :     // These methods automatically handle saving/loading for any effect 
      96              :     // that uses the EffectParam vector.
      97              :     
      98           15 :     virtual nlohmann::json get_params() const {
      99           15 :         nlohmann::json j;
     100              :         // Accessing mutable params to read values
     101           15 :         auto& p_list = const_cast<Effect*>(this)->params();
     102           57 :         for (const auto& p : p_list) {
     103           56 :             j[p.name] = p.value;
     104              :         }
     105           15 :         j["enabled"] = enabled_.load();
     106           15 :         j["mix"] = mix_;
     107           15 :         return j;
     108            5 :     }
     109              : 
     110           18 :     virtual void set_params(const nlohmann::json& j) {
     111           18 :         if (j.contains("enabled")) enabled_.store(j["enabled"].get<bool>());
     112           18 :         if (j.contains("mix")) mix_ = j["mix"];
     113              :         
     114           18 :         auto& p_list = params();
     115           69 :         for (auto& p : p_list) {
     116           51 :             if (j.contains(p.name)) {
     117           42 :                 p.value = j[p.name];
     118           14 :             }
     119              :         }
     120           18 :     }
     121              : 
     122              : protected:
     123          621 :     int sample_rate_ = DEFAULT_SAMPLE_RATE;
     124          621 :     std::atomic<bool> enabled_{true};
     125          621 :     float mix_ = 1.0f;
     126              : 
     127              :     // Wet/dry mix helper
     128            6 :     void apply_mix(const float* dry, float* wet, int num_samples) {
     129            6 :         if (mix_ >= 1.0f) return;
     130           15 :         for (int i = 0; i < num_samples; ++i) {
     131           12 :             wet[i] = dry[i] * (1.0f - mix_) + wet[i] * mix_;
     132            4 :         }
     133            2 :     }
     134              : };
     135              : 
     136              : } // namespace Amplitron
        

Generated by: LCOV version 2.0-1