You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

499 lines
17KB

  1. #ifndef MODULE_MULTIOSCILLATOR_HPP
  2. #define MODULE_MULTIOSCILLATOR_HPP
  3. //----------------------------------------------------------------------
  4. // Multi-oscillator (digital) for drawing.
  5. //----------------------------------------------------------------------
  6. #include "rack.hpp"
  7. using namespace rack;
  8. #include "trowaSoft.hpp"
  9. #include "dsp/digital.hpp"
  10. #define DEBUG 1
  11. #define TROWA_MOSC_DEFAULT_NUM_OSCILLATORS 3 // Default # of oscillators.
  12. #define TROWA_MOSC_DEFAULT_NUM_OSC_OUTPUTS 2 // For a given frequency, how many output signals
  13. #define TROWA_MOSC_KNOB_MIN_V -10.0f // [V]
  14. #define TROWA_MOSC_KNOB_MAX_V 10.0f // [V]
  15. #define TROWA_MOSC_INPUT_MIN_V -10.0f // [V]
  16. #define TROWA_MOSC_INPUT_MAX_V 10.0f // [V]
  17. #define TROWA_MOSC_KNOB_AUX_MIN_V 0.0f // [V] Min knob voltage for AUX
  18. #define TROWA_MOSC_KNOB_AUX_MAX_V 10.0f // [V] Max knob voltage for AUX
  19. #define TROWA_MOSC_AUX_MIN_V -5.0f // [V] Min input voltage for AUX
  20. #define TROWA_MOSC_AUX_MAX_V 5.0f // [V] Max input voltage for AUX
  21. #define TROWA_MOSC_TYPE_INPUT_MIN_V -5.0f // [V]
  22. #define TROWA_MOSC_TYPE_INPUT_MAX_V 5.0f // [V]
  23. #define TROWA_MOSC_MIX_MIN_V 0.0f // [V] Min input knob voltage for MIX
  24. #define TROWA_MOSC_MIX_MAX_V 1.0f // [V] Max input knob voltage for MIX
  25. #define TROWA_MOSC_MIX_DEF_V 0.5f // [V] Default knob voltage for MIX
  26. #define MOSC_FREQ_DEFAULT_HZ 432.0f // Default Frequency [Hz]
  27. #define MOSC_PHASE_SHIFT_DEFAULT_DEG 0.0f // [degrees]
  28. #define MOSC_OFFSET_DEFAULT_V 0.0f // [V]
  29. #define MOSC_AMPLITUDE_DEFAULT_V 5.0f // Default Amplittude [V]
  30. #define MOSC_FREQ_MIN_HZ 0.0f // Min Frequency [Hz]
  31. #define MOSC_PHASE_SHIFT_MIN_DEG -360.0f // [degrees]. Since we will listen to up to -10V, if -5V is input limit this will still give -180
  32. #define MOSC_OFFSET_MIN_V -10.0f // [V]
  33. #define MOSC_AMPLITUDE_MIN_V -10.0f // Min Amplittude [V]
  34. #define MOSC_FREQ_MAX_HZ 20000.0f // Max Frequency [Hz]
  35. #define MOSC_PHASE_SHIFT_MAX_DEG 360.0f // [degrees].
  36. #define MOSC_OFFSET_MAX_V 10.0f // [V]
  37. #define MOSC_AMPLITUDE_MAX_V 10.0f // Max Amplitude [V]
  38. //#define TROWA_MOSC_F_KNOB_MIN_V -20.0f // Frequency
  39. //#define TROWA_MOSC_F_KNOB_MAX_V 20.0f // Frequency
  40. #define TROWA_MOSC_F_KNOB_MIN_V MOSC_FREQ_MIN_HZ // Frequency
  41. #define TROWA_MOSC_F_KNOB_MAX_V MOSC_FREQ_MAX_HZ // Frequency
  42. #define TROWA_MOSC_FREQ_KNOB_NEEDS_CONVERSION 0 // If Knob value is same as the frequency values, then we don't need to convert.
  43. // Wave form type (SINE, SQUARE, TRIANGLE, SAW).
  44. enum WaveFormType {
  45. // Sine
  46. WAVEFORM_SIN,
  47. // Triangle
  48. WAVEFORM_TRI,
  49. // Saw
  50. WAVEFORM_SAW,
  51. // Square
  52. WAVEFORM_SQR,
  53. // The number of wave forms.
  54. NUM_WAVEFORMS
  55. };
  56. // Oscillator output.
  57. struct TS_OscillatorOutput {
  58. // Base param ids for the oscilator
  59. enum BaseParamIds {
  60. // What type of oscillator (SIN, SQU, TRI, SAW). [Voltage Range: +/- 10V]
  61. OUT_OSC_TYPE_PARAM,
  62. // Secondary parameter (i.e. Pulse width for Rectangle, Ramp slope sign for Saw).
  63. OUT_AUX_PARAM,
  64. // Phi_degrees: Phase Shift (degrees) [-360 to 360].
  65. OUT_PHASE_SHIFT_PARAM,
  66. // Mix of the raw with the AM signal. 1.0 is all AM; 0.0 is all raw.
  67. OUT_AM_MIX_PARAM,
  68. // Toggle (Digital or Ring Modulation)
  69. OUT_AM_TYPE_PARAM,
  70. // Number of params for an oscillator.
  71. OUT_NUM_PARAMS
  72. };
  73. // Base input ids for the oscilator
  74. enum BaseInputIds {
  75. // Oscillator type (SIN, SQU, TRI, SAW). [Voltage Range: +/- 5V].
  76. OUT_OSC_TYPE_INPUT,
  77. // Secondary input (i.e. Pulse width for Rectangle, Ramp slope sign for Saw).
  78. OUT_AUX_INPUT,
  79. // Phi_degrees: Phase Shift (degrees) [-360 to 360]. [Voltage Range: +/- 10V]
  80. OUT_PHASE_SHIFT_INPUT,
  81. // Amplitude modulation
  82. OUT_AM_INPUT,
  83. // Number of inputs for an oscillator.
  84. OUT_NUM_INPUTS
  85. };
  86. // Base output ids for the oscillator.
  87. enum BaseOutputIds {
  88. // Raw output.
  89. OUT_RAW_SIGNAL,
  90. // After amplitude modulation.
  91. OUT_MULTIPLIED_SIGNAL,
  92. // Number of outputs for an oscillator.
  93. OUT_NUM_OUTPUTS
  94. };
  95. // Base light ids for the oscillator.
  96. enum BaseLightIds {
  97. OUT_OSC_TYPE_LED,
  98. // On = Ring modulation, OFf = Digital.
  99. OUT_AM_MODE_LED,
  100. OUT_NUM_LIGHTS
  101. };
  102. int outputChannelNumber = 0;
  103. // Phase shift (degrees) from user inputs (not CV).
  104. float ui_phaseShift_deg = 0.0f;
  105. // Phase shift (degrees) from user inputs and CV.
  106. float phaseShift_deg = 0.0f;
  107. // Phase shift (-1 to 1).
  108. float phaseShift_norm = 0.0f;
  109. // Which wave form to output.
  110. WaveFormType waveFormType = WaveFormType::WAVEFORM_SIN;
  111. // Waveform from knob/ui control (not CV).
  112. WaveFormType ui_waveFormType = WaveFormType::WAVEFORM_SIN;
  113. // [Rectangle] Pulse width (normalized 0-1).
  114. // [Ramp] Or >= 0.5f for positive Ramp, < 0.5f for negative Ramp.
  115. float auxParam_norm = 0.5;
  116. // For cycling through waveform types (btn).
  117. SchmittTrigger waveFormTrigger;
  118. // Digital (false) or Ring Mod (true)
  119. bool amRingModulation = false;
  120. // For AM mode (btn). Digital (false) or Ring Mod (true).
  121. SchmittTrigger amRingModulationTrigger;
  122. #if DEBUG
  123. // For debugging:
  124. float lastPhi_deg = 0.0f;
  125. #endif
  126. TS_OscillatorOutput()
  127. {
  128. initialize();
  129. return;
  130. }
  131. //--------------------------------------------------------
  132. // getRampSlope()
  133. // @returns: True for positive slope, false for negative slope.
  134. //--------------------------------------------------------
  135. bool getRampSlope()
  136. {
  137. return auxParam_norm >= 0.5f;
  138. }
  139. //--------------------------------------------------------
  140. // getRectPulseWidth()
  141. // @returns: Pulse width.
  142. //--------------------------------------------------------
  143. bool getRectPulseWidth()
  144. {
  145. return auxParam_norm;
  146. }
  147. //--------------------------------------------------------
  148. // initialize()
  149. // Initialize (UI) values to default values.
  150. //--------------------------------------------------------
  151. void initialize();
  152. //--------------------------------------------------------
  153. // serialize()
  154. // @returns : The TS_Oscillator json node.
  155. //--------------------------------------------------------
  156. json_t* serialize();
  157. //--------------------------------------------------------
  158. // deserialize()
  159. // @rootJ : (IN) The TS_Oscillator json node.
  160. //--------------------------------------------------------
  161. void deserialize(json_t* rootJ);
  162. //--------------------------------------------------------
  163. // setPhaseShift_deg()
  164. // @deg : (IN) The phase shift in degrees.
  165. //--------------------------------------------------------
  166. void setPhaseShift_deg(float deg);
  167. };
  168. // https://www.researchgate.net/publication/230561132_A_Simple_Digital_Model_of_the_Diode-Based_Ring-Modulator
  169. struct TS_RingMod {
  170. // h is a parameter specifying the slope of the linear section.
  171. float h = 0.5f;
  172. // vb is a parameter specifying the equivalent of the diode forward bias voltage.
  173. // Per the googles: Silicon diodes have a forward voltage of approximately 0.7 volts. Germanium diodes have a forward voltage of approximately 0.3 volts.
  174. float v_b = 0.7f;
  175. // vL is a parameter giving the voltage beyond which the function is linear.
  176. float v_L = 1.2f;
  177. inline float diode_shaping(float v_in)
  178. {
  179. if (v_in <= v_b)
  180. {
  181. // Zero
  182. return 0;
  183. }
  184. else if (v_in > v_L)
  185. {
  186. // Linear
  187. float temp = (v_L - v_b);
  188. return h * (v_in - v_L + temp * temp / (2 * (v_L - v_b)));
  189. }
  190. else //if (v_in <= v_L)
  191. {
  192. // Polynomial
  193. float temp = (v_in - v_b);
  194. return h * temp*temp / (2*(v_L - v_b));
  195. }
  196. }
  197. //----------------------------------------------------------
  198. // ringMod()
  199. // Emulate ring modulation. (Figure 4 in paper).
  200. // @v_in : (IN) Voltage input.
  201. // @v_c : (IN) Carrier voltage.
  202. // @returns : The modulator input.
  203. //----------------------------------------------------------
  204. float ringMod(float v_in, float v_c)
  205. {
  206. float voltageA = v_c + v_in / 2; // Top Input
  207. float voltageB = v_c - v_in / 2; // Bottom Input
  208. // Top Block - Bottom Block (Figure 4)
  209. return diode_shaping(voltageA) + diode_shaping(-voltageA) - (diode_shaping(voltageB) + diode_shaping(-voltageB));
  210. }
  211. };
  212. // A base oscillator (basically a frequency) with N waveform outputs based on this frequency
  213. struct TS_Oscillator {
  214. // Base param ids for the oscilator
  215. enum BaseParamIds {
  216. // A_V: Amplitude (Volts). Should not be = 0 (pointless) and max +/-12 V.
  217. OSCWF_AMPLITUDE_PARAM,
  218. // f_Hz: Frequency (Hz)
  219. OSCWF_FREQUENCY_PARAM,
  220. // Phi_degrees: Phase Shift (degrees) [0-360]
  221. OSCWF_PHASE_SHIFT_PARAM,
  222. // y0_V : Offset (Volts). +/- 10 V?
  223. OSCWF_OFFSET_PARAM,
  224. // Sync/Restart waveform.
  225. OSCWF_SYNC_PARAM,
  226. // Number of params for an oscillator.
  227. OSCWF_NUM_PARAMS
  228. };
  229. // Base input ids for the oscilator
  230. enum BaseInputIds {
  231. // A_V: Amplitude (Volts). [Voltage Range: +/-12 V]
  232. OSCWF_AMPLITUDE_INPUT,
  233. // f_Hz: Frequency (Hz). [Voltage Range: +/- 10V]
  234. OSCWF_FREQUENCY_INPUT,
  235. // Phi_degrees: Phase Shift (degrees) [0-360]. [Voltage Range: +/- 10V]
  236. OSCWF_PHASE_SHIFT_INPUT,
  237. // y0_V : Offset (Volts). [Voltage Range: +/- 10V]
  238. OSCWF_OFFSET_INPUT,
  239. // Sync/Restart waveform.
  240. OSCWF_SYNC_INPUT,
  241. // Frequency Modulator Input
  242. OSCWF_FM_INPUT,
  243. // Number of inputs for an oscillator.
  244. OSCWF_NUM_INPUTS
  245. };
  246. // Base output ids for the oscillator.
  247. enum BaseOutputIds {
  248. // Any time sync happens or oscillator is at 0 phase.
  249. OSCWF_SYNC_OUTPUT,
  250. // Number of outputs for an oscillator.
  251. OSCWF_NUM_OUTPUTS
  252. };
  253. // Base light ids for the oscillator.
  254. enum BaseLightIds{
  255. OSCWF_SYNC_LED,
  256. OSCWF_NUM_LIGHTS
  257. };
  258. // Amplitutde (V) (used value).
  259. float amplitude_V = 1.0f;
  260. // Frequency (Hz) (used value).
  261. float frequency_Hz = 500.0f;
  262. // Phase shift (degrees) (used value).
  263. float phaseShift_deg = 0.0f;
  264. // Phase shift (-1 to 1).
  265. float phaseShift_norm = 0.0f;
  266. // Phase shift (radians) (used value).
  267. //float phaseShift_radians = 0.0f;
  268. // Offset (V) (used value).
  269. float offset_V = 0.0f;
  270. // Amplitutde (V) from user inputs (not CV).
  271. float ui_amplitude_V = 1.0f;
  272. // Frequency (Hz) from user inputs (not CV).
  273. float ui_frequency_Hz = 500.0f;
  274. // Phase shift (degrees) from user inputs (not CV).
  275. float ui_phaseShift_deg = 0.0f;
  276. // Offset (V) from user inputs (not CV).
  277. float ui_offset_V = 0.0f;
  278. // Phase from 0-1.
  279. float phase = 0.0f;
  280. // Shift phase from 0-1.
  281. float shiftedPhase = 0.0f;
  282. // The number of output waves.
  283. int numOutputWaveForms = TROWA_MOSC_DEFAULT_NUM_OSC_OUTPUTS;
  284. // The output waveforms
  285. std::vector<TS_OscillatorOutput> outputWaveforms;
  286. /// TODO: Figure out good h, v_b, and v_L.
  287. // Ring modulator.
  288. TS_RingMod ringModulator;
  289. // For synch button detection
  290. SchmittTrigger synchTrigger;
  291. // Sync out
  292. PulseGenerator synchPulse;
  293. //// If this oscillator should sync with another, the source oscillator index.
  294. //int syncSrcOscillatorIx = -1;
  295. //// If this step, the oscillator is restarted either by sync input or by reaching the end.
  296. //bool oscillatorRestart = false;
  297. //--------------------------------------------------------
  298. // TS_Oscillator()
  299. // @numOutWaveForms: (IN) The number of output waveforms we will have from this oscillator.
  300. //--------------------------------------------------------
  301. TS_Oscillator(int numOutWaveForms);
  302. //--------------------------------------------------------
  303. // TS_Oscillator()
  304. //--------------------------------------------------------
  305. TS_Oscillator() : TS_Oscillator(TROWA_MOSC_DEFAULT_NUM_OSC_OUTPUTS)
  306. {
  307. return;
  308. }
  309. //--------------------------------------------------------
  310. // ~TS_Oscillator()
  311. //--------------------------------------------------------
  312. ~TS_Oscillator()
  313. {
  314. outputWaveforms.clear();
  315. return;
  316. }
  317. //--------------------------------------------------------
  318. // initialize()
  319. // Initialize (UI) values to default values.
  320. //--------------------------------------------------------
  321. void initialize();
  322. //--------------------------------------------------------
  323. // serialize()
  324. // @returns : The TS_Oscillator json node.
  325. //--------------------------------------------------------
  326. json_t* serialize();
  327. //--------------------------------------------------------
  328. // deserialize()
  329. // @rootJ : (IN) The TS_Oscillator json node.
  330. //--------------------------------------------------------
  331. void deserialize(json_t* rootJ);
  332. //--------------------------------------------------------
  333. // calculatePhase()
  334. // @dt : (IN) Time elapsed.
  335. // @doSync : (IN) If sync / reset requested.
  336. // @returns: True if shifted phase has reset (gone over 1)
  337. //--------------------------------------------------------
  338. bool calculatePhase(float dt, bool doSync);
  339. //--------------------------------------------------------
  340. // setPhaseShift_deg()
  341. // @deg : (IN) The phase shift in degrees.
  342. //--------------------------------------------------------
  343. void setPhaseShift_deg(float deg);
  344. float calcSin();
  345. float calcSquare();
  346. float calcTri();
  347. float calcSaw();
  348. float calcSin(float phaseShift_n);
  349. float calcRect(float phaseShift_n, float pulseWidth_n);
  350. float calcTri(float phaseShift_n);
  351. float calcSaw(float phaseShift_n, bool posRamp);
  352. };
  353. //===============================================================================
  354. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  355. // multiOscillator
  356. // Simple digital oscillator for drawing.
  357. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  358. //===============================================================================
  359. struct multiOscillator : Module {
  360. // User control parameters
  361. enum ParamIds {
  362. SYNC_PARAM,
  363. OSC_PARAM_START,
  364. NUM_PARAMS = OSC_PARAM_START // Add #oscillators * OSCWF_NUM_PARAMS to this
  365. };
  366. enum InputIds {
  367. SYNC_INPUT,
  368. OSC_INPUT_START,
  369. NUM_INPUTS = OSC_INPUT_START // Add # oscillators * OSCWF_NUM_INPUTS to this
  370. };
  371. enum OutputIds {
  372. SYNC_OUTPUT,
  373. OSC_OUTPUT_START,
  374. NUM_OUTPUTS = OSC_OUTPUT_START // Add # oscillators * OSCWF_NUM_OUTPUTS to this Determined by # of channels
  375. };
  376. enum LightIds {
  377. SYNC_LIGHT,
  378. OSC_LIGHT_START,
  379. NUM_LIGHTS = OSC_LIGHT_START // Add # oscillators
  380. };
  381. // Number of oscillators
  382. int numberOscillators = TROWA_MOSC_DEFAULT_NUM_OSCILLATORS;
  383. // Collection of oscillators.
  384. TS_Oscillator* oscillators = NULL;
  385. // The number of output signals from the oscillator.
  386. int numOscillatorOutputs = TROWA_MOSC_DEFAULT_NUM_OSC_OUTPUTS;
  387. // 3 letter wave form abbreviations.
  388. static const char* WaveFormAbbr[WaveFormType::NUM_WAVEFORMS];// = { "SIN", "TRI", "SAW", "SQR" };
  389. // If this has it controls configured.
  390. bool isInitialized = false;
  391. const float lightLambda = 0.005f;
  392. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  393. // multiOscillator()
  394. // @numOscillators: (IN) Number of oscillators.
  395. // @numOscillatorOutputs: (IN) Number of oscillators output signals (channels per oscillator).
  396. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  397. multiOscillator(int numOscillators, int numOscillatorOutputs);
  398. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  399. // multiOscillator()
  400. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  401. multiOscillator() : multiOscillator(TROWA_MOSC_DEFAULT_NUM_OSCILLATORS, TROWA_MOSC_DEFAULT_NUM_OSC_OUTPUTS) {
  402. return;
  403. }
  404. ~multiOscillator();
  405. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  406. // findSyncedOscillators(void)
  407. // Try to find if osccilator A should be synced to oscillator B.
  408. // @returns: Number of oscillators that have sync.
  409. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  410. int findSyncedOscillators();
  411. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  412. // initializeOscillators(void)
  413. // Set oscillators to default values.
  414. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  415. void initialOscillators() {
  416. for (int i = 0; i < numberOscillators; i++)
  417. {
  418. oscillators[i].initialize();
  419. }
  420. return;
  421. }
  422. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  423. // step(void)
  424. // Process.
  425. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  426. void step() override;
  427. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  428. // reset(void)
  429. // Initialize values.
  430. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  431. void reset() override;
  432. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  433. // randomize(void)
  434. // Randomize button stuff.
  435. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  436. void randomize() override
  437. {
  438. for (int i = 0; i < numberOscillators; i++)
  439. {
  440. for (int j = 0; j < oscillators[i].numOutputWaveForms; j++)
  441. {
  442. oscillators[i].outputWaveforms[j].amRingModulation = (rand() % 100 > 50);
  443. }
  444. }
  445. return;
  446. }
  447. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  448. // toJson(void)
  449. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  450. json_t *toJson() override;
  451. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  452. // fromJson(void)
  453. //-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  454. void fromJson(json_t *rootJ) override;
  455. };
  456. #endif // !MODULE_MULTIOSCILLATOR_HPP