1 /*
2 ** Surge Synthesizer is Free and Open Source Software
3 **
4 ** Surge is made available under the Gnu General Public License, v3.0
5 ** https://www.gnu.org/licenses/gpl-3.0.en.html
6 **
7 ** Copyright 2004-2020 by various individuals as described by the Git transaction log
8 **
9 ** All source at: https://github.com/surge-synthesizer/surge.git
10 **
11 ** Surge was a commercial product from 2004-2018, with Copyright and ownership
12 ** in that period held by Claes Johanson at Vember Audio. Claes made Surge
13 ** open source in September 2018.
14 */
15
16 #pragma once
17 #include "globals.h"
18 #include "Parameter.h"
19 #include "ModulationSource.h"
20 #include "Wavetable.h"
21
22 #include "tinyxml/tinyxml.h"
23 #include "filesystem/import.h"
24
25 #include <vector>
26 #include <memory>
27 #include <mutex>
28 #include <atomic>
29 #include <cstdint>
30 #include <fstream>
31 #include <iterator>
32 #include <functional>
33 #include <unordered_map>
34 #include <map>
35 #include <utility>
36 #include <random>
37 #include <chrono>
38
39 #include "Tunings.h"
40
41 #if WINDOWS
42 #define PATH_SEPARATOR '\\'
43 #else
44 #define PATH_SEPARATOR '/'
45 #endif
46
47 // patch layer
48
49 const int n_oscs = 3;
50 const int n_lfos_voice = 6;
51 const int n_lfos_scene = 6;
52 const int n_lfos = n_lfos_voice + n_lfos_scene;
53 const int n_osc_params = 7;
54 const int n_fx_params = 12;
55 const int n_fx_slots = 8;
56 const int FIRipol_M = 256;
57 const int FIRipol_M_bits = 8;
58 const int FIRipol_N = 12;
59 const int FIRoffset = FIRipol_N >> 1;
60 const int FIRipolI16_N = 8;
61 const int FIRoffsetI16 = FIRipolI16_N >> 1;
62
63 // XML storage fileformat revision
64 // 0 -> 1 new EG attack shapes (0>1, 1>2, 2>2)
65 // 1 -> 2 new LFO EG stages (if (decay == max) sustain = max else sustain = min
66 // 2 -> 3 filter subtypes added: comb defaults to 1 and legacy ladder to 3
67 // 3 -> 4 comb +/- combined into one filter type (subtype 0, 0->0; 0, 1->1; 1,0 -> 2; 1,1 -> 3 )
68 // 4 -> 5 stereo filter configuration got seperate pan controls
69 // 5 -> 6 new filter sound in v1.2 (same parameters, different sound - changed resonance response)
70 // 6 -> 7 custom controller state now stored (in DAW recall)
71 // 7 -> 8 larger resonance range (old filters are set to subtype 1)
72 // pan2 -> width
73 // 8 -> 9 macros extended to 8 (offset IDs larger than ctrl7 by + 1)
74 // macros can have names (guess for pre-rev9 patches)
75 // 9 -> 10 added Character parameter
76 // 10 -> 11 (1.6.2 release) added DAW extra state
77 // 11 -> 12 (1.6.3 release) added new parameters to the Distortion effect
78 // 12 -> 13 (1.7.0 release) slider deactivation
79 // sine LP/HP filters
80 // sine/FM2/FM3 feedback extension/bipolar
81 // 13 -> 14 (1.8.0 nightlies) add phaser stages/center/spread parameters
82 // add ability to configure vocoder modulator mono/sterao/L/R
83 // add comb filter tuning and compatibility block
84 // 14 -> 15 (1.8.0 release) apply the great filter remap (GitHub issue #3006)
85 // 15 -> 16 (1.9.0 release) implement oscillator retrigger consistently (GitHub issue #3171)
86 // add tuningApplicationMode to patch
87
88 const int ff_revision = 16;
89
90 extern float sinctable alignas(16)[(FIRipol_M + 1) * FIRipol_N * 2];
91 extern float sinctable1X alignas(16)[(FIRipol_M + 1) * FIRipol_N];
92 extern short sinctableI16 alignas(16)[(FIRipol_M + 1) * FIRipolI16_N];
93 extern float table_envrate_lpf alignas(16)[512], table_envrate_linear alignas(16)[512],
94 table_glide_exp alignas(16)[512], table_glide_log alignas(16)[512];
95 extern float table_note_omega alignas(16)[2][512];
96 extern float samplerate, samplerate_inv;
97 extern double dsamplerate, dsamplerate_inv;
98 extern double dsamplerate_os, dsamplerate_os_inv;
99
100 const int n_scene_params = 271;
101 const int n_global_params = 113;
102 const int n_global_postparams = 1;
103 const int n_total_params = n_global_params + 2 * n_scene_params + n_global_postparams;
104 const int metaparam_offset = 20480; // has to be bigger than total + 16 * 130 for fake VST3 mapping
105 const int n_scenes = 2;
106 const int n_filterunits_per_scene = 2;
107 const int n_max_filter_subtypes = 16;
108
109 enum scene_mode
110 {
111 sm_single = 0,
112 sm_split,
113 sm_dual,
114 sm_chsplit,
115
116 n_scene_modes,
117 };
118
119 const char scene_mode_names[n_scene_modes][16] = {
120 "Single",
121 "Key Split",
122 "Dual",
123 "Channel Split",
124 };
125
126 enum play_mode
127 {
128 pm_poly = 0,
129 pm_mono,
130 pm_mono_st,
131 pm_mono_fp,
132 pm_mono_st_fp,
133 pm_latch,
134
135 n_play_modes,
136 };
137 const char play_mode_names[n_play_modes][64] = {
138 "Poly",
139 "Mono",
140 "Mono (Single Trigger)",
141 "Mono (Fingered Portamento)",
142 "Mono (Single Trigger + Fingered Portamento)",
143 "Latch (Monophonic)",
144 };
145
146 enum porta_curve
147 {
148 porta_log = -1,
149 porta_lin = 0,
150 porta_exp = 1,
151 };
152
153 enum deform_type
154 {
155 type_1,
156 type_2,
157 type_3,
158
159 n_deform_types,
160 };
161
162 enum lfo_trigger_mode
163 {
164 lm_freerun = 0,
165 lm_keytrigger,
166 lm_random,
167
168 n_lfo_trigger_modes,
169 };
170
171 const char lfo_trigger_mode_names[n_lfo_trigger_modes][16] = {
172 "Freerun",
173 "Keytrigger",
174 "Random",
175 };
176
177 enum character_mode
178 {
179 cm_warm = 0,
180 cm_neutral,
181 cm_bright,
182
183 n_character_modes,
184 };
185 const char character_names[n_character_modes][16] = {
186 "Warm",
187 "Neutral",
188 "Bright",
189 };
190
191 // IDs are used in resources/data/configuration.xml
192 enum osc_type
193 {
194 ot_classic = 0, // #0
195 ot_sine, // #1
196 ot_wavetable, // #2
197 ot_shnoise, // #3
198 ot_audioinput, // #4
199 // used to be just FM (FM3 on GUI), so name it like this, but enum order has to stick
200 ot_FM3, // #5
201 ot_FM2, // #6
202 ot_window, // #7
203 ot_modern, // #8
204 ot_string, // #9
205 ot_twist, // #10
206 ot_alias, // #11
207 // ot_phasedist,
208 // ot_chaos,
209 // ot_FM4,
210
211 n_osc_types,
212 };
213
214 const char osc_type_names[n_osc_types][24] = {"Classic", "Sine", "Wavetable", "S&H Noise",
215 "Audio In", "FM3", "FM2", "Window",
216 "Modern", "String", "Twist", "Alias",
217 /*, "Phase Distortion", "Chaos", "FM4"*/};
218
219 const char osc_type_shortnames[n_osc_types][24] = {"Classic", "Sine", "WT", "S&H Noise",
220 "Audio In", "FM3", "FM2", "Window",
221 "Modern", "String", "Twist", "Alias",
222 /*, "PD", "Chaos", "FM4"*/};
223
224 const char window_names[9][16] = {
225 "Triangle", "Cosine", "Blend 1", "Blend 2", "Blend 3",
226 "Sawtooth", "Sine", "Square", "Rectangle",
227 };
228
uses_wavetabledata(int i)229 inline bool uses_wavetabledata(int i)
230 {
231 switch (i)
232 {
233 case ot_wavetable:
234 case ot_window:
235 return true;
236 }
237 return false;
238 }
239
240 enum fxslot_positions
241 {
242 fxslot_ains1,
243 fxslot_ains2,
244 fxslot_bins1,
245 fxslot_bins2,
246 fxslot_send1,
247 fxslot_send2,
248 fxslot_global1,
249 fxslot_global2
250 };
251
252 const char fxslot_names[8][NAMECHARS] = {
253 "A Insert FX 1", "A Insert FX 2", "B Insert FX 1", "B Insert FX 2",
254 "Send FX 1", "Send FX 2", "Global FX 1", "Global FX 2",
255 };
256
257 enum fx_type
258 {
259 fxt_off = 0,
260 fxt_delay,
261 fxt_reverb,
262 fxt_phaser,
263 fxt_rotaryspeaker,
264 fxt_distortion,
265 fxt_eq,
266 fxt_freqshift,
267 fxt_conditioner,
268 fxt_chorus4,
269 fxt_vocoder,
270 fxt_reverb2,
271 fxt_flanger,
272 fxt_ringmod,
273 fxt_airwindows,
274 fxt_neuron,
275 fxt_geq11,
276 fxt_resonator,
277 fxt_chow,
278 fxt_exciter,
279 fxt_ensemble,
280 fxt_combulator,
281 fxt_nimbus,
282 fxt_tape,
283 fxt_treemonster,
284
285 n_fx_types,
286 };
287
288 const char fx_type_names[n_fx_types][16] = {
289 "Off", "Delay", "Reverb 1", "Phaser", "Rotary", "Distortion", "EQ",
290 "Freq Shift", "Conditioner", "Chorus", "Vocoder", "Reverb 2", "Flanger", "Ring Mod",
291 "Airwindows", "Neuron", "Graphic EQ", "Resonator", "CHOW", "Exciter", "Ensemble",
292 "Combulator", "Nimbus", "Tape", "Treemonster",
293 };
294
295 const char fx_type_shortnames[n_fx_types][8] = {
296 "OFF", "DLY", "RV1", "PH", "ROT", "DIST", "EQ", "FRQ", "DYN", "CH", "VOC", "RV2", "FL",
297 "RM", "AW", "NEU", "GEQ", "RES", "CHW", "XCT", "ENS", "CMB", "NIM", "TAPE", "TM",
298 };
299
300 enum fx_bypass
301 {
302 fxb_all_fx = 0,
303 fxb_no_sends,
304 fxb_scene_fx_only,
305 fxb_no_fx,
306
307 n_fx_bypass,
308 };
309
310 const char fxbypass_names[n_fx_bypass][32] = {
311 "All FX",
312 "No Send FX",
313 "No Send And Global FX",
314 "All FX Off",
315 };
316
317 enum filter_config
318 {
319 fc_serial1 = 0,
320 fc_serial2,
321 fc_serial3,
322 fc_dual1,
323 fc_dual2,
324 fc_stereo,
325 fc_ring,
326 fc_wide,
327
328 n_filter_configs,
329 };
330
331 const char fbc_names[n_filter_configs][16] = {
332 "Serial 1", "Serial 2", "Serial 3", "Dual 1", "Dual 2", "Stereo", "Ring", "Wide",
333 };
334
335 enum fm_routing
336 {
337 fm_off = 0,
338 fm_2to1,
339 fm_3to2to1,
340 fm_2and3to1,
341
342 n_fm_routings,
343 };
344
345 const char fmr_names[n_fm_routings][16] = {
346 "Off",
347 "2 > 1",
348 "3 > 2 > 1",
349 "2 > 1 < 3",
350 };
351
352 enum lfo_type
353 {
354 lt_sine = 0,
355 lt_tri,
356 lt_square,
357 lt_ramp,
358 lt_noise,
359 lt_snh,
360 lt_envelope,
361 lt_stepseq,
362 lt_mseg,
363 lt_function,
364
365 n_lfo_types,
366 };
367
368 const char lt_names[n_lfo_types][32] = {
369 "Sine", "Triangle", "Square", "Sawtooth", "Noise",
370 "Sample & Hold", "Envelope", "Step Sequencer", "MSEG", "Function (work in progress!)",
371 };
372
373 const int lt_num_deforms[n_lfo_types] = {
374 3, // lt_sine
375 3, // lt_tri
376 0, // lt_square
377 3, // lt_ramp
378 0, // lt_noise
379 0, // lt_snh
380 3, // lt_envelope
381 0, // lt_stepseq
382 0, // lt_mseg
383 3, // lt_function
384 };
385
386 /*
387 * With 1.8 for compactness all the filter names and stuff went to a separate header
388 */
389 #include "FilterConfiguration.h"
390
391 enum ws_type
392 {
393 wst_none = 0,
394 wst_soft,
395 wst_hard,
396 wst_asym,
397 wst_sine,
398 wst_digital,
399
400 n_ws_types,
401 };
402
403 const char wst_names[n_ws_types][16] = {
404 "Off", "Soft", "Hard", "Asymmetric", "Sine", "Digital",
405 };
406
407 extern float waveshapers alignas(16)[n_ws_types][1024];
408
409 enum env_mode
410 {
411 emt_digital = 0,
412 emt_analog,
413
414 n_env_modes,
415 };
416
417 const char em_names[n_env_modes][16] = {
418 "Digital",
419 "Analog",
420 };
421
422 enum adsr_purpose
423 {
424 adsr_ampeg = 0,
425 adsr_filteg
426 };
427
428 /*
429 * How does the sustain pedal work in mono mode? Current modes for this are:
430 *
431 * HOLD_ALL_NOTES (the default). If you release a note with the pedal down
432 * it does not release
433 *
434 * RELEASE_IF_OTHERS_HELD. If you release a note, and no other notes are down,
435 * do not release. But if you release and another note is down, return to that
436 * note (basically allow sustain pedal trills).
437 */
438 enum MonoPedalMode
439 {
440 HOLD_ALL_NOTES,
441 RELEASE_IF_OTHERS_HELD
442 };
443
444 enum MonoVoicePriorityMode
445 {
446 NOTE_ON_LATEST_RETRIGGER_HIGHEST, // The legacy mode for 1.7.1 and earlier
447 ALWAYS_LATEST, // Could also be called "NOTE_ON_LATEST_RETRIGGER_LATEST"
448 ALWAYS_HIGHEST,
449 ALWAYS_LOWEST,
450 };
451
452 struct MidiKeyState
453 {
454 int keystate;
455 char lastdetune;
456 int64_t voiceOrder;
457 };
458
459 struct MidiChannelState
460 {
461 MidiKeyState keyState[128];
462 int nrpn[2], nrpn_v[2];
463 int rpn[2], rpn_v[2];
464 int pitchBend;
465 bool nrpn_last;
466 bool hold;
467 float pan;
468 float pitchBendInSemitones;
469 float pressure;
470 float timbre;
471 };
472
473 // I have used the ordering here in SurgeGUIEditor to iterate. Be careful if type or retrigger move
474 // from first/last position.
475 struct OscillatorStorage : public CountedSetUserData // The counted set is the wavetables
476 {
477 Parameter type;
478 Parameter pitch, octave;
479 Parameter p[n_osc_params];
480 Parameter keytrack, retrigger;
481 Wavetable wt;
482 #define WAVETABLE_DISPLAY_NAME_SIZE 256
483 char wavetable_display_name[WAVETABLE_DISPLAY_NAME_SIZE];
484 void *queue_xmldata;
485 int queue_type;
486
487 struct ExtraConfigurationData
488 {
489 static constexpr size_t max_config = 64;
490 int nData = 0;
491 float data[max_config];
492 } extraConfig;
493
getCountedSetSizeOscillatorStorage494 virtual int getCountedSetSize() { return wt.n_tables; }
495 };
496
497 struct FilterStorage
498 {
499 Parameter type; // NOTE: In SurgeSynthesizer we assume that type and subtype are
500 Parameter subtype; // adjacent in param space. See comment there.
501 Parameter cutoff;
502 Parameter resonance;
503 Parameter envmod;
504 Parameter keytrack;
505 };
506
507 struct WaveshaperStorage
508 {
509 Parameter type;
510 Parameter drive;
511 };
512
513 struct ADSRStorage
514 {
515 Parameter a, d, s, r;
516 Parameter a_s, d_s, r_s;
517 Parameter mode;
518 };
519
520 // I have used the ordering here in CLFOGui to iterate.
521 // Be careful if Rate or LFO EG Release move from first/last position!
522 struct LFOStorage
523 {
524 Parameter rate, shape, start_phase, magnitude, deform;
525 Parameter trigmode, unipolar;
526 Parameter delay, hold, attack, decay, sustain, release;
527 };
528
529 struct FxStorage
530 {
531 // Just a heads up: if you change this, please go look at fx_reorder in SurgeStorage too!
532 Parameter type;
533 Parameter return_level;
534 Parameter p[n_fx_params];
535 };
536
537 struct SurgeSceneStorage
538 {
539 OscillatorStorage osc[n_oscs];
540 Parameter pitch, octave;
541 Parameter fm_depth, fm_switch;
542 Parameter drift, noise_colour, keytrack_root;
543 Parameter osc_solo;
544 Parameter level_o1, level_o2, level_o3, level_noise, level_ring_12, level_ring_23, level_pfg;
545 Parameter mute_o1, mute_o2, mute_o3, mute_noise, mute_ring_12,
546 mute_ring_23; // all mute parameters must be contiguous!
547 Parameter solo_o1, solo_o2, solo_o3, solo_noise, solo_ring_12,
548 solo_ring_23; // all solo parameters must be contiguous!
549 Parameter route_o1, route_o2, route_o3, route_noise, route_ring_12, route_ring_23;
550 Parameter vca_level;
551 Parameter pbrange_dn, pbrange_up;
552 Parameter vca_velsense;
553 Parameter polymode;
554 Parameter portamento;
555 Parameter volume, pan, width;
556 Parameter send_level[2];
557
558 FilterStorage filterunit[2];
559 Parameter f2_cutoff_is_offset, f2_link_resonance;
560 WaveshaperStorage wsunit;
561 ADSRStorage adsr[2];
562 LFOStorage lfo[n_lfos];
563 Parameter feedback, filterblock_configuration, filter_balance;
564 Parameter lowcut;
565
566 std::vector<ModulationRouting> modulation_scene, modulation_voice;
567 std::vector<ModulationSource *> modsources;
568
569 bool modsource_doprocess[n_modsources];
570
571 MonoVoicePriorityMode monoVoicePriorityMode = ALWAYS_LATEST;
572 };
573
574 const int n_stepseqsteps = 16;
575 struct StepSequencerStorage
576 {
577 float steps[n_stepseqsteps];
578 int loop_start, loop_end;
579 float shuffle;
580 uint64_t trigmask;
581 };
582
583 const int max_msegs = 128;
584 struct MSEGStorage
585 {
586 struct segment // If you add something here fix blankAllSegments in MSEGModulationHelper
587 {
588 float duration;
589 float dragDuration; // Snap mode helper
590 float v0;
591 float dragv0; // In snap mode, this is the location we are dragged to.
592 // It is just convenience storage.
593 float nv1; // This is the v0 of the neighbor and is here just for convenience.
594 // MSEGModulationHelper::rebuildCache will set it
595 float dragv1; // Only used in the endpoint
596 float cpduration, cpv, dragcpv, dragcpratio = 0.5;
597 bool useDeform = true;
598 bool invertDeform = false;
599 enum Type
600 {
601 LINEAR = 1,
602 QUAD_BEZIER,
603 SCURVE,
604 SINE,
605 STAIRS,
606 BROWNIAN,
607 SQUARE,
608 TRIANGLE,
609 HOLD,
610 SAWTOOTH,
611 RESERVED, // used to be Spike, but it broke some MSEG model constraints,
612 // so we ditched it - can add a different curve type later on!
613 BUMP,
614 SMOOTH_STAIRS,
615 } type;
616 };
617
618 // These values are streamed so please don't change the integer values!
619 enum EndpointMode
620 {
621 LOCKED = 1,
622 FREE = 2
623 } endpointMode = FREE;
624
625 // These values are streamed so please don't change the integer values!
626 enum EditMode
627 {
628 ENVELOPE = 0, // no constraints on horizontal time axis
629 LFO = 1, // MSEG editing is constrained to just one phase unit (0 ... 1)
630 // useful for single cycle waveform editing
631 } editMode = ENVELOPE;
632
633 // These values are streamed so please don't change the integer values!
634 enum LoopMode
635 {
636 ONESHOT = 1, // Play the MSEG front to back and then output the final value
637 LOOP = 2, // Play the MSEG front to loop end and then return to loop start
638 GATED_LOOP = 3 // Play the MSEG front to loop end, then return to loop start,
639 // but if at any time a note off is generated, jump to loop end
640 // at current value and progress to end once
641 } loopMode = LOOP;
642
643 int loop_start = -1, loop_end = -1; // -1 signifies the entire MSEG in this context
644
645 int n_activeSegments = 0;
646 std::array<segment, max_msegs> segments;
647
648 // These are calculated values which derive from the segment, which we cache for efficiency.
649 // If you edit the segments, then MSEGModulationHelper::rebuildCache can rebuild them
650 float totalDuration;
651 std::array<float, max_msegs> segmentStart, segmentEnd;
652 float durationToLoopEnd;
653 float durationLoopStartToLoopEnd;
654 float envelopeModeDuration = -1, envelopeModeNV1 = -2; // -2 as sentinel since NV1 is -1/1
655
656 /*
657 * These "UI" type things we decided, late in 1.8, are actually a critical part of
658 * the modelling experience, so even if they aren't required to actually evaluate
659 * the model, we decided to move them to the model and the patch, rather than the
660 * dawExtraState. Note that vSnap and hSnap are also streamed into the DES at write
661 * time and optionally streamed out based on a user preference.
662 */
663 static constexpr float defaultVSnapDefault = 0.25, defaultHSnapDefault = 0.125;
664 float vSnapDefault = defaultVSnapDefault, hSnapDefault = defaultHSnapDefault;
665 float vSnap = 0, hSnap = 0;
666 float axisWidth = -1, axisStart = -1;
667
668 static constexpr float minimumDuration = 0.0;
669 };
670
671 struct FormulaModulatorStorage
672 { // Currently an unused placeholder
673 };
674
675 /*
676 ** There is a collection of things we want your DAW to save about your particular instance
677 ** but don't want saved in your patch. So have this extra structure in the patch which we
678 ** can activate/populate from the DAW hosts. See #915
679 */
680 struct DAWExtraStateStorage
681 {
682 bool isPopulated = false;
683
684 /*
685 * Here's the prescription to add something to the editor state
686 *
687 * 1. Add it here with a reasonable default.
688 * 2. In the SurgeGUIEditor Constructor, read off the value
689 * 3. In SurgeGUIEditor::populateDawExtraState write it
690 * 4. In SurgeGUIEditor::loadDawExtraState read it (this will probably be pretty similar to
691 * the constructor code in step 4, but this is the step when restoring, as opposed to
692 * creating an object).
693 * 5. In SurgePatch load/save XML write and read it
694 *
695 * Then the state will survive create/destroy and save/restore
696 */
697 struct EditorState
698 {
699 int instanceZoomFactor = -1;
700 int current_scene = 0;
701 int current_fx = 0;
702 int current_osc[n_scenes] = {0};
703 modsources modsource = ms_lfo1, modsource_editor[n_scenes] = {ms_lfo1, ms_lfo1};
704 bool isMSEGOpen = false;
705
706 bool msegStateIsPopulated = false;
707 struct
708 {
709 int timeEditMode = 0;
710 } msegEditState[n_scenes][n_lfos];
711
712 struct
713 {
714 bool hasCustomEditor = false;
715 } oscExtraEditState[n_scenes][n_lfos];
716 } editor;
717
718 bool mpeEnabled = false;
719 int mpePitchBendRange = -1;
720
721 bool hasScale = false;
722 std::string scaleContents = "";
723
724 bool hasMapping = false;
725 std::string mappingContents = "";
726 std::string mappingName = "";
727
728 std::unordered_map<int, int> midictrl_map; // param -> midictrl
729 std::unordered_map<int, int> customcontrol_map; // custom controller number -> midicontrol
730
731 int monoPedalMode = 0;
732 int oddsoundRetuneMode = 0;
733 };
734
735 struct PatchTuningStorage
736 {
737 bool tuningStoredInPatch = false;
738 std::string scaleContents = "";
739 std::string mappingContents = "";
740 std::string mappingName = "";
741 };
742
743 class SurgeStorage;
744
745 class SurgePatch
746 {
747 public:
748 SurgePatch(SurgeStorage *storage);
749 ~SurgePatch();
750 void init_default_values();
751 void update_controls(bool init = false, void *init_osc = 0, bool from_stream = false);
752 void do_morph();
753 void copy_scenedata(pdata *, int scene);
754 void copy_globaldata(pdata *);
755
756 // load/save
757 // void load_xml();
758 // void save_xml();
759 void load_xml(const void *data, int size, bool preset);
760 unsigned int save_xml(void **data);
761 unsigned int save_RIFF(void **data);
762
763 // Factor these so the LFO preset mechanism can use them as well
764 void msegToXMLElement(MSEGStorage *ms, TiXmlElement &parent) const;
765 void msegFromXMLElement(MSEGStorage *ms, TiXmlElement *parent, bool restoreSnaps) const;
766 void stepSeqToXmlElement(StepSequencerStorage *ss, TiXmlElement &parent, bool streamMask) const;
767 void stepSeqFromXmlElement(StepSequencerStorage *ss, TiXmlElement *parent) const;
768
769 void load_patch(const void *data, int size, bool preset);
770 unsigned int save_patch(void **data);
771
772 // data
773 SurgeSceneStorage scene[n_scenes], morphscene;
774 FxStorage fx[n_fx_slots];
775 // char name[NAMECHARS];
776 int scene_start[n_scenes], scene_size;
777 Parameter scene_active, scenemode, scenemorph,
778 splitpoint; // streaming name for splitpoint is splitkey (due to legacy)
779 Parameter volume;
780 Parameter polylimit;
781 Parameter fx_bypass, fx_disable;
782 Parameter character;
783
784 StepSequencerStorage stepsequences[n_scenes][n_lfos];
785 MSEGStorage msegs[n_scenes][n_lfos];
786 FormulaModulatorStorage formulamods[n_scenes][n_lfos];
787
788 PatchTuningStorage patchTuning;
789 DAWExtraStateStorage dawExtraState;
790
791 std::vector<Parameter *> param_ptr;
792 std::vector<int> easy_params_id;
793
794 std::vector<ModulationRouting> modulation_global;
795 pdata scenedata[n_scenes][n_scene_params];
796 pdata globaldata[n_global_params];
797 void *patchptr;
798 SurgeStorage *storage;
799
800 // metadata
801 std::string name, category, author, comment;
802 // metaparameters
803 #define CUSTOM_CONTROLLER_LABEL_SIZE 16
804 char CustomControllerLabel[n_customcontrollers][CUSTOM_CONTROLLER_LABEL_SIZE];
805
806 int streamingRevision;
807 int currentSynthStreamingRevision;
808
809 /*
810 * This parameter exists for the very special reason of maintaing compatibility with
811 * comb filter tuning for streaming versions which are older than Surge v1.8.
812 * Prior to that, the comb filter had a calculation error in the time and was out of tune,
813 * but that lead to a unique sound in existing patches. So we introduce this parameter
814 * which allows us to leave old patches mis-tuned in FilterCoefficientMaker and is handled
815 * properly at stream time and so on.
816 */
817 bool correctlyTuneCombFilter = true;
818
819 FilterSelectorMapper patchFilterSelectorMapper;
820 };
821
822 struct Patch
823 {
824 std::string name;
825 fs::path path;
826 int category;
827 int order;
828 bool fav;
829 };
830
831 struct PatchCategory
832 {
833 std::string name;
834 int order;
835 std::vector<PatchCategory> children;
836 bool isRoot;
837
838 int internalid;
839 int numberOfPatchesInCatgory;
840 int numberOfPatchesInCategoryAndChildren;
841 };
842
843 enum surge_copysource
844 {
845 cp_off = 0,
846 cp_scene,
847 cp_osc,
848 cp_lfo,
849 cp_oscmod,
850
851 n_copysources,
852 };
853
854 class MTSClient;
855
856 /* storage layer */
857
858 class alignas(16) SurgeStorage
859 {
860 public:
861 float audio_in alignas(16)[2][BLOCK_SIZE_OS];
862 float audio_in_nonOS alignas(16)[2][BLOCK_SIZE];
863 float audio_otherscene alignas(
864 16)[2][BLOCK_SIZE_OS]; // this will be a pointer to an aligned 2 x BLOCK_SIZE_OS array
865 // float sincoffset alignas(16)[(FIRipol_M)*FIRipol_N]; // deprecated
866
867 SurgeStorage(std::string suppliedDataPath = "");
868
869 static constexpr int tuning_table_size = 512;
870 float table_pitch alignas(16)[tuning_table_size];
871 float table_pitch_inv alignas(16)[tuning_table_size];
872 float table_note_omega alignas(16)[2][tuning_table_size];
873 float table_pitch_ignoring_tuning alignas(16)[tuning_table_size];
874 float table_pitch_inv_ignoring_tuning alignas(16)[tuning_table_size];
875 float table_note_omega_ignoring_tuning alignas(16)[2][tuning_table_size];
876 // 2^0 -> 2^+/-1/12th. See comment in note_to_pitch
877 float table_two_to_the alignas(16)[1001];
878 float table_two_to_the_minus alignas(16)[1001];
879
880 ~SurgeStorage();
881
882 std::unique_ptr<SurgePatch> _patch;
883
884 SurgePatch &getPatch();
885
886 float pitch_bend;
887
888 float vu_falloff;
889 float temposyncratio, temposyncratio_inv; // 1.f is 120 BPM
890 double songpos;
891 void init_tables();
892 float nyquist_pitch;
893 int last_key[2]; // TODO: FIX SCENE ASSUMPTION?
894 TiXmlElement *getSnapshotSection(const char *name);
895 void load_midi_controllers();
896 void write_midi_controllers_to_user_default();
897 void save_snapshots();
898 int controllers[n_customcontrollers];
899 float poly_aftertouch[2][128]; // TODO: FIX SCENE ASSUMPTION?
900 float modsource_vu[n_modsources];
901 void setSamplerate(float sr);
902
903 void refresh_wtlist();
904 void refresh_wtlistAddDir(bool userDir, std::string subdir);
905 void refresh_patchlist();
906 void refreshPatchlistAddDir(bool userDir, std::string subdir);
907
908 void refreshPatchOrWTListAddDir(bool userDir, std::string subdir,
909 std::function<bool(std::string)> filterOp,
910 std::vector<Patch> &items,
911 std::vector<PatchCategory> &categories);
912
913 void perform_queued_wtloads();
914
915 void load_wt(int id, Wavetable *wt, OscillatorStorage *);
916 void load_wt(std::string filename, Wavetable *wt, OscillatorStorage *);
917 bool load_wt_wt(std::string filename, Wavetable *wt);
918 // void load_wt_wav(std::string filename, Wavetable* wt);
919 bool load_wt_wav_portable(std::string filename, Wavetable *wt);
920 void export_wt_wav_portable(std::string fbase, Wavetable *wt);
921 void clipboard_copy(int type, int scene, int entry);
922 void clipboard_paste(int type, int scene, int entry);
923 int get_clipboard_type();
924
925 int getAdjacentWaveTable(int id, bool nextPrev);
926
927 // The in-memory patch database.
928 std::vector<Patch> patch_list;
929 std::vector<PatchCategory> patch_category;
930 int firstThirdPartyCategory;
931 int firstUserCategory;
932 std::vector<int> patchOrdering;
933 std::vector<int> patchCategoryOrdering;
934
935 // The in-memory wavetable database.
936 std::vector<Patch> wt_list;
937 std::vector<PatchCategory> wt_category;
938 int firstThirdPartyWTCategory;
939 int firstUserWTCategory;
940 std::vector<int> wtOrdering;
941 std::vector<int> wtCategoryOrdering;
942
943 std::string wtpath;
944 std::string datapath;
945 std::string userDataPath;
946 std::string userDefaultFilePath;
947 std::string userFXPath;
948 std::string installedPath;
949
950 std::string userMidiMappingsPath;
951 std::map<std::string, TiXmlDocument> userMidiMappingsXMLByName;
952 void rescanUserMidiMappings();
953 void loadMidiMappingByName(std::string name);
954 void storeMidiMappingToName(std::string name);
955
956 // float table_sin[512],table_sin_offset[512];
957 std::mutex waveTableDataMutex;
958 std::recursive_mutex modRoutingMutex;
959 Wavetable WindowWT;
960
961 // hardclip
962 enum HardClipMode
963 {
964 HARDCLIP_TO_18DBFS = 1,
965 HARDCLIP_TO_0DBFS,
966 BYPASS_HARDCLIP // scene only
967 } hardclipMode = HARDCLIP_TO_18DBFS,
968 sceneHardclipMode[n_scenes] = {HARDCLIP_TO_18DBFS, HARDCLIP_TO_18DBFS};
969
970 float note_to_pitch(float x);
971 float note_to_pitch_inv(float x);
972 float note_to_pitch_ignoring_tuning(float x);
973 float note_to_pitch_inv_ignoring_tuning(float x);
note_to_pitch_tuningctr(float x)974 inline float note_to_pitch_tuningctr(float x)
975 {
976 return note_to_pitch(x + scaleConstantNote()) * scaleConstantPitchInv();
977 }
note_to_pitch_inv_tuningctr(float x)978 inline float note_to_pitch_inv_tuningctr(float x)
979 {
980 return note_to_pitch_inv(x + scaleConstantNote()) * scaleConstantPitch();
981 }
982
983 void note_to_omega(float, float &, float &);
984 void note_to_omega_ignoring_tuning(float, float &, float &);
985
986 /*
987 * Tuning Support and Tuning State. Here's how it works
988 *
989 * We have SCL, KBM and Tunings and use the nomelcature "Scale", "Mapping", and "Tuning"
990 * consistently as of 1.9. The Tuning is the combination of a scale and mapping which results
991 * in pitches. We now consistently manage that three-part state in the functions below and
992 * make them available here as read-only state. (I mean I guess you could write directly
993 * to these members, but don't).
994 *
995 * The functions we provide are
996 * - retuneTo12TetCStandardMapping (basically resets everytnig)
997 * - retuneTo12TETScale (resets scale, leaves mapping intact)
998 * - reemapToConcertCKeyboard (leaves scale, resets mapping)
999 * - retuneToScale( s ) (resets scale, leaves mapping)
1000 * - remapToKeyboard( k ) (leaves scale, resets mapping)
1001 * - retuneTosCaleAndMapping() ( pretty obvious right?)
1002 */
1003 Tunings::Tuning twelveToneStandardMapping;
1004 Tunings::Tuning currentTuning;
1005 Tunings::Scale currentScale;
1006 Tunings::KeyboardMapping currentMapping;
1007 bool isStandardTuning = true, isStandardScale = true, isStandardMapping = true;
1008
1009 enum TuningApplicationMode
1010 {
1011 RETUNE_ALL = 0, // These values are streamed so don't change them if you add
1012 RETUNE_MIDI_ONLY = 1
1013 } tuningApplicationMode = RETUNE_MIDI_ONLY; // This is the default as of 1.9/sv16
1014
1015 float tuningPitch = 32.0f, tuningPitchInv = 0.03125f;
1016
1017 Tunings::Scale cachedToggleOffScale;
1018 Tunings::KeyboardMapping cachedToggleOffMapping;
1019 bool isToggledToCache;
1020 bool togglePriorState[3];
1021 void toggleTuningToCache();
1022
retuneToScale(const Tunings::Scale & s)1023 bool retuneToScale(const Tunings::Scale &s)
1024 {
1025 currentScale = s;
1026 isStandardTuning = false;
1027 isStandardScale = false;
1028 return resetToCurrentScaleAndMapping();
1029 }
retuneTo12TETScale()1030 bool retuneTo12TETScale()
1031 {
1032 currentScale = Tunings::evenTemperament12NoteScale();
1033 isStandardScale = true;
1034 isStandardTuning = isStandardMapping;
1035
1036 return resetToCurrentScaleAndMapping();
1037 }
retuneTo12TETScaleC261Mapping()1038 bool retuneTo12TETScaleC261Mapping()
1039 {
1040 currentScale = Tunings::evenTemperament12NoteScale();
1041 currentMapping = Tunings::KeyboardMapping();
1042 isStandardTuning = true;
1043 isStandardScale = true;
1044 isStandardMapping = true;
1045 resetToCurrentScaleAndMapping();
1046 init_tables();
1047 return true;
1048 }
remapToKeyboard(const Tunings::KeyboardMapping & k)1049 bool remapToKeyboard(const Tunings::KeyboardMapping &k)
1050 {
1051 currentMapping = k;
1052 isStandardMapping = false;
1053 isStandardTuning = false;
1054
1055 tuningPitch = k.tuningFrequency / Tunings::MIDI_0_FREQ;
1056 tuningPitchInv = 1.0 / tuningPitch;
1057 return resetToCurrentScaleAndMapping();
1058 }
1059
remapToConcertCKeyboard()1060 bool remapToConcertCKeyboard()
1061 {
1062 auto k = Tunings::KeyboardMapping();
1063 currentMapping = k;
1064 isStandardMapping = true;
1065 isStandardTuning = isStandardScale;
1066
1067 tuningPitch = 32.0;
1068 tuningPitchInv = 1.0 / 32.0;
1069 return resetToCurrentScaleAndMapping();
1070 }
1071
retuneAndRemapToScaleAndMapping(const Tunings::Scale & s,const Tunings::KeyboardMapping & k)1072 bool retuneAndRemapToScaleAndMapping(const Tunings::Scale &s, const Tunings::KeyboardMapping &k)
1073 {
1074 currentMapping = k;
1075 currentScale = s;
1076 isStandardMapping = false;
1077 isStandardScale = false;
1078 isStandardTuning = false;
1079
1080 return resetToCurrentScaleAndMapping();
1081 }
1082
1083 // Critically this does not touch the "isStandard" variables at all
1084 bool resetToCurrentScaleAndMapping();
1085
scaleConstantNote()1086 inline int scaleConstantNote()
1087 {
1088 if (tuningApplicationMode == RETUNE_ALL)
1089 {
1090 return currentMapping.tuningConstantNote;
1091 }
1092 else
1093 {
1094 /*
1095 * In this case the mapping happens at the keyboard layer so
1096 * don't double-retune it
1097 */
1098 return 60;
1099 }
1100 }
scaleConstantPitch()1101 inline float scaleConstantPitch() { return tuningPitch; }
scaleConstantPitchInv()1102 inline float scaleConstantPitchInv()
1103 {
1104 return tuningPitchInv;
1105 } // Obviously that's the inverse of the above
1106
1107 void setTuningApplicationMode(const TuningApplicationMode m);
1108
1109 void initialize_oddsound();
1110 void deinitialize_oddsound();
1111 MTSClient *oddsound_mts_client = nullptr;
1112 std::atomic<bool> oddsound_mts_active;
1113 uint32_t oddsound_mts_on_check = 0;
1114 enum OddsoundRetuneMode
1115 {
1116 RETUNE_CONSTANT = 0,
1117 RETUNE_NOTE_ON_ONLY = 1
1118 } oddsoundRetuneMode = RETUNE_CONSTANT;
1119
1120 /*
1121 * If we tune at keyboard or with MTS, we don't reset the internal tuning table.
1122 * Same if we are in standard tuning. So lets have that condition be done once
1123 */
tuningTableIs12TET()1124 inline bool tuningTableIs12TET()
1125 {
1126 if ((isStandardTuning) || // nothing changed
1127 (oddsound_mts_client && oddsound_mts_active) || // MTS in command
1128 tuningApplicationMode == RETUNE_MIDI_ONLY // tune the keyboard not the tables
1129 )
1130 return true;
1131 return false;
1132 }
1133
guessAtKBMName(const Tunings::KeyboardMapping & k)1134 std::string guessAtKBMName(const Tunings::KeyboardMapping &k)
1135 {
1136 auto res = std::string("");
1137 res += "Root " + std::to_string(k.middleNote);
1138 res += " with note " + std::to_string(k.tuningConstantNote);
1139 res += " @ " + std::to_string(k.tuningFrequency) + "Hz";
1140 return res;
1141 }
1142
1143 /*
1144 * Other users of surge may want to force clients to override user prefs.
1145 * Really we just use this to force the FX bank to 2 decimals for now. But...
1146 */
1147 std::unordered_map<std::string, std::pair<int, std::string>> userPrefOverrides;
1148
1149 ControllerModulationSource::SmoothingMode smoothingMode =
1150 ControllerModulationSource::SmoothingMode::LEGACY;
1151 ControllerModulationSource::SmoothingMode pitchSmoothingMode =
1152 ControllerModulationSource::SmoothingMode::LEGACY;
1153 float mpePitchBendRange = -1.0f;
1154
1155 std::atomic<int> otherscene_clients;
1156
1157 std::unordered_map<int, std::string> helpURL_controlgroup;
1158 std::unordered_map<std::string, std::string> helpURL_paramidentifier;
1159 std::unordered_map<std::string, std::string> helpURL_specials;
1160 // Alternately make this unordered and provide a hash
1161 std::map<std::pair<std::string, int>, std::string> helpURL_paramidentifier_typespecialized;
1162
1163 int subtypeMemory[n_scenes][n_filterunits_per_scene][n_fu_types];
1164 MonoPedalMode monoPedalMode = HOLD_ALL_NOTES;
1165
1166 private:
1167 TiXmlDocument snapshotloader;
1168 std::vector<Parameter> clipboard_p;
1169 int clipboard_type;
1170 StepSequencerStorage clipboard_stepsequences[n_lfos];
1171 MSEGStorage clipboard_msegs[n_lfos];
1172 OscillatorStorage::ExtraConfigurationData clipboard_extraconfig[n_oscs];
1173 std::vector<ModulationRouting> clipboard_modulation_scene, clipboard_modulation_voice;
1174 Wavetable clipboard_wt[n_oscs];
1175 char clipboard_wt_names[n_oscs][256];
1176 MonoVoicePriorityMode clipboard_primode = NOTE_ON_LATEST_RETRIGGER_HIGHEST;
1177
1178 public:
1179 // whether to skip loading, desired while exporting manifests. Only used by LV2 currently.
1180 static bool skipLoadWtAndPatch;
1181
1182 /*
1183 * An RNG which is decoupled from the non-Surge global state and is threadsafe.
1184 * This RNG has the semantic that it is seeded when the first Surge in your session
1185 * uses it on a given thread, and then retains its independent state. It is designed
1186 * to have the same API as std::rand, so 'std::rand -> storage::rand' is a good change.
1187 *
1188 * Reseeding it impacts the global state on that thread.
1189 */
1190 #define STORAGE_USES_INDEPENDENT_RNG 1
1191 #if STORAGE_USES_INDEPENDENT_RNG
1192 /*
1193 * Turn this back on with a different threading check
1194 */
1195 struct RNGGen
1196 {
RNGGenRNGGen1197 RNGGen()
1198 : g(std::chrono::system_clock::now().time_since_epoch().count()), d(0, RAND_MAX),
1199 pm1(-1.f, 1.f), z1(0.f, 1.f), u32(0, 0xFFFFFFFF)
1200 {
1201 }
1202 std::minstd_rand g;
1203 std::uniform_int_distribution<int> d;
1204 std::uniform_real_distribution<float> pm1, z1;
1205 std::uniform_int_distribution<uint32_t> u32;
1206 } rngGen;
1207
1208 #define DEBUG_RNG_THREADING 0
1209 #if DEBUG_RNG_THREADING
1210 pthread_t audioThreadID = 0;
runningOnAudioThread()1211 inline void runningOnAudioThread()
1212 {
1213 if (audioThreadID && pthread_self() != audioThreadID)
1214 {
1215 std::cout << "BUM CALL ON NON AUDIO THREAD" << std::endl;
1216 }
1217 }
1218 #else
1219 #define runningOnAudioThread() (void *)0;
1220 #endif
1221 /*
1222 * These API points are only thread safe on the AUDIO thread.
1223 * If you want to have an independent RNG on another thread, manage
1224 * your lifecycle yourself or if you want make a new instance of the
1225 * Storage::RNGGen utility class above
1226 */
rand()1227 inline int rand()
1228 {
1229 runningOnAudioThread();
1230 return rngGen.d(rngGen.g);
1231 }
rand_u32()1232 inline uint32_t rand_u32()
1233 {
1234 runningOnAudioThread();
1235 return rngGen.u32(rngGen.g);
1236 }
rand_pm1()1237 inline float rand_pm1()
1238 {
1239 runningOnAudioThread();
1240 return rngGen.pm1(rngGen.g);
1241 }
rand_01()1242 inline float rand_01()
1243 {
1244 runningOnAudioThread();
1245 return rngGen.z1(rngGen.g);
1246 }
1247 // void seed_rand(int s) { rngGen.g.seed(s); }
1248 #else
rand()1249 inline int rand() { return std::rand(); }
rand_u32()1250 inline uint32_t rand_u32() { return (uint32_t)(rand_01() * (float)(0xFFFFFFFF)); }
rand_pm1()1251 inline float rand_pm1() { return rand_01() * 2 - 1; }
rand_01()1252 inline float rand_01() { return (float)std::rand() / (float)(RAND_MAX); }
1253 #endif
1254 };
1255
1256 float db_to_linear(float);
1257 float lookup_waveshape(int, float);
1258 float lookup_waveshape_warp(int, float);
1259 float envelope_rate_lpf(float);
1260 float envelope_rate_linear(float);
1261 float envelope_rate_linear_nowrap(float);
1262 float glide_log(float);
1263 float glide_exp(float);
1264
1265 namespace Surge
1266 {
1267 namespace Storage
1268 {
1269 bool isValidName(const std::string &name);
1270 // is this really not in stdlib?
1271 bool isValidUTF8(const std::string &testThis);
1272
1273 std::string findReplaceSubstring(std::string &source, const std::string &from,
1274 const std::string &to);
1275
1276 std::string appendDirectory(const std::string &root, const std::string &path1);
1277 std::string appendDirectory(const std::string &root, const std::string &path1,
1278 const std::string &path2);
1279 } // namespace Storage
1280 } // namespace Surge
1281
1282 /*
1283 ** ToElement does this && check to check nulls (as does ToDocument and so on).
1284 ** gcc -O3 on Linux optimizes that away giving crashes. So do this instead
1285 ** See GitHub issue #469
1286 */
1287 #define TINYXML_SAFE_TO_ELEMENT(expr) ((expr) ? (expr)->ToElement() : NULL)
1288