MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
ModalNetwork.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "NodeNetwork.hpp"
4
5namespace MayaFlux::Nodes {
6
7namespace Generator {
8 class Generator;
9}
10
11/**
12 * @class ModalNetwork
13 * @brief Network of resonant modes for modal synthesis
14 *
15 * CONCEPT:
16 * ========
17 * Modal synthesis models physical objects as collections of resonant modes,
18 * each with its own frequency, decay rate, and amplitude. The sum of all
19 * modes produces rich, organic timbres characteristic of struck/plucked
20 * instruments (bells, marimbas, strings, membranes).
21 *
22 * STRUCTURE:
23 * ==========
24 * Each mode is an independent oscillator (typically Sine) with:
25 * - Frequency: Resonant frequency of the mode
26 * - Decay: Exponential amplitude envelope
27 * - Amplitude: Initial strike/excitation strength
28 *
29 * Modes can follow various frequency relationships:
30 * - HARMONIC: f, 2f, 3f, 4f... (ideal strings)
31 * - INHARMONIC: f, 2.76f, 5.40f, 8.93f... (bells, bars)
32 * - STRETCHED: f, 2.01f, 3.02f, 4.04f... (stiff strings, piano)
33 * - CUSTOM: User-defined frequency ratios
34 *
35 * USAGE:
36 * ======
37 * ```cpp
38 * // Bell-like inharmonic spectrum
39 * auto bell = std::make_shared<ModalNetwork>(
40 * 16, // 16 modes
41 * 220.0, // Base frequency
42 * ModalNetwork::Spectrum::INHARMONIC
43 * );
44 * bell->set_output_mode(OutputMode::AUDIO_SINK);
45 * bell->excite(1.0); // Strike the bell
46 *
47 * node_graph_manager->add_network(bell, ProcessingToken::AUDIO_RATE);
48 * ```
49 *
50 * PARAMETER MAPPING:
51 * ==================
52 * External nodes can control:
53 * - "frequency": Base frequency (BROADCAST)
54 * - "decay": Global decay multiplier (BROADCAST)
55 * - "amplitude": Per-mode amplitude (ONE_TO_ONE)
56 * - "detune": Per-mode frequency offset (ONE_TO_ONE)
57 */
58class MAYAFLUX_API ModalNetwork : public NodeNetwork {
59public:
60 /**
61 * @enum Spectrum
62 * @brief Predefined frequency relationship patterns
63 */
64 enum class Spectrum : uint8_t {
65 HARMONIC, ///< Integer harmonics: f, 2f, 3f, 4f...
66 INHARMONIC, ///< Bell-like: f, 2.76f, 5.40f, 8.93f, 13.34f...
67 STRETCHED, ///< Piano-like stiffness: f, 2.01f, 3.02f, 4.04f...
68 CUSTOM ///< User-provided frequency ratios
69 };
70
71 /**
72 * @struct ModalNode
73 * @brief Represents a single resonant mode
74 */
75 struct ModalNode {
76 std::shared_ptr<Generator::Generator> oscillator; ///< Sine wave generator
77
78 double base_frequency; ///< Frequency without modulation
79 double current_frequency; ///< After mapping/modulation
80 double frequency_ratio; ///< Ratio relative to fundamental
81
82 double decay_time; ///< Time constant for amplitude decay (seconds)
83 double amplitude; ///< Current amplitude (0.0 to 1.0)
84 double initial_amplitude; ///< Amplitude at excitation
85 double decay_coefficient; ///< Precomputed exp factor
86
87 double phase = 0.0; ///< Current phase (for manual oscillator impl)
88 size_t index; ///< Index in network
89 };
90
91 //-------------------------------------------------------------------------
92 // Construction
93 //-------------------------------------------------------------------------
94
95 /**
96 * @brief Create modal network with predefined spectrum
97 * @param num_modes Number of resonant modes
98 * @param fundamental Base frequency in Hz
99 * @param spectrum Frequency relationship pattern
100 * @param base_decay Base decay time in seconds (modes get proportional decay)
101 */
102 ModalNetwork(size_t num_modes, double fundamental = 220.0,
103 Spectrum spectrum = Spectrum::HARMONIC, double base_decay = 1.0);
104
105 /**
106 * @brief Create modal network with custom frequency ratios
107 * @param frequency_ratios Vector of frequency multipliers relative to
108 * fundamental
109 * @param fundamental Base frequency in Hz
110 * @param base_decay Base decay time in seconds
111 */
112 ModalNetwork(const std::vector<double>& frequency_ratios,
113 double fundamental = 220.0, double base_decay = 1.0);
114
115 //-------------------------------------------------------------------------
116 // NodeNetwork Interface Implementation
117 //-------------------------------------------------------------------------
118
119 void process_batch(unsigned int num_samples) override;
120
121 [[nodiscard]] size_t get_node_count() const override
122 {
123 return m_modes.size();
124 }
125
126 void initialize() override { };
127
128 void reset() override;
129
130 [[nodiscard]] std::unordered_map<std::string, std::string>
131 get_metadata() const override;
132
133 //-------------------------------------------------------------------------
134 // Parameter Mapping
135 //-------------------------------------------------------------------------
136
137 void map_parameter(const std::string& param_name,
138 const std::shared_ptr<Node>& source,
139 MappingMode mode = MappingMode::BROADCAST) override;
140
141 void
142 map_parameter(const std::string& param_name,
143 const std::shared_ptr<NodeNetwork>& source_network) override;
144
145 void unmap_parameter(const std::string& param_name) override;
146
147 //-------------------------------------------------------------------------
148 // Modal Control
149 //-------------------------------------------------------------------------
150
151 /**
152 * @brief Excite all modes (strike/pluck)
153 * @param strength Excitation strength (0.0 to 1.0+)
154 *
155 * Resets all mode amplitudes to their initial values scaled by strength.
156 * Simulates striking or plucking the resonant structure.
157 */
158 void excite(double strength = 1.0);
159
160 /**
161 * @brief Excite specific mode
162 * @param mode_index Index of mode to excite
163 * @param strength Excitation strength
164 */
165 void excite_mode(size_t mode_index, double strength = 1.0);
166
167 /**
168 * @brief Damp all modes (rapidly reduce amplitude)
169 * @param damping_factor Multiplier applied to current amplitudes (0.0 to 1.0)
170 */
171 void damp(double damping_factor = 0.1);
172
173 /**
174 * @brief Set base frequency (fundamental)
175 * @param frequency Frequency in Hz
176 *
177 * Updates all mode frequencies proportionally to maintain spectrum shape.
178 */
179 void set_fundamental(double frequency);
180
181 /**
182 * @brief Get current fundamental frequency
183 */
184 [[nodiscard]] double get_fundamental() const { return m_fundamental; }
185
186 /**
187 * @brief Set global decay multiplier
188 * @param multiplier Scales all decay times (>1.0 = longer decay, <1.0 =
189 * shorter)
190 */
191 void set_decay_multiplier(double multiplier)
192 {
193 m_decay_multiplier = multiplier;
194 }
195
196 /**
197 * @brief Get mode data (read-only access for visualization)
198 */
199 [[nodiscard]] const std::vector<ModalNode>& get_modes() const
200 {
201 return m_modes;
202 }
203
204 /**
205 * @brief Get specific mode
206 */
207 [[nodiscard]] const ModalNode& get_mode(size_t index) const
208 {
209 return m_modes.at(index);
210 }
211
212 /**
213 * @brief Get output of specific internal node (for ONE_TO_ONE mapping)
214 * @param index Index of node in network
215 * @return Output value, or nullopt if not applicable
216 */
217 [[nodiscard]] std::optional<double> get_node_output(size_t index) const override;
218
219private:
220 //-------------------------------------------------------------------------
221 // Internal State
222 //-------------------------------------------------------------------------
223
224 std::vector<ModalNode> m_modes;
227 double m_decay_multiplier = 1.0;
228
229 // Cached output for get_audio_output()
230 mutable double m_last_output = 0.0;
231
232 //-------------------------------------------------------------------------
233 // Initialization Helpers
234 //-------------------------------------------------------------------------
235
236 /**
237 * @brief Generate frequency ratios for predefined spectra
238 */
239 static std::vector<double> generate_spectrum_ratios(Spectrum spectrum,
240 size_t count);
241
242 /**
243 * @brief Initialize modes with given frequency ratios
244 */
245 void initialize_modes(const std::vector<double>& ratios, double base_decay);
246
247 /**
248 * @brief Update mapped parameters before processing
249 */
250 void update_mapped_parameters();
251
252 /**
253 * @brief Apply broadcast parameter to all modes
254 */
255 void apply_broadcast_parameter(const std::string& param, double value);
256
257 /**
258 * @brief Apply one-to-one parameter from another network
259 */
260 void apply_one_to_one_parameter(const std::string& param,
261 const std::shared_ptr<NodeNetwork>& source);
262};
263
264} // namespace MayaFlux::Nodes
Spectrum
Predefined frequency relationship patterns.
std::vector< ModalNode > m_modes
size_t get_node_count() const override
Get the number of nodes in the network.
void initialize() override
Called once before first process_batch()
double get_fundamental() const
Get current fundamental frequency.
const ModalNode & get_mode(size_t index) const
Get specific mode.
void set_decay_multiplier(double multiplier)
Set global decay multiplier.
const std::vector< ModalNode > & get_modes() const
Get mode data (read-only access for visualization)
Network of resonant modes for modal synthesis.
Abstract base class for structured collections of nodes with defined relationships.
Contains the node-based computational processing system components.
Definition Chronie.hpp:5
std::shared_ptr< Generator::Generator > oscillator
Sine wave generator.
double decay_time
Time constant for amplitude decay (seconds)
double decay_coefficient
Precomputed exp factor.
double frequency_ratio
Ratio relative to fundamental.
double base_frequency
Frequency without modulation.
double current_frequency
After mapping/modulation.
double initial_amplitude
Amplitude at excitation.
double amplitude
Current amplitude (0.0 to 1.0)
Represents a single resonant mode.