Vital
Loading...
Searching...
No Matches
synth_module.cpp
Go to the documentation of this file.
1
7#include "synth_module.h"
8
9#include "synth_constants.h"
10#include "smooth_value.h"
11#include "value_switch.h"
12
13namespace vital {
14
22 Value* SynthModule::createBaseControl(std::string name, bool audio_rate, bool smooth_value) {
24
25 Value* val = nullptr;
26 if (audio_rate) {
27 if (smooth_value) {
28 val = new SmoothValue(default_value);
29 addMonoProcessor(val, false);
30 }
31 else {
32 val = new Value(default_value);
34 }
35 }
36 else {
37 if (smooth_value) {
38 val = new cr::SmoothValue(default_value);
39 addMonoProcessor(val, false);
40 }
41 else {
42 val = new cr::Value(default_value);
44 }
45 }
46
47 data_->controls[name] = val;
48 return val;
49 }
50
59 Output* SynthModule::createBaseModControl(std::string name, bool audio_rate,
60 bool smooth_value, Output* internal_modulation) {
61 Processor* base_val = createBaseControl(name, audio_rate, smooth_value);
62
63 Processor* mono_total = nullptr;
64 if (audio_rate)
65 mono_total = new ModulationSum();
66 else
67 mono_total = new cr::VariableAdd();
68
69 mono_total->plugNext(base_val);
70 addMonoProcessor(mono_total, false);
71 data_->mono_mod_destinations[name] = mono_total;
72 data_->mono_modulation_readout[name] = mono_total->output();
73
74 ValueSwitch* control_switch = new ValueSwitch(0.0f);
75 control_switch->plugNext(base_val);
76 control_switch->plugNext(mono_total);
77
78 if (internal_modulation)
79 mono_total->plugNext(internal_modulation);
80 else
81 control_switch->addProcessor(mono_total);
82
83 addIdleMonoProcessor(control_switch);
84
85 // Determine which path (no mod or modded) is active by default.
86 if (smooth_value || internal_modulation)
87 control_switch->set(1);
88 else
89 control_switch->set(0);
90
91 data_->mono_modulation_switches[name] = control_switch;
92 return control_switch->output(ValueSwitch::kSwitch);
93 }
94
104 Output* SynthModule::createMonoModControl(std::string name, bool audio_rate,
105 bool smooth_value, Output* internal_modulation) {
106 ValueDetails details = Parameters::getDetails(name);
107 Output* control_rate_total = createBaseModControl(name, audio_rate, smooth_value, internal_modulation);
108 if (audio_rate)
109 return control_rate_total;
110
111 // Apply value scale post-processing if needed.
112 if (details.value_scale == ValueDetails::kQuadratic) {
113 Processor* scale = nullptr;
114 if (details.post_offset)
115 scale = new cr::Quadratic(details.post_offset);
116 else
117 scale = new cr::Square();
118
119 scale->plug(control_rate_total);
120 addMonoProcessor(scale);
121 control_rate_total = scale->output();
122 }
123 else if (details.value_scale == ValueDetails::kCubic) {
124 Processor* scale = nullptr;
125 VITAL_ASSERT(details.post_offset == 0.0f);
126 if (details.post_offset)
127 scale = new cr::Cubic(details.post_offset);
128 else
129 scale = new cr::Cube();
130
131 scale->plug(control_rate_total);
132 addMonoProcessor(scale);
133 control_rate_total = scale->output();
134 }
135 else if (details.value_scale == ValueDetails::kQuartic) {
136 Processor* scale = nullptr;
137 VITAL_ASSERT(details.post_offset == 0.0f);
138 if (details.post_offset)
139 scale = new cr::Quartic(details.post_offset);
140 else
141 scale = new cr::Quart();
142
143 scale->plug(control_rate_total);
144 addMonoProcessor(scale);
145 control_rate_total = scale->output();
146 }
147 else if (details.value_scale == ValueDetails::kExponential) {
148 cr::ExponentialScale* exponential = new cr::ExponentialScale(details.min, details.max, 2.0f);
149 exponential->plug(control_rate_total);
150 addMonoProcessor(exponential);
151 control_rate_total = exponential->output();
152 }
153 else if (details.value_scale == ValueDetails::kSquareRoot) {
154 cr::Root* root = new cr::Root(details.post_offset);
155 root->plug(control_rate_total);
156 addMonoProcessor(root);
157 control_rate_total = root->output();
158 }
159
160 return control_rate_total;
161 }
162
173 Output* SynthModule::createPolyModControl(std::string name, bool audio_rate,
174 bool smooth_value, Output* internal_modulation, Input* reset) {
175 ValueDetails details = Parameters::getDetails(name);
176 Output* base_control = createBaseModControl(name, audio_rate, smooth_value);
177
178 // Create poly mod sum.
179 Processor* poly_total;
180 if (audio_rate) {
181 poly_total = new ModulationSum();
182 if (reset)
184 }
185 else
186 poly_total = new cr::VariableAdd();
187
188 addProcessor(poly_total);
189 data_->poly_mod_destinations[name] = poly_total;
190
191 // Create final sum of base + poly mod.
192 Processor* modulation_total;
193 if (audio_rate)
194 modulation_total = new Add();
195 else
196 modulation_total = new cr::Add();
197
198 modulation_total->plug(base_control, 0);
199 modulation_total->plug(poly_total, 1);
200 addProcessor(modulation_total);
201
202 data_->poly_modulation_readout[name] = poly_total->output();
203
204 // Use a ValueSwitch to toggle between no mod and modded output.
205 ValueSwitch* control_switch = new ValueSwitch(0.0f);
206 control_switch->plugNext(base_control);
207 control_switch->plugNext(modulation_total);
208
209 if (internal_modulation) {
210 poly_total->plugNext(internal_modulation);
211 control_switch->set(1);
212 }
213 else {
214 control_switch->addProcessor(poly_total);
215 control_switch->addProcessor(modulation_total);
216 control_switch->set(0);
217 }
218 addIdleProcessor(control_switch);
219 data_->poly_modulation_switches[name] = control_switch;
220
221 Output* control_rate_total = control_switch->output(ValueSwitch::kSwitch);
222
223 // If control rate, no further scaling is needed.
224 if (audio_rate)
225 return control_rate_total;
226
227 // Apply any final scaling if requested.
228 if (details.value_scale == ValueDetails::kQuadratic) {
229 Processor* scale = nullptr;
230 if (details.post_offset)
231 scale = new cr::Quadratic(details.post_offset);
232 else
233 scale = new cr::Square();
234
235 scale->plug(control_rate_total);
236 addProcessor(scale);
237 control_rate_total = scale->output();
238 }
239 else if (details.value_scale == ValueDetails::kCubic) {
240 Processor* scale = nullptr;
241 VITAL_ASSERT(details.post_offset == 0.0f);
242 if (details.post_offset)
243 scale = new cr::Cubic(details.post_offset);
244 else
245 scale = new cr::Cube();
246
247 scale->plug(control_rate_total);
248 addProcessor(scale);
249 control_rate_total = scale->output();
250 }
251 else if (details.value_scale == ValueDetails::kQuartic) {
252 Processor* scale = nullptr;
253 VITAL_ASSERT(details.post_offset == 0.0f);
254 if (details.post_offset)
255 scale = new cr::Quartic(details.post_offset);
256 else
257 scale = new cr::Quart();
258
259 scale->plug(control_rate_total);
260 addProcessor(scale);
261 control_rate_total = scale->output();
262 }
263 else if (details.value_scale == ValueDetails::kExponential) {
264 Processor* exponential = new cr::ExponentialScale(details.min, details.max, 2.0f, details.post_offset);
265 exponential->plug(control_rate_total);
266 addProcessor(exponential);
267 control_rate_total = exponential->output();
268 }
269 else if (details.value_scale == ValueDetails::kSquareRoot) {
270 cr::Root* root = new cr::Root(details.post_offset);
271 root->plug(control_rate_total);
272 addProcessor(root);
273 control_rate_total = root->output();
274 }
275
276 return control_rate_total;
277 }
278
290 const Output* beats_per_second, bool poly, Input* midi) {
291 Output* tempo = nullptr;
292 if (poly)
293 tempo = createPolyModControl(name + "_tempo");
294 else
295 tempo = createMonoModControl(name + "_tempo");
296
297 cr::Value* sync = new cr::Value(1.0f);
298 data_->controls[name + "_sync"] = sync;
299 addIdleProcessor(sync);
300
301 TempoChooser* tempo_chooser = new TempoChooser();
302 tempo_chooser->plug(sync, TempoChooser::kSync);
303 tempo_chooser->plug(tempo, TempoChooser::kTempoIndex);
304 tempo_chooser->plug(frequency, TempoChooser::kFrequency);
305 tempo_chooser->plug(beats_per_second, TempoChooser::kBeatsPerSecond);
306
307 if (midi) {
308 Output* keytrack_transpose = nullptr;
309 Output* keytrack_tune = nullptr;
310 if (poly) {
311 keytrack_transpose = createPolyModControl(name + "_keytrack_transpose");
312 keytrack_tune = createPolyModControl(name + "_keytrack_tune");
313 }
314 else {
315 keytrack_transpose = createMonoModControl(name + "_keytrack_transpose");
316 keytrack_tune = createMonoModControl(name + "_keytrack_tune");
317 }
318
319 tempo_chooser->plug(keytrack_transpose, TempoChooser::kKeytrackTranspose);
320 tempo_chooser->plug(keytrack_tune, TempoChooser::kKeytrackTune);
321 tempo_chooser->useInput(midi, TempoChooser::kMidi);
322 }
323
324 if (poly)
325 addProcessor(tempo_chooser);
326 else
327 addMonoProcessor(tempo_chooser);
328
329 return tempo_chooser->output();
330 }
331
337 void SynthModule::createStatusOutput(std::string name, Output* source) {
338 data_->status_outputs[name] = std::make_unique<StatusOutput>(source);
339 }
340
342 control_map all_controls = data_->controls;
343 for (SynthModule* sub_module : data_->sub_modules) {
344 control_map sub_controls = sub_module->getControls();
345 all_controls.insert(sub_controls.begin(), sub_controls.end());
346 }
347 return all_controls;
348 }
349
351 if (data_->mod_sources.count(name))
352 return data_->mod_sources[name];
353
354 for (SynthModule* sub_module : data_->sub_modules) {
355 Output* source = sub_module->getModulationSource(name);
356 if (source)
357 return source;
358 }
359 return nullptr;
360 }
361
362 const StatusOutput* SynthModule::getStatusOutput(std::string name) const {
363 if (data_->status_outputs.count(name))
364 return data_->status_outputs.at(name).get();
365
366 for (SynthModule* sub_module : data_->sub_modules) {
367 const StatusOutput* source = sub_module->getStatusOutput(name);
368 if (source)
369 return source;
370 }
371 return nullptr;
372 }
373
374 Processor* SynthModule::getModulationDestination(std::string name, bool poly) {
375 Processor* poly_destination = getPolyModulationDestination(name);
376 if (poly && poly_destination)
377 return poly_destination;
378
379 return getMonoModulationDestination(name);
380 }
381
383 if (data_->mono_mod_destinations.count(name))
384 return data_->mono_mod_destinations[name];
385
386 for (SynthModule* sub_module : data_->sub_modules) {
387 Processor* destination = sub_module->getMonoModulationDestination(name);
388 if (destination)
389 return destination;
390 }
391 return nullptr;
392 }
393
395 if (data_->poly_mod_destinations.count(name))
396 return data_->poly_mod_destinations[name];
397
398 for (SynthModule* sub_module : data_->sub_modules) {
399 Processor* destination = sub_module->getPolyModulationDestination(name);
400 if (destination)
401 return destination;
402 }
403 return nullptr;
404 }
405
406 ValueSwitch* SynthModule::getModulationSwitch(std::string name, bool poly) {
407 if (poly)
408 return getPolyModulationSwitch(name);
409 return getMonoModulationSwitch(name);
410 }
411
413 if (data_->mono_modulation_switches.count(name))
414 return data_->mono_modulation_switches[name];
415
416 for (SynthModule* sub_module : data_->sub_modules) {
417 ValueSwitch* value_switch = sub_module->getMonoModulationSwitch(name);
418 if (value_switch)
419 return value_switch;
420 }
421 return nullptr;
422 }
423
425 if (data_->poly_modulation_switches.count(name))
426 return data_->poly_modulation_switches[name];
427
428 for (SynthModule* sub_module : data_->sub_modules) {
429 ValueSwitch* value_switch = sub_module->getPolyModulationSwitch(name);
430 if (value_switch)
431 return value_switch;
432 }
433 return nullptr;
434 }
435
437 // Update all mono modulation switches
438 for (auto& mod_switch : data_->mono_modulation_switches) {
439 bool enable = data_->mono_mod_destinations[mod_switch.first]->connectedInputs() > 1;
440 if (data_->poly_mod_destinations.count(mod_switch.first))
441 enable = enable || data_->poly_mod_destinations[mod_switch.first]->connectedInputs() > 0;
442 mod_switch.second->set(enable ? 1.0f : 0.0f);
443 }
444
445 // Update all poly modulation switches
446 for (auto& mod_switch : data_->poly_modulation_switches)
447 mod_switch.second->set(data_->poly_mod_destinations[mod_switch.first]->connectedInputs() > 0);
448
449 // Recursively update submodules
450 for (SynthModule* sub_module : data_->sub_modules)
451 sub_module->updateAllModulationSwitches();
452 }
453
455 output_map& all_sources = data_->mod_sources;
456 for (SynthModule* sub_module : data_->sub_modules) {
457 output_map& sub_sources = sub_module->getModulationSources();
458 all_sources.insert(sub_sources.begin(), sub_sources.end());
459 }
460 return all_sources;
461 }
462
464 input_map& all_destinations = data_->mono_mod_destinations;
465 for (SynthModule* sub_module : data_->sub_modules) {
466 input_map& sub_destinations = sub_module->getMonoModulationDestinations();
467 all_destinations.insert(sub_destinations.begin(), sub_destinations.end());
468 }
469 return all_destinations;
470 }
471
473 input_map& all_destinations = data_->poly_mod_destinations;
474 for (SynthModule* sub_module : data_->sub_modules) {
475 input_map& sub_destinations = sub_module->getPolyModulationDestinations();
476 all_destinations.insert(sub_destinations.begin(), sub_destinations.end());
477 }
478 return all_destinations;
479 }
480
482 output_map& all_readouts = data_->mono_modulation_readout;
483 for (SynthModule* sub_module : data_->sub_modules) {
484 output_map& sub_readouts = sub_module->getMonoModulations();
485 all_readouts.insert(sub_readouts.begin(), sub_readouts.end());
486 }
487 return all_readouts;
488 }
489
491 output_map& all_readouts = data_->poly_modulation_readout;
492 for (SynthModule* sub_module : data_->sub_modules) {
493 output_map& sub_readouts = sub_module->getPolyModulations();
494 all_readouts.insert(sub_readouts.begin(), sub_readouts.end());
495 }
496 return all_readouts;
497 }
498
504 for (Processor* processor : data_->owned_mono_processors)
505 processor->enable(enable);
506
507 for (SynthModule* sub_module : data_->sub_modules)
508 sub_module->enable(enable);
509 }
510
516 void SynthModule::enable(bool enable) {
517 if (enabled() == enable)
518 return;
519
522 }
523
529 void SynthModule::addMonoProcessor(Processor* processor, bool own) {
530 getMonoRouter()->addProcessor(processor);
531 if (own)
532 data_->owned_mono_processors.push_back(processor);
533 }
534
543
544} // namespace vital
Adds two input buffers sample-by-sample.
Definition operators.h:205
A special sum operator that can accumulate control-rate and audio-rate modulation signals.
Definition operators.h:256
@ kReset
Definition operators.h:259
static const ValueDetails & getDetails(const std::string &name)
Definition synth_parameters.h:200
Base class for all signal-processing units in Vital.
Definition processor.h:212
void plugNext(const Output *source)
Connects an external Output to the first available (unplugged) input.
Definition processor.cpp:104
force_inline bool enabled() const
Checks if this Processor is enabled.
Definition processor.h:310
void useInput(Input *input)
Uses an existing Input object as this Processor's first input.
Definition processor.cpp:126
void plug(const Output *source)
Connects an external Output to this Processor's first input.
Definition processor.cpp:79
force_inline Output * output(unsigned int index=0) const
Retrieves the Output pointer at a given index.
Definition processor.h:616
virtual void enable(bool enable)
Enables or disables this Processor.
Definition processor.h:318
virtual void reset(poly_mask reset_mask)
Called to reset the Processor's per-voice state (e.g., on note-on).
Definition processor.h:267
virtual ProcessorRouter * getMonoRouter()
Gets the mono router that corresponds to this ProcessorRouter.
Definition processor_router.cpp:263
virtual void addIdleProcessor(Processor *processor)
Adds a Processor that should remain idle (not processed) in the router.
Definition processor_router.cpp:146
virtual void addProcessor(Processor *processor)
Adds a Processor to be managed by this router.
Definition processor_router.cpp:121
A Value processor that smoothly transitions from its current value to a target value.
Definition smooth_value.h:23
A helper class to track the "status" of a particular Output as a poly_float value.
Definition synth_module.h:35
A ProcessorRouter that encapsulates a cohesive unit of functionality in the synthesizer.
Definition synth_module.h:129
Processor * getPolyModulationDestination(std::string name)
Retrieves a poly modulation destination by name.
Definition synth_module.cpp:394
output_map & getModulationSources()
Returns a reference to the map of modulation sources.
Definition synth_module.cpp:454
Output * createPolyModControl(std::string name, bool audio_rate=false, bool smooth_value=false, Output *internal_modulation=nullptr, Input *reset=nullptr)
Creates a polyphonic mod control, including applying parameter scaling.
Definition synth_module.cpp:173
virtual output_map & getMonoModulations()
Returns a reference to the map of mono modulation readouts.
Definition synth_module.cpp:481
void addMonoProcessor(Processor *processor, bool own=true)
Adds a mono processor to this module.
Definition synth_module.cpp:529
Value * createBaseControl(std::string name, bool audio_rate=false, bool smooth_value=false)
Creates a simple control processor for a given parameter name.
Definition synth_module.cpp:22
void addIdleMonoProcessor(Processor *processor)
Adds a mono processor that is considered idle (not part of main processing chain).
Definition synth_module.cpp:540
std::shared_ptr< ModuleData > data_
Shared data storage for this SynthModule.
Definition synth_module.h:354
ValueSwitch * getMonoModulationSwitch(std::string name)
Retrieves a mono modulation switch by name.
Definition synth_module.cpp:412
input_map & getPolyModulationDestinations()
Returns a reference to the map of poly modulation destinations.
Definition synth_module.cpp:472
control_map getControls()
Returns a map of all controls from this module and its submodules.
Definition synth_module.cpp:341
ValueSwitch * getPolyModulationSwitch(std::string name)
Retrieves a poly modulation switch by name.
Definition synth_module.cpp:424
Processor * getMonoModulationDestination(std::string name)
Retrieves a mono modulation destination by name.
Definition synth_module.cpp:382
Processor * getModulationDestination(std::string name, bool poly)
Retrieves a modulation destination Processor by name and poly mode.
Definition synth_module.cpp:374
virtual output_map & getPolyModulations()
Returns a reference to the map of poly modulation readouts.
Definition synth_module.cpp:490
Output * createTempoSyncSwitch(std::string name, Processor *frequency, const Output *beats_per_second, bool poly, Input *midi=nullptr)
Creates a tempo sync switch that toggles between tempo-based frequency and free-running frequency.
Definition synth_module.cpp:289
Output * getModulationSource(std::string name)
Retrieves a modulation source output by name.
Definition synth_module.cpp:350
input_map & getMonoModulationDestinations()
Returns a reference to the map of mono modulation destinations.
Definition synth_module.cpp:463
ValueSwitch * getModulationSwitch(std::string name, bool poly)
Retrieves a modulation switch by name and poly mode.
Definition synth_module.cpp:406
Output * createBaseModControl(std::string name, bool audio_rate=false, bool smooth_value=false, Output *internal_modulation=nullptr)
Creates a base mod control, which is a control combined with a modulation input.
Definition synth_module.cpp:59
void updateAllModulationSwitches()
Updates all modulation switches based on whether their destinations have inputs.
Definition synth_module.cpp:436
void createStatusOutput(std::string name, Output *source)
Creates a status output associated with a given Output.
Definition synth_module.cpp:337
void enableOwnedProcessors(bool enable)
Enables or disables all owned processors.
Definition synth_module.cpp:503
virtual void enable(bool enable) override
Enables or disables this SynthModule and its owned processors.
Definition synth_module.cpp:516
Output * createMonoModControl(std::string name, bool audio_rate=false, bool smooth_value=false, Output *internal_modulation=nullptr)
Creates a monophonic mod control, including applying parameter scaling.
Definition synth_module.cpp:104
const StatusOutput * getStatusOutput(std::string name) const
Retrieves a StatusOutput by name.
Definition synth_module.cpp:362
Chooses a frequency based on tempo sync or direct frequency modes.
Definition operators.h:580
@ kTempoIndex
Definition operators.h:593
@ kSync
Definition operators.h:595
@ kKeytrackTune
Definition operators.h:598
@ kKeytrackTranspose
Definition operators.h:597
@ kFrequency
Definition operators.h:592
@ kMidi
Definition operators.h:596
@ kBeatsPerSecond
Definition operators.h:594
A Processor that maintains and outputs a constant poly_float value.
Definition value.h:24
A specialized Value processor that selects one of multiple input sources to pass through,...
Definition value_switch.h:28
void addProcessor(Processor *processor)
Adds a processor to be enabled or disabled depending on the selected source.
Definition value_switch.h:69
@ kSwitch
The selected input signal output.
Definition value_switch.h:36
virtual void set(poly_float value) override
Sets the control value, selecting the corresponding input as the output.
Definition value_switch.cpp:21
Control-rate addition of two values.
Definition operators.h:700
Control-rate operator cubing a single value.
Definition operators.h:786
Control-rate operator computing x^3 + offset.
Definition operators.h:845
Raises scale_ to the power of the input value (clamped to [min_, max_]).
Definition operators.h:912
Control-rate operator computing x^2 + offset.
Definition operators.h:823
Control-rate operator raising a single value to the 4th power.
Definition operators.h:804
Control-rate operator computing x^4 + offset.
Definition operators.h:867
Control-rate operator computing sqrt(x) + offset.
Definition operators.h:890
A control-rate version of the SmoothValue that smooths values at control rate instead of audio rate.
Definition smooth_value.h:91
Control-rate operator squaring a single value.
Definition operators.h:768
A control-rate variant of the Value processor.
Definition value.h:82
Control-rate version of summing multiple inputs into one.
Definition operators.h:944
#define VITAL_ASSERT(x)
Definition common.h:11
Contains classes and functions used within the Vital synthesizer framework.
std::map< std::string, Output * > output_map
Maps parameter names to Output pointers, representing output signals from various modules.
Definition synth_types.h:229
std::map< std::string, Value * > control_map
Maps parameter names to Value pointers representing synth control parameters.
Definition synth_types.h:214
std::map< std::string, Processor * > input_map
Maps parameter names to Processor pointers, representing input processors for signals.
Definition synth_types.h:224
float mono_float
Definition common.h:33
Declares the SmoothValue classes, providing time-smoothed transitions for values.
Represents a connection to an Output from another Processor.
Definition processor.h:128
Holds and manages a buffer of samples (poly_float) for a Processor's output.
Definition processor.h:35
Holds metadata about a single parameter (control) in the Vital synthesizer.
Definition synth_parameters.h:23
mono_float max
Maximum parameter value.
Definition synth_parameters.h:41
mono_float post_offset
Offset applied after scaling (for certain scale types).
Definition synth_parameters.h:43
@ kQuartic
Parameter value transformed by a quartic curve.
Definition synth_parameters.h:33
@ kSquareRoot
Parameter value transformed by a square root function.
Definition synth_parameters.h:34
@ kCubic
Parameter value transformed by a cubic curve.
Definition synth_parameters.h:32
@ kExponential
Parameter value transformed by an exponential function.
Definition synth_parameters.h:35
@ kQuadratic
Parameter value transformed by a quadratic curve.
Definition synth_parameters.h:31
mono_float min
Minimum parameter value.
Definition synth_parameters.h:40
mono_float default_value
Default value for the parameter.
Definition synth_parameters.h:42
ValueScale value_scale
The scaling mode of the parameter value.
Definition synth_parameters.h:45
Defines the SynthModule class which extends ProcessorRouter to form a building block of the Vital syn...
Declares the ValueSwitch class, which allows switching the output buffer based on a control value.