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 2125 : 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 1132 : class Effect {
26 : public:
27 1210 : 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 3 : virtual void process_stereo(float* left, float* right, int num_samples) {
35 3 : process(left, num_samples);
36 3 : std::memcpy(right, left, static_cast<size_t>(num_samples) * sizeof(float));
37 3 : }
38 :
39 : // Update the processing sample rate before audio starts or after device changes.
40 2017 : 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 621 : void set_enabled(bool enabled) { enabled_ = enabled; }
57 1458 : bool is_enabled() const { return enabled_; }
58 :
59 525 : void set_mix(float mix) { mix_ = clamp(mix, 0.0f, 1.0f); }
60 1018 : float get_mix() const { return mix_; }
61 :
62 : virtual std::shared_ptr<Effect> clone() const;
63 :
64 3 : std::vector<std::string> get_param_names() {
65 3 : std::vector<std::string> names;
66 15 : for (const auto& p : params()) {
67 12 : names.push_back(p.name);
68 : }
69 3 : return names;
70 1 : }
71 :
72 15 : float get_param_value(const std::string& name) {
73 24 : for (const auto& p : params()) {
74 21 : if (p.name == name) {
75 12 : return p.value;
76 : }
77 : }
78 2 : return 0.0f;
79 5 : }
80 :
81 9 : void set_param_by_name(const std::string& name, float value) {
82 9 : for (auto& p : params()) {
83 9 : if (p.name == name) {
84 9 : p.value = clamp(value, p.min_val, p.max_val);
85 9 : return;
86 : }
87 : }
88 3 : }
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 9 : virtual nlohmann::json get_params() const {
99 9 : nlohmann::json j;
100 : // Accessing mutable params to read values
101 9 : auto& p_list = const_cast<Effect*>(this)->params();
102 36 : for (const auto& p : p_list) {
103 36 : j[p.name] = p.value;
104 : }
105 9 : j["enabled"] = enabled_.load();
106 9 : j["mix"] = mix_;
107 9 : return j;
108 3 : }
109 :
110 12 : virtual void set_params(const nlohmann::json& j) {
111 12 : if (j.contains("enabled")) enabled_.store(j["enabled"].get<bool>());
112 12 : if (j.contains("mix")) mix_ = j["mix"];
113 :
114 12 : auto& p_list = params();
115 48 : for (auto& p : p_list) {
116 36 : if (j.contains(p.name)) {
117 27 : p.value = j[p.name];
118 9 : }
119 : }
120 12 : }
121 :
122 : protected:
123 566 : int sample_rate_ = DEFAULT_SAMPLE_RATE;
124 566 : std::atomic<bool> enabled_{true};
125 566 : 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
|