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