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
|