14 Spectrum spectrum,
double base_decay)
15 : m_spectrum(spectrum)
16 , m_fundamental(fundamental)
26 double fundamental,
double base_decay)
28 , m_fundamental(fundamental)
43 std::vector<double> ratios;
44 ratios.reserve(count);
49 for (
size_t i = 0; i < count; ++i) {
50 ratios.push_back(
static_cast<double>(i + 1));
57 ratios = { 1.0, 2.756, 5.404, 8.933, 13.344, 18.64, 24.81, 31.86 };
58 while (ratios.size() < count) {
59 double last = ratios.back();
60 ratios.push_back(last + 6.8);
69 constexpr double B = 0.0001;
70 for (
size_t n = 1; n <= count; ++n) {
71 double ratio = n * std::sqrt(1.0 +
B * n * n);
72 ratios.push_back(ratio);
79 for (
size_t i = 0; i < count; ++i) {
80 ratios.push_back(
static_cast<double>(i + 1));
98 for (
size_t i = 0; i < ratios.size(); ++i) {
115 m_modes.push_back(std::move(mode));
122 mode.amplitude = 0.0;
124 mode.current_frequency = mode.base_frequency;
148 for (
unsigned int i = 0; i < num_samples; ++i) {
153 if (mode.amplitude > 0.0001) {
154 mode.amplitude *= mode.decay_coefficient;
156 mode.amplitude = 0.0;
159 double sample = mode.oscillator->process_sample(0.0) * mode.amplitude;
176 double value = mapping.broadcast_source->get_last_output();
187 if (param ==
"frequency") {
189 }
else if (param ==
"decay") {
191 }
else if (param ==
"amplitude") {
193 mode.amplitude *= value;
199 const std::string& param,
const std::shared_ptr<NodeNetwork>& source)
201 if (source->get_node_count() !=
m_modes.size()) {
205 if (param ==
"amplitude") {
206 for (
size_t i = 0; i <
m_modes.size(); ++i) {
207 auto val = source->get_node_output(i);
212 }
else if (param ==
"detune") {
213 for (
size_t i = 0; i <
m_modes.size(); ++i) {
214 auto val = source->get_node_output(i);
216 double detune_cents = *val * 100.0;
217 double ratio = std::pow(2.0, detune_cents / 1200.0);
219 m_modes[i].oscillator->set_frequency(
m_modes[i].current_frequency);
226 const std::shared_ptr<Node>& source,
241 const std::string& param_name,
242 const std::shared_ptr<NodeNetwork>& source_network)
259 [&](
const auto& m) { return m.param_name == param_name; }),
270 mode.amplitude = mode.initial_amplitude * strength;
276 if (mode_index <
m_modes.size()) {
277 m_modes[mode_index].amplitude =
m_modes[mode_index].initial_amplitude * strength;
284 mode.amplitude *= damping_factor;
294 mode.current_frequency = mode.base_frequency;
296 mode.oscillator->set_frequency(mode.current_frequency);
304std::unordered_map<std::string, std::string>
309 metadata[
"fundamental"] = std::to_string(
m_fundamental) +
" Hz";
310 metadata[
"spectrum"] = [
this]() {
326 double avg_amplitude = 0.0;
327 for (
const auto& mode :
m_modes) {
328 avg_amplitude += mode.amplitude;
330 avg_amplitude /=
m_modes.size();
331 metadata[
"avg_amplitude"] = std::to_string(avg_amplitude);
339 return m_modes[index].oscillator->get_last_output();
#define B(method_name, full_type_name)
static std::vector< double > generate_spectrum_ratios(Spectrum spectrum, size_t count)
Generate frequency ratios for predefined spectra.
Spectrum
Predefined frequency relationship patterns.
@ STRETCHED
Piano-like stiffness: f, 2.01f, 3.02f, 4.04f...
@ INHARMONIC
Bell-like: f, 2.76f, 5.40f, 8.93f, 13.34f...
@ CUSTOM
User-provided frequency ratios.
@ HARMONIC
Integer harmonics: f, 2f, 3f, 4f...
void damp(double damping_factor=0.1)
Damp all modes (rapidly reduce amplitude)
std::vector< ModalNode > m_modes
void process_batch(unsigned int num_samples) override
Process the network for the given number of samples.
void apply_one_to_one_parameter(const std::string ¶m, const std::shared_ptr< NodeNetwork > &source)
Apply one-to-one parameter from another network.
double m_decay_multiplier
void unmap_parameter(const std::string ¶m_name) override
Remove parameter mapping.
ModalNetwork(size_t num_modes, double fundamental=220.0, Spectrum spectrum=Spectrum::HARMONIC, double base_decay=1.0)
Create modal network with predefined spectrum.
void apply_broadcast_parameter(const std::string ¶m, double value)
Apply broadcast parameter to all modes.
void excite(double strength=1.0)
Excite all modes (strike/pluck)
std::unordered_map< std::string, std::string > get_metadata() const override
Get network metadata for debugging/visualization.
void set_fundamental(double frequency)
Set base frequency (fundamental)
std::optional< double > get_node_output(size_t index) const override
Get output of specific internal node (for ONE_TO_ONE mapping)
void reset() override
Reset network to initial state.
void update_mapped_parameters()
Update mapped parameters before processing.
void map_parameter(const std::string ¶m_name, const std::shared_ptr< Node > &source, MappingMode mode=MappingMode::BROADCAST) override
Map external node output to network parameter.
void excite_mode(size_t mode_index, double strength=1.0)
Excite specific mode.
void initialize_modes(const std::vector< double > &ratios, double base_decay)
Initialize modes with given frequency ratios.
std::vector< ParameterMapping > m_parameter_mappings
void set_topology(Topology topology)
Set the network's topology.
void ensure_initialized()
Ensure initialize() is called exactly once.
MappingMode
Defines how nodes map to external entities (e.g., audio channels, graphics objects)
@ ONE_TO_ONE
Node array/network → network nodes (must match count)
@ BROADCAST
One node → all network nodes.
@ INDEPENDENT
No connections, nodes process independently.
std::vector< double > m_last_audio_buffer
virtual std::unordered_map< std::string, std::string > get_metadata() const
Get network metadata for debugging/visualization.
@ AUDIO_SINK
Aggregated audio samples sent to output.
bool is_enabled() const
Check if network is enabled.
void set_output_mode(OutputMode mode)
Set the network's output routing mode.
uint32_t get_sample_rate()
Gets the sample rate from the default engine.
Contains the node-based computational processing system components.
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.
size_t index
Index in network.
double initial_amplitude
Amplitude at excitation.
double amplitude
Current amplitude (0.0 to 1.0)
Represents a single resonant mode.
std::shared_ptr< Node > broadcast_source
std::shared_ptr< NodeNetwork > network_source