Vital
Loading...
Searching...
No Matches
load_save.cpp
Go to the documentation of this file.
1#include "load_save.h"
3#include "sound_engine.h"
4#include "midi_manager.h"
5#include "sample_source.h"
6#include "synth_base.h"
7#include "synth_constants.h"
8#include "synth_oscillator.h"
9
10#define QUOTE(x) #x
11#define STRINGIFY(x) QUOTE(x)
12
13namespace {
14 const std::string kLinuxUserDataDirectory = "~/.local/share/vital/";
15 const std::string kAvailablePacksFile = "available_packs.json";
16 const std::string kInstalledPacksFile = "packs.json";
17
18 Time getBuildTime() {
19 StringArray date_tokens;
20 date_tokens.addTokens(STRINGIFY(BUILD_DATE), true);
21 if (date_tokens.size() != 5)
22 return Time::getCompilationDate();
23
24 int year = date_tokens[0].getIntValue();
25 int month = date_tokens[1].getIntValue() - 1;
26 int day = date_tokens[2].getIntValue();
27 int hour = date_tokens[3].getIntValue();
28 int minute = date_tokens[4].getIntValue();
29
30 return Time(year, month, day, hour, minute);
31 }
32} // namespace
33
34const std::string LoadSave::kUserDirectoryName = "User";
35const std::string LoadSave::kPresetFolderName = "Presets";
36const std::string LoadSave::kWavetableFolderName = "Wavetables";
37const std::string LoadSave::kSkinFolderName = "Skins";
38const std::string LoadSave::kSampleFolderName = "Samples";
39const std::string LoadSave::kLfoFolderName = "LFOs";
40
41const std::string LoadSave::kAdditionalWavetableFoldersName = "wavetable_folders";
42const std::string LoadSave::kAdditionalSampleFoldersName = "sample_folders";
43
44void LoadSave::convertBufferToPcm(json& data, const std::string& field) {
45 if (data.count(field) == 0)
46 return;
47
48 MemoryOutputStream decoded;
49 std::string wave_data = data[field];
50 Base64::convertFromBase64(decoded, wave_data);
51 int size = static_cast<int>(decoded.getDataSize()) / sizeof(float);
52 std::unique_ptr<float[]> float_data = std::make_unique<float[]>(size);
53 memcpy(float_data.get(), decoded.getData(), size * sizeof(float));
54 std::unique_ptr<int16_t[]> pcm_data = std::make_unique<int16_t[]>(size);
55 vital::utils::floatToPcmData(pcm_data.get(), float_data.get(), size);
56
57 String encoded = Base64::toBase64(pcm_data.get(), sizeof(int16_t) * size);
58 data[field] = encoded.toStdString();
59}
60
61void LoadSave::convertPcmToFloatBuffer(json& data, const std::string& field) {
62 if (data.count(field) == 0)
63 return;
64
65 MemoryOutputStream decoded;
66 std::string wave_data = data[field];
67 Base64::convertFromBase64(decoded, wave_data);
68 int size = static_cast<int>(decoded.getDataSize()) / sizeof(int16_t);
69 std::unique_ptr<int16_t[]> pcm_data = std::make_unique<int16_t[]>(size);
70 memcpy(pcm_data.get(), decoded.getData(), size * sizeof(int16_t));
71 std::unique_ptr<float[]> float_data = std::make_unique<float[]>(size);
72 vital::utils::pcmToFloatData(float_data.get(), pcm_data.get(), size);
73
74 String encoded = Base64::toBase64(float_data.get(), sizeof(float) * size);
75 data[field] = encoded.toStdString();
76}
77
78json LoadSave::stateToJson(SynthBase* synth, const CriticalSection& critical_section) {
79 json settings_data;
80 vital::control_map& controls = synth->getControls();
81 for (auto& control : controls)
82 settings_data[control.first] = control.second->value();
83
84 vital::Sample* sample = synth->getSample();
85 if (sample)
86 settings_data["sample"] = sample->stateToJson();
87
88 json modulations;
89 vital::ModulationConnectionBank& modulation_bank = synth->getModulationBank();
90 for (int i = 0; i < vital::kMaxModulationConnections; ++i) {
91 vital::ModulationConnection* connection = modulation_bank.atIndex(i);
92 json modulation_data;
93 modulation_data["source"] = connection->source_name;
94 modulation_data["destination"] = connection->destination_name;
95
96 LineGenerator* line_mapping = connection->modulation_processor->lineMapGenerator();
97 if (!line_mapping->linear())
98 modulation_data["line_mapping"] = line_mapping->stateToJson();
99
100 modulations.push_back(modulation_data);
101 }
102
103 settings_data["modulations"] = modulations;
104
105 if (synth->getWavetableCreator(0)) {
106 json wavetables;
107 for (int i = 0; i < vital::kNumOscillators; ++i) {
108 WavetableCreator* wavetable_creator = synth->getWavetableCreator(i);
109 wavetables.push_back(wavetable_creator->stateToJson());
110 }
111
112 settings_data["wavetables"] = wavetables;
113 }
114
115 json lfos;
116 for (int i = 0; i < vital::kNumLfos; ++i) {
117 LineGenerator* lfo_source = synth->getLfoSource(i);
118 lfos.push_back(lfo_source->stateToJson());
119 }
120
121 settings_data["lfos"] = lfos;
122
123 json data;
124 data["synth_version"] = ProjectInfo::versionString;
125 data["preset_name"] = synth->getPresetName().toStdString();
126 data["author"] = synth->getAuthor().toStdString();
127 data["comments"] = synth->getComments().toStdString();
128 data["preset_style"] = synth->getStyle().toStdString();
129 for (int i = 0; i < vital::kNumMacros; ++i) {
130 std::string name = synth->getMacroName(i).toStdString();
131 data["macro" + std::to_string(i + 1)] = name;
132 }
133 data["settings"] = settings_data;
134 return data;
135}
136
137void LoadSave::loadControls(SynthBase* synth, const json& data) {
138 vital::control_map controls = synth->getControls();
139 for (auto& control : controls) {
140 std::string name = control.first;
141 if (data.count(name)) {
142 vital::mono_float value = data[name];
143 control.second->set(value);
144 }
145 else {
147 control.second->set(details.default_value);
148 }
149 }
150
151 synth->modWheelGuiChanged(controls["mod_wheel"]->value());
152}
153
154void LoadSave::loadModulations(SynthBase* synth, const json& modulations) {
155 synth->clearModulations();
156 vital::ModulationConnectionBank& modulation_bank = synth->getModulationBank();
157 int index = 0;
158 for (const json& modulation : modulations) {
159 std::string source = modulation["source"];
160 std::string destination = modulation["destination"];
161 vital::ModulationConnection* connection = modulation_bank.atIndex(index);
162 index++;
163
164 if (synth->getEngine()->getModulationSource(source) == nullptr ||
165 synth->getEngine()->getMonoModulationDestination(destination) == nullptr) {
166 continue;
167 }
168
169 if (source.length() && destination.length()) {
170 connection->source_name = source;
171 connection->destination_name = destination;
172 synth->connectModulation(connection);
173 }
174
175 if (modulation.count("line_mapping"))
176 connection->modulation_processor->lineMapGenerator()->jsonToState(modulation["line_mapping"]);
177 else
178 connection->modulation_processor->lineMapGenerator()->initLinear();
179 }
180}
181
182void LoadSave::loadSample(SynthBase* synth, const json& json_sample) {
183 vital::Sample* sample = synth->getSample();
184 if (sample)
185 sample->jsonToState(json_sample);
186}
187
188void LoadSave::loadWavetables(SynthBase* synth, const json& wavetables) {
189 if (synth->getWavetableCreator(0) == nullptr)
190 return;
191
192 int i = 0;
193 for (const json& wavetable : wavetables) {
194 WavetableCreator* wavetable_creator = synth->getWavetableCreator(i);
195 wavetable_creator->jsonToState(wavetable);
196 wavetable_creator->render();
197 i++;
198 }
199}
200
201void LoadSave::loadLfos(SynthBase* synth, const json& lfos) {
202 int i = 0;
203 for (const json& lfo : lfos) {
204 LineGenerator* lfo_source = synth->getLfoSource(i);
205 lfo_source->jsonToState(lfo);
206 lfo_source->render();
207 i++;
208 }
209}
210
211void LoadSave::loadSaveState(std::map<std::string, String>& state, json data) {
212 if (data.count("preset_name")) {
213 std::string preset_name = data["preset_name"];
214 state["preset_name"] = preset_name;
215 }
216
217 if (data.count("author")) {
218 std::string author = data["author"];
219 state["author"] = author;
220 }
221
222 if (data.count("comments")) {
223 std::string comments = data["comments"];
224 state["comments"] = comments;
225 }
226
227 if (data.count("preset_style")) {
228 std::string style = data["preset_style"];
229 state["style"] = style;
230 }
231
232 for (int i = 0; i < vital::kNumMacros; ++i) {
233 std::string key = "macro" + std::to_string(i + 1);
234 if (data.count(key)) {
235 std::string name = data[key];
236 state[key] = name;
237 }
238 else
239 state[key] = "MACRO " + std::to_string(i + 1);
240 }
241}
242
243void LoadSave::initSaveInfo(std::map<std::string, String>& save_info) {
244 save_info["preset_name"] = "";
245 save_info["author"] = "";
246 save_info["comments"] = "";
247 save_info["style"] = "";
248
249 for (int i = 0; i < vital::kNumMacros; ++i)
250 save_info["macro" + std::to_string(i + 1)] = "MACRO " + std::to_string(i + 1);
251}
252
254 json settings = state["settings"];
255 json modulations = settings["modulations"];
256 json sample = settings["sample"];
257 json wavetables = settings["wavetables"];
258
259 std::string version = state["synth_version"];
260
261 if (compareVersionStrings(version, "0.2.0") < 0 || settings.count("sub_octave")) {
262 int sub_waveform = settings["sub_waveform"];
263 if (sub_waveform == 4)
264 sub_waveform = 5;
265 else if (sub_waveform == 5)
266 sub_waveform = 4;
267 settings["sub_waveform"] = sub_waveform;
268
269 int sub_octave = settings["sub_octave"];
270 settings["sub_transpose"] = vital::kNotesPerOctave * sub_octave;
271
272 int osc_1_filter_routing = settings["osc_1_filter_routing"];
273 int osc_2_filter_routing = settings["osc_2_filter_routing"];
274 int sample_filter_routing = settings["sample_filter_routing"];
275 int sub_filter_routing = settings["sub_filter_routing"];
276 settings["filter_1_osc1_input"] = 1 - osc_1_filter_routing;
277 settings["filter_1_osc2_input"] = 1 - osc_2_filter_routing;
278 settings["filter_1_sample_input"] = 1 - sample_filter_routing;
279 settings["filter_1_sub_input"] = 1 - sub_filter_routing;
280 settings["filter_2_osc1_input"] = osc_1_filter_routing;
281 settings["filter_2_osc2_input"] = osc_2_filter_routing;
282 settings["filter_2_sample_input"] = sample_filter_routing;
283 settings["filter_2_sub_input"] = sub_filter_routing;
284
285 int filter_1_style = settings["filter_1_style"];
286 if (filter_1_style == 2)
287 filter_1_style = 3;
288 else if (filter_1_style == 3)
289 filter_1_style = 2;
290 settings["filter_1_style"] = filter_1_style;
291
292 int filter_2_style = settings["filter_2_style"];
293 if (filter_2_style == 2)
294 filter_2_style = 3;
295 else if (filter_2_style == 3)
296 filter_2_style = 2;
297 settings["filter_2_style"] = filter_2_style;
298 }
299
300 if (compareVersionStrings(version, "0.2.1") < 0) {
301 std::string env_start = "env_";
302
303 for (int i = 0; i < vital::kNumEnvelopes; ++i) {
304 std::string number = std::to_string(i + 1);
305 std::string attack_string = env_start + number + "_attack";
306 std::string decay_string = env_start + number + "_decay";
307 std::string release_string = env_start + number + "_release";
308 if (settings.count(attack_string) == 0)
309 break;
310
311 settings[attack_string] = std::pow(settings[attack_string], 1.0f / 1.5f);
312 settings[decay_string] = std::pow(settings[decay_string], 1.0f / 1.5f);
313 settings[release_string] = std::pow(settings[release_string], 1.0f / 1.5f);
314 }
315
316 if (settings.count("wave_tables"))
317 settings["wavetables"] = settings["wave_tables"];
318 }
319
320 wavetables = settings["wavetables"];
321
322 if (compareVersionStrings(version, "0.2.4") < 0) {
323 int portamento_type = settings["portamento_type"];
324 settings["portamento_force"] = std::max(0, portamento_type - 1);
325
326 if (portamento_type == 0)
327 settings["portamento_time"] = -10.0f;
328 }
329
330 if (compareVersionStrings(version, "0.2.5") < 0) {
331 std::string env_start = "env_";
332
333 for (int i = 0; i < vital::kNumEnvelopes; ++i) {
334 std::string number = std::to_string(i + 1);
335 std::string attack_string = env_start + number + "_attack";
336 std::string decay_string = env_start + number + "_decay";
337 std::string release_string = env_start + number + "_release";
338 if (settings.count(attack_string) == 0)
339 break;
340
341 float adjust_power = 3.0f / 4.0f;
342 settings[attack_string] = std::pow(settings[attack_string], adjust_power);
343 settings[decay_string] = std::pow(settings[decay_string], adjust_power);
344 settings[release_string] = std::pow(settings[release_string], adjust_power);
345 }
346 }
347
348 if (compareVersionStrings(version, "0.2.6") < 0) {
349 std::string lfo_start = "lfo_";
350
351 for (int i = 0; i < vital::kNumLfos; ++i) {
352 std::string number = std::to_string(i + 1);
353 std::string fade_string = lfo_start + number + "_fade_time";
354 std::string delay_string = lfo_start + number + "_delay_time";
355 settings[fade_string] = 0.0f;
356 settings[delay_string] = 0.0f;
357 }
358 }
359
360 if (compareVersionStrings(version, "0.2.7") < 0) {
361 static constexpr float adjustment = 0.70710678119f;
362 float osc_1_level = settings["osc_1_level"];
363 float osc_2_level = settings["osc_2_level"];
364 float sub_level = settings["sub_level"];
365 float sample_level = settings["sample_level"];
366 osc_1_level = adjustment * osc_1_level * osc_1_level;
367 osc_2_level = adjustment * osc_2_level * osc_2_level;
368 sub_level = adjustment * sub_level * sub_level;
369 sample_level = adjustment * sample_level * sample_level;
370
371 settings["osc_1_level"] = sqrtf(osc_1_level);
372 settings["osc_2_level"] = sqrtf(osc_2_level);
373 settings["sub_level"] = sqrtf(sub_level);
374 settings["sample_level"] = sqrtf(sample_level);
375 }
376
377 if (compareVersionStrings(version, "0.3.0") < 0) {
378 float reverb_damping = settings["reverb_damping"];
379 float reverb_feedback = settings["reverb_feedback"];
380 settings["decay_time"] = (reverb_feedback - 0.8f) * 10.0f;
381 settings["reverb_high_shelf_gain"] = -reverb_damping * 4.0f;
382 settings["reverb_pre_high_cutoff"] = 128.0f;
383
384 json new_modulations;
385 for (json& modulation : modulations) {
386 if (modulation["destination"] == "reverb_damping")
387 modulation["destination"] = "reverb_high_shelf_gain";
388 if (modulation["destination"] == "reverb_feedback")
389 modulation["destination"] = "reverb_decay_time";
390
391 new_modulations.push_back(modulation);
392 }
393 modulations = new_modulations;
394 }
395
396 if (compareVersionStrings(version, "0.3.1") < 0) {
397 float sample_transpose = settings["sample_transpose"];
398 float sample_keytrack = settings["sample_keytrack"];
399 if (sample_keytrack)
400 settings["sample_transpose"] = sample_transpose + 28.0f;
401 }
402
403 if (compareVersionStrings(version, "0.3.2") < 0) {
404 float osc_1_transpose = settings["osc_1_transpose"];
405 float osc_1_midi_track = settings["osc_1_midi_track"];
406 if (osc_1_midi_track == 0.0f)
407 settings["osc_1_transpose"] = osc_1_transpose - 48.0f;
408
409 float osc_2_transpose = settings["osc_2_transpose"];
410 float osc_2_midi_track = settings["osc_2_midi_track"];
411 if (osc_2_midi_track == 0.0f)
412 settings["osc_2_transpose"] = osc_2_transpose - 48.0f;
413 }
414
415 if (compareVersionStrings(version, "0.3.4") < 0) {
416 float float_order = settings["effect_chain_order"];
417 int effect_order[vital::constants::kNumEffects];
419 for (int i = 0; i < vital::constants::kNumEffects - 1; ++i) {
420 if (effect_order[i] >= vital::constants::kFilterFx)
421 effect_order[i] += 1;
422 }
424 settings["effect_chain_order"] = vital::utils::encodeOrderToFloat(effect_order, vital::constants::kNumEffects);
425 }
426
427 if (compareVersionStrings(version, "0.3.5") < 0) {
428 float osc_1_distortion_type = settings["osc_1_distortion_type"];
429 float osc_2_distortion_type = settings["osc_2_distortion_type"];
430 if (osc_1_distortion_type >= 10.0f)
431 settings["osc_1_distortion_type"] = osc_1_distortion_type + 1.0f;
432 if (osc_2_distortion_type >= 10.0f)
433 settings["osc_2_distortion_type"] = osc_2_distortion_type + 1.0f;
434 }
435
436 if (compareVersionStrings(version, "0.3.6") < 0) {
437 std::string lfo_start = "lfo_";
438
439 for (int i = 0; i < vital::kNumLfos; ++i) {
440 std::string sync_type_string = lfo_start + std::to_string(i + 1) + "_sync_type";
441 if (settings.count(sync_type_string)) {
442 float value = settings[sync_type_string];
443 if (value >= 2.0f)
444 settings[sync_type_string] = value - 1.0f;
445 }
446 }
447 }
448
449 if (compareVersionStrings(version, "0.3.7") < 0) {
450 convertBufferToPcm(sample, "samples");
451 convertBufferToPcm(sample, "samples_stereo");
452 }
453
454 if (compareVersionStrings(version, "0.4.1") < 0) {
455 bool update = false;
456 json new_modulations;
457 for (json& modulation : modulations) {
458 if (modulation["source"] == "perlin") {
459 update = true;
460 modulation["source"] = "random_1";
461 }
462
463 new_modulations.push_back(modulation);
464 }
465
466 if (update) {
467 modulations = new_modulations;
468 settings["random_1_sync"] = 0.0f;
469 settings["random_1_frequency"] = 1.65149612947f;
470 settings["random_1_stereo"] = 1.0f;
471 }
472 }
473
474 if (compareVersionStrings(version, "0.4.3") < 0) {
475 float osc_1_distortion_type = settings["osc_1_distortion_type"];
476 float osc_1_distortion_amount = settings["osc_1_distortion_amount"];
477 if (osc_1_distortion_type == vital::SynthOscillator::kFormant) {
478 settings["osc_1_distortion_amount"] = 0.5f + 0.5f * osc_1_distortion_amount;
479
480 int index = 1;
481 for (json& modulation : modulations) {
482 if (modulation["destination"] == "osc_1_distortion_amount") {
483 std::string amount_string = "modulation_" + std::to_string(index) + "_amount";
484 float last_amount = settings[amount_string];
485 settings[amount_string] = 0.5f * last_amount;
486 }
487
488 index++;
489 }
490 }
491
492 float osc_2_distortion_type = settings["osc_2_distortion_type"];
493 float osc_2_distortion_amount = settings["osc_2_distortion_amount"];
494 if (osc_2_distortion_type == vital::SynthOscillator::kFormant) {
495 settings["osc_2_distortion_amount"] = 0.5f + 0.5f * osc_2_distortion_amount;
496
497 int index = 1;
498 for (json& modulation : modulations) {
499 if (modulation["destination"] == "osc_2_distortion_amount") {
500 std::string amount_string = "modulation_" + std::to_string(index) + "_amount";
501 float last_amount = settings[amount_string];
502 settings[amount_string] = 0.5f * last_amount;
503 }
504
505 index++;
506 }
507 }
508 }
509
510 if (compareVersionStrings(version, "0.4.4") < 0) {
511 float osc_1_distortion_type = settings["osc_1_distortion_type"];
512 float osc_1_distortion_amount = settings["osc_1_distortion_amount"];
513 if (osc_1_distortion_type == vital::SynthOscillator::kSync) {
514 settings["osc_1_distortion_amount"] = 0.5f + 0.5f * osc_1_distortion_amount;
515
516 int index = 1;
517 for (json& modulation : modulations) {
518 if (modulation["destination"] == "osc_1_distortion_amount") {
519 std::string amount_string = "modulation_" + std::to_string(index) + "_amount";
520 float last_amount = settings[amount_string];
521 settings[amount_string] = 0.5f * last_amount;
522 }
523
524 index++;
525 }
526 }
527
528 float osc_2_distortion_type = settings["osc_2_distortion_type"];
529 float osc_2_distortion_amount = settings["osc_2_distortion_amount"];
530 if (osc_2_distortion_type == vital::SynthOscillator::kSync) {
531 settings["osc_2_distortion_amount"] = 0.5f + 0.5f * osc_2_distortion_amount;
532
533 int index = 1;
534 for (json& modulation : modulations) {
535 if (modulation["destination"] == "osc_2_distortion_amount") {
536 std::string amount_string = "modulation_" + std::to_string(index) + "_amount";
537 float last_amount = settings[amount_string];
538 settings[amount_string] = 0.5f * last_amount;
539 }
540
541 index++;
542 }
543 }
544 }
545
546 if (compareVersionStrings(version, "0.4.5") < 0) {
547 float compressor_low_band = settings["compressor_low_band"];
548 float compressor_high_band = settings["compressor_high_band"];
549 if (compressor_low_band && compressor_high_band)
550 settings["compressor_enabled_bands"] = 0;
551 else if (compressor_low_band)
552 settings["compressor_enabled_bands"] = 1;
553 else if (compressor_high_band)
554 settings["compressor_enabled_bands"] = 2;
555 else
556 settings["compressor_enabled_bands"] = 3;
557 }
558
559 if (compareVersionStrings(version, "0.4.7") < 0 && settings.count("osc_1_distortion_type")) {
560 static const int kRemapResolution = 32;
561
562 float osc_1_distortion_type = settings["osc_1_distortion_type"];
563 if (osc_1_distortion_type)
564 settings["osc_1_distortion_type"] = osc_1_distortion_type - 1.0f;
565
566 float osc_2_distortion_type = settings["osc_2_distortion_type"];
567 if (osc_2_distortion_type)
568 settings["osc_2_distortion_type"] = osc_2_distortion_type - 1.0f;
569
570 if (osc_1_distortion_type == 1.0f)
571 settings["osc_1_spectral_morph_type"] = vital::SynthOscillator::kLowPass;
572
573 if (osc_2_distortion_type == 1.0f)
574 settings["osc_2_spectral_morph_type"] = vital::SynthOscillator::kLowPass;
575
576 json new_modulations;
577 for (json& modulation : modulations) {
578 if (osc_1_distortion_type == 1.0f && modulation["destination"] == "osc_1_distortion_amount")
579 modulation["destination"] = "osc_1_spectral_morph_amount";
580 else if (osc_2_distortion_type == 1.0f && modulation["destination"] == "osc_2_distortion_amount")
581 modulation["destination"] = "osc_2_spectral_morph_amount";
582
583 new_modulations.push_back(modulation);
584 }
585
586 osc_1_distortion_type = settings["osc_1_distortion_type"];
587 osc_2_distortion_type = settings["osc_2_distortion_type"];
588 if (osc_1_distortion_type == 7 || osc_1_distortion_type == 8 || osc_1_distortion_type == 9) {
589 float original_fm_amount = settings["osc_1_distortion_amount"];
590 float new_fm_amount = std::pow(original_fm_amount, 1.0f / 2.0f);
591 settings["osc_1_distortion_amount"] = new_fm_amount;
592
593 int index = 1;
594 for (json& modulation : new_modulations) {
595 if (modulation["destination"] == "osc_1_distortion_amount") {
596 std::string number = std::to_string(index);
597 std::string amount_string = "modulation_" + number + "_amount";
598 float last_amount = settings[amount_string];
599 if (last_amount == 0.0f)
600 continue;
601
602 bool bipolar = settings["modulation_" + number + "_bipolar"] != 0.0f;
603 float min = std::min(original_fm_amount, original_fm_amount + last_amount);
604 float max = std::max(original_fm_amount, original_fm_amount + last_amount);
605
606 if (bipolar) {
607 min = std::min(original_fm_amount + last_amount * 0.5f, original_fm_amount - last_amount * 0.5f);
608 max = std::max(original_fm_amount + last_amount * 0.5f, original_fm_amount - last_amount * 0.5f);
609 }
610
611 float min_target = std::pow(min, 1.0f / 2.0f);
612 float max_target = std::pow(max, 1.0f / 2.0f);
613 float new_amount = max_target - min_target;
614 if (bipolar)
615 new_amount = 2.0f * std::max(new_fm_amount - min_target, max_target - new_fm_amount);
616 settings[amount_string] = new_amount;
617
618 LineGenerator scale;
619 scale.initLinear();
620 scale.setNumPoints(kRemapResolution);
621 for (int i = 0; i < kRemapResolution; ++i) {
622 float t = i / (kRemapResolution - 1.0f);
623 float old_value = vital::utils::interpolate(min, max, t);
624 float adjusted_old_value = std::pow(old_value, 1.0f / 2.0f);
625 float y = 1.0f - (adjusted_old_value - min_target) / new_amount;
626 scale.setPoint(i, std::pair<float, float>(t, y));
627 }
628 modulation["line_mapping"] = scale.stateToJson();
629 }
630 index++;
631 }
632 }
633
634 if (osc_2_distortion_type == 7 || osc_2_distortion_type == 8 || osc_2_distortion_type == 9) {
635 float original_fm_amount = settings["osc_2_distortion_amount"];
636 float new_fm_amount = std::pow(original_fm_amount, 1.0f / 2.0f);
637 settings["osc_2_distortion_amount"] = new_fm_amount;
638
639 int index = 1;
640 for (json& modulation : new_modulations) {
641 if (modulation["destination"] == "osc_2_distortion_amount") {
642 std::string number = std::to_string(index);
643 std::string amount_string = "modulation_" + number + "_amount";
644 float last_amount = settings[amount_string];
645 if (last_amount == 0.0f)
646 continue;
647
648 bool bipolar = settings["modulation_" + number + "_bipolar"] != 0.0f;
649 float min = std::min(original_fm_amount, original_fm_amount + last_amount);
650 float max = std::max(original_fm_amount, original_fm_amount + last_amount);
651
652 if (bipolar) {
653 min = std::min(original_fm_amount + last_amount * 0.5f, original_fm_amount - last_amount * 0.5f);
654 max = std::max(original_fm_amount + last_amount * 0.5f, original_fm_amount - last_amount * 0.5f);
655 }
656
657 float min_target = std::pow(min, 1.0f / 2.0f);
658 float max_target = std::pow(max, 1.0f / 2.0f);
659 float new_amount = max_target - min_target;
660 if (bipolar)
661 new_amount = 2.0f * std::max(new_fm_amount - min_target, max_target - new_fm_amount);
662 settings[amount_string] = new_amount;
663
664 LineGenerator scale;
665 scale.initLinear();
666 scale.setNumPoints(kRemapResolution);
667 for (int i = 0; i < kRemapResolution; ++i) {
668 float t = i / (kRemapResolution - 1.0f);
669 float old_value = vital::utils::interpolate(min, max, t);
670 float adjusted_old_value = std::pow(old_value, 1.0f / 2.0f);
671 float y = 1.0f - (adjusted_old_value - min_target) / new_amount;
672 scale.setPoint(i, std::pair<float, float>(t, y));
673 }
674 modulation["line_mapping"] = scale.stateToJson();
675 }
676 index++;
677 }
678 }
679
680 modulations = new_modulations;
681 }
682
683 if (compareVersionStrings(version, "0.5.0") < 0 && settings.count("sub_on")) {
684 settings["osc_3_on"] = settings["sub_on"];
685 settings["osc_3_level"] = settings["sub_level"];
686 settings["osc_3_pan"] = settings["sub_pan"];
687 settings["osc_3_transpose"] = settings["sub_transpose"];
688
689 if (settings.count("sub_transpose_quantize"))
690 settings["osc_3_transpose_quantize"] = settings["sub_transpose_quantize"];
691
692 settings["osc_3_tune"] = settings["sub_tune"];
693 settings["osc_3_phase"] = 0.25f;
694 settings["osc_3_random_phase"] = 0.0f;
695
696 float sub_waveform = settings["sub_waveform"];
697 settings["osc_3_wave_frame"] = sub_waveform * 257.0f / 6.0f;
698
699 float sub_filter1 = settings["filter_1_sub_input"];
700 float sub_filter2 = settings["filter_2_sub_input"];
701 float sub_direct_out = settings["sub_direct_out"];
702 if (sub_direct_out)
703 settings["osc_3_destination"] = 4.0f;
704 else if (sub_filter1 && sub_filter2)
705 settings["osc_3_destination"] = 2.0f;
706 else if (sub_filter2)
707 settings["osc_3_destination"] = 1.0f;
708 else if (sub_filter1)
709 settings["osc_3_destination"] = 0.0f;
710 else
711 settings["osc_3_destination"] = 3.0f;
712
713 float osc1_filter1 = settings["filter_1_osc1_input"];
714 float osc1_filter2 = settings["filter_2_osc1_input"];
715 if (osc1_filter1 && osc1_filter2)
716 settings["osc_1_destination"] = 2.0f;
717 else if (osc1_filter2)
718 settings["osc_1_destination"] = 1.0f;
719 else if (osc1_filter1)
720 settings["osc_1_destination"] = 0.0f;
721 else
722 settings["osc_1_destination"] = 3.0f;
723
724 float osc2_filter1 = settings["filter_1_osc2_input"];
725 float osc2_filter2 = settings["filter_2_osc2_input"];
726 if (osc2_filter1 && osc2_filter2)
727 settings["osc_2_destination"] = 2.0f;
728 else if (osc2_filter2)
729 settings["osc_2_destination"] = 1.0f;
730 else if (osc2_filter1)
731 settings["osc_2_destination"] = 0.0f;
732 else
733 settings["osc_2_destination"] = 3.0f;
734
735 float sample_filter1 = settings["filter_1_sample_input"];
736 float sample_filter2 = settings["filter_2_sample_input"];
737 if (sample_filter1 && sample_filter2)
738 settings["sample_destination"] = 2.0f;
739 else if (sample_filter2)
740 settings["sample_destination"] = 1.0f;
741 else if (sample_filter1)
742 settings["sample_destination"] = 0.0f;
743 else
744 settings["sample_destination"] = 3.0f;
745
747 WavetableCreator wavetable_creator(&wavetable);
748 wavetable_creator.initPredefinedWaves();
749 wavetable_creator.setName("Sub");
750
751 json new_wavetables;
752 for (int i = (int)wavetables.size() - 1; i >= 0; --i)
753 new_wavetables.push_back(wavetables[i]);
754
755 new_wavetables.push_back(wavetable_creator.stateToJson());
756 settings["wavetables"] = new_wavetables;
757
758 json new_modulations;
759 for (json& modulation : modulations) {
760 if (modulation["destination"] == "sub_transpose")
761 modulation["destination"] = "osc_3_transpose";
762 else if (modulation["destination"] == "sub_tune")
763 modulation["destination"] = "osc_3_tune";
764 else if (modulation["destination"] == "sub_level")
765 modulation["destination"] = "osc_3_level";
766 else if (modulation["destination"] == "sub_pan")
767 modulation["destination"] = "osc_3_pan";
768
769 new_modulations.push_back(modulation);
770 }
771
772 modulations = new_modulations;
773 }
774
775 if (compareVersionStrings(version, "0.5.5") < 0) {
776 float flanger_tempo = settings["flanger_tempo"];
777 settings["flanger_tempo"] = flanger_tempo + 1.0f;
778
779 float phaser_tempo = settings["phaser_tempo"];
780 settings["phaser_tempo"] = phaser_tempo + 1.0f;
781
782 float chorus_tempo = settings["chorus_tempo"];
783 settings["chorus_tempo"] = chorus_tempo + 1.0f;
784
785 float delay_tempo = settings["delay_tempo"];
786 settings["delay_tempo"] = delay_tempo + 1.0f;
787
788 std::string lfo_start = "lfo_";
789 for (int i = 0; i < vital::kNumLfos; ++i) {
790 std::string tempo_string = lfo_start + std::to_string(i + 1) + "_tempo";
791 if (settings.count(tempo_string)) {
792 float tempo = settings[tempo_string];
793 settings[tempo_string] = tempo + 1.0f;
794 }
795 }
796
797 std::string random_start = "random_";
798 for (int i = 0; i < vital::kNumRandomLfos; ++i) {
799 std::string tempo_string = random_start + std::to_string(i + 1) + "_tempo";
800 if (settings.count(tempo_string)) {
801 float tempo = settings[tempo_string];
802 settings[tempo_string] = tempo + 1.0f;
803 }
804 }
805 }
806
807 if (compareVersionStrings(version, "0.5.7") < 0) {
808 settings["delay_aux_sync"] = settings["delay_sync"];
809 settings["delay_aux_frequency"] = settings["delay_frequency"];
810 settings["delay_aux_tempo"] = settings["delay_tempo"];
811
812 float style = settings["delay_style"];
813 if (style)
814 settings["delay_style"] = style + 1.0f;
815 }
816
817 if (compareVersionStrings(version, "0.5.8") < 0)
818 settings["chorus_damping"] = 1.0f;
819
820 if (compareVersionStrings(version, "0.6.5") < 0) {
821 settings["stereo_mode"] = 1.0f;
822 float routing = settings["stereo_routing"];
823 routing *= 0.125f;
824 if (routing < 0.0f)
825 settings["stereo_routing"] = 1.0f - routing;
826 else
827 settings["stereo_routing"] = routing;
828 }
829
830 if (compareVersionStrings(version, "0.6.6") < 0) {
831 float stereo_mode = settings["stereo_mode"];
832 float routing = settings["stereo_routing"];
833 if (stereo_mode == 0.0f)
834 settings["stereo_routing"] = 1.0f - routing;
835 }
836
837 if (compareVersionStrings(version, "0.6.7") < 0) {
838 float chorus_damping = settings["chorus_damping"];
839 settings["chorus_cutoff"] = 20.0f;
840 settings["chorus_spread"] = chorus_damping;
841
842 json new_modulations;
843 for (json& modulation : modulations) {
844 if (modulation["destination"] == "chorus_damping")
845 modulation["destination"] = "chorus_spread";
846
847 new_modulations.push_back(modulation);
848 }
849 modulations = new_modulations;
850 }
851
852 if (compareVersionStrings(version, "0.7.1") < 0) {
853 float osc_1_spectral_morph_type = 0.0f;
854 if (settings.count("osc_1_spectral_morph_type"))
855 osc_1_spectral_morph_type = settings["osc_1_spectral_morph_type"];
856
857 float osc_2_spectral_morph_type = 0.0f;
858 if (settings.count("osc_2_spectral_morph_type"))
859 osc_2_spectral_morph_type = settings["osc_2_spectral_morph_type"];
860
861 if (osc_1_spectral_morph_type == 9.0f) {
862 float osc_1_spectral_morph_amount = settings["osc_1_spectral_morph_amount"];
863 settings["osc_1_spectral_morph_amount"] = -0.5f * osc_1_spectral_morph_amount + 0.5f;
864
865 int index = 1;
866 for (json& modulation : modulations) {
867 if (modulation["destination"] == "osc_1_spectral_morph_amount") {
868 std::string name = "modulation_" + std::to_string(index) + "_amount";
869 float modulation_amount = settings[name];
870 settings[name] = modulation_amount * -0.5f;
871 }
872
873 index++;
874 }
875 }
876 if (osc_2_spectral_morph_type == 9.0f) {
877 float osc_2_spectral_morph_amount = settings["osc_2_spectral_morph_amount"];
878 settings["osc_2_spectral_morph_amount"] = -0.5f * osc_2_spectral_morph_amount + 0.5f;
879
880 int index = 1;
881 for (json& modulation : modulations) {
882 if (modulation["destination"] == "osc_2_spectral_morph_amount") {
883 std::string name = "modulation_" + std::to_string(index) + "_amount";
884 float modulation_amount = settings[name];
885 settings[name] = modulation_amount * -0.5f;
886 }
887
888 index++;
889 }
890 }
891 }
892
893 if (compareVersionStrings(version, "0.7.5") < 0) {
894 static constexpr float kFlangerCenterMultiply = 48.0f / 128.0f;
895 static constexpr float kFlangerCenterOffset = 53.69f;
896 static constexpr float kPhaserCenterMultiply = 48.0f / 128.0f;
897
898 if (settings.count("flanger_center")) {
899 float flanger_center = settings["flanger_center"];
900 settings["flanger_center"] = flanger_center + kFlangerCenterOffset;
901 }
902
903 int index = 1;
904 for (json& modulation : modulations) {
905 if (modulation["destination"] == "flanger_center") {
906 std::string name = "modulation_" + std::to_string(index) + "_amount";
907 float modulation_amount = settings[name];
908 settings[name] = modulation_amount * kFlangerCenterMultiply;
909 }
910 if (modulation["destination"] == "phaser_center") {
911 std::string name = "modulation_" + std::to_string(index) + "_amount";
912 float modulation_amount = settings[name];
913 settings[name] = modulation_amount * kPhaserCenterMultiply;
914 }
915
916 index++;
917 }
918 }
919
920 if (compareVersionStrings(version, "0.7.6") < 0) {
921 int filter_1_model = settings["filter_1_model"];
922 int filter_2_model = settings["filter_2_model"];
923
924 if (filter_1_model == 6) {
925 int filter_1_style = settings["filter_1_style"];
926 if (filter_1_style == 1)
927 settings["filter_1_style"] = 3;
928 }
929
930 if (filter_2_model == 6) {
931 int filter_2_style = settings["filter_2_style"];
932 if (filter_2_style == 1)
933 settings["filter_2_style"] = 3;
934 }
935
936 if (settings.count("filter_fx_model")) {
937 int filter_fx_model = settings["filter_fx_model"];
938 if (filter_fx_model == 6) {
939 int filter_fx_style = settings["filter_fx_style"];
940 if (filter_fx_style == 1)
941 settings["filter_fx_style"] = 3;
942 }
943 }
944 }
945
946 if (compareVersionStrings(version, "0.7.6") < 0) {
947 if (settings.count("osc_1_spectral_morph_type")) {
948 float osc_1_spectral_morph_type = settings["osc_1_spectral_morph_type"];
949 if (osc_1_spectral_morph_type == 10.0f)
950 settings["osc_1_spectral_morph_type"] = 7.0f;
951 }
952
953 if (settings.count("osc_2_spectral_morph_type")) {
954 float osc_2_spectral_morph_type = settings["osc_2_spectral_morph_type"];
955 if (osc_2_spectral_morph_type == 10.0f)
956 settings["osc_2_spectral_morph_type"] = 7.0f;
957 }
958
959 if (settings.count("osc_3_spectral_morph_type")) {
960 float osc_3_spectral_morph_type = settings["osc_3_spectral_morph_type"];
961 if (osc_3_spectral_morph_type == 10.0f)
962 settings["osc_3_spectral_morph_type"] = 7.0f;
963 }
964 }
965
966 if (compareVersionStrings(version, "0.8.1") < 0) {
967 for (int i = 0; i < vital::kNumLfos; ++i) {
968 std::string name = "lfo_" + std::to_string(i) + "_smooth_mode";
969 settings[name] = 0.0f;
970 }
971 }
972
973 if (compareVersionStrings(version, "0.9.0") < 0) {
974 float filter_1_model = settings["filter_1_model"];
975 if (filter_1_model == 4) {
976 settings["filter_1_blend"] = 0.0f;
977 settings["filter_1_style"] = 0.0f;
978 int index = 1;
979 for (json& modulation : modulations) {
980 if (modulation["destination"] == "filter_1_blend") {
981 std::string name = "modulation_" + std::to_string(index) + "_amount";
982 settings[name] = 0.0f;
983 }
984
985 index++;
986 }
987 }
988
989 float filter_2_model = settings["filter_2_model"];
990 if (filter_2_model == 4) {
991 settings["filter_2_blend"] = 0.0f;
992 settings["filter_2_style"] = 0.0f;
993 int index = 1;
994 for (json& modulation : modulations) {
995 if (modulation["destination"] == "filter_2_blend") {
996 std::string name = "modulation_" + std::to_string(index) + "_amount";
997 settings[name] = 0.0f;
998 }
999
1000 index++;
1001 }
1002 }
1003 }
1004
1005 settings["modulations"] = modulations;
1006 settings["sample"] = sample;
1007 state["settings"] = settings;
1008 return state;
1009}
1010
1011bool LoadSave::jsonToState(SynthBase* synth, std::map<std::string, String>& save_info, json data) {
1012 std::string version = data["synth_version"];
1013
1014 int compare_feature_versions = compareFeatureVersionStrings(version, ProjectInfo::versionString);
1015 if (compare_feature_versions > 0)
1016 return false;
1017
1018 int compare_versions = compareVersionStrings(version, ProjectInfo::versionString);
1019 if (compare_versions < 0 || data["settings"].count("sub_octave"))
1020 data = updateFromOldVersion(data);
1021
1022 json settings = data["settings"];
1023 json modulations = settings["modulations"];
1024 json sample = settings["sample"];
1025 json wavetables = settings["wavetables"];
1026 json lfos = settings["lfos"];
1027
1028 loadControls(synth, settings);
1029 loadModulations(synth, modulations);
1030 loadSample(synth, sample);
1031 loadWavetables(synth, wavetables);
1032 loadLfos(synth, lfos);
1033 loadSaveState(save_info, data);
1034 synth->checkOversampling();
1035
1036 return true;
1037}
1038
1039String LoadSave::getAuthorFromFile(const File& file) {
1040 static constexpr int kMaxCharacters = 40;
1041 static constexpr int kMinSize = 60;
1042 FileInputStream file_stream(file);
1043
1044 if (file_stream.getTotalLength() < kMinSize)
1045 return "";
1046
1047 file_stream.readByte();
1048 file_stream.readByte();
1049 MemoryBlock author_memory_block;
1050 file_stream.readIntoMemoryBlock(author_memory_block, 6);
1051
1052 char end_quote = file_stream.readByte();
1053 char colon = file_stream.readByte();
1054 char begin_quote = file_stream.readByte();
1055 if (author_memory_block.toString() != "author" || end_quote != '"' || colon != ':' || begin_quote != '"') {
1056 try {
1057 json parsed_json_state = json::parse(file.loadFileAsString().toStdString(), nullptr, false);
1058 return getAuthor(parsed_json_state);
1059 }
1060 catch (const json::exception& e) {
1061 return "";
1062 }
1063 }
1064
1065 MemoryBlock name_memory_block;
1066 file_stream.readIntoMemoryBlock(name_memory_block, kMaxCharacters);
1067 String name = name_memory_block.toString();
1068
1069 if (!name.contains("\""))
1070 return name.toStdString();
1071
1072 StringArray tokens;
1073 tokens.addTokens(name, "\"", "");
1074
1075 return tokens[0];
1076}
1077
1078String LoadSave::getStyleFromFile(const File& file) {
1079 static constexpr int kMinSize = 5000;
1080 FileInputStream file_stream(file);
1081
1082 if (file_stream.getTotalLength() < kMinSize)
1083 return "";
1084
1085 MemoryBlock style_memory_block;
1086 file_stream.readIntoMemoryBlock(style_memory_block, kMinSize);
1087
1088 StringArray tokens;
1089 tokens.addTokens(style_memory_block.toString(), "\"", "");
1090 bool found_style = false;
1091 for (String token : tokens) {
1092 if (found_style && token.trim() != ":")
1093 return token;
1094 if (token == "preset_style")
1095 found_style = true;
1096 }
1097
1098 return "";
1099}
1100
1101std::string LoadSave::getAuthor(json data) {
1102 if (data.count("author"))
1103 return data["author"];
1104 return "";
1105}
1106
1107std::string LoadSave::getLicense(json data) {
1108 if (data.count("license"))
1109 return data["license"];
1110 return "";
1111}
1112
1114#if defined(JUCE_DATA_STRUCTURES_H_INCLUDED)
1115 PropertiesFile::Options config_options;
1116 config_options.applicationName = "Vial";
1117 config_options.osxLibrarySubFolder = "Application Support";
1118 config_options.filenameSuffix = "config";
1119
1120#ifdef LINUX
1121 config_options.folderName = "." + String(ProjectInfo::projectName).toLowerCase();
1122#else
1123 config_options.folderName = String(ProjectInfo::projectName).toLowerCase();
1124#endif
1125
1126 return config_options.getDefaultFile();
1127#else
1128 return File();
1129#endif
1130}
1131
1132void LoadSave::writeCrashLog(String crash_log) {
1133 File data_dir = getDataDirectory();
1134 if (!data_dir.exists() || !data_dir.isDirectory())
1135 return;
1136 File file = data_dir.getChildFile("crash.txt");
1137 file.replaceWithText(crash_log);
1138}
1139
1140void LoadSave::writeErrorLog(String error_log) {
1141 File data_dir = getDataDirectory();
1142 if (!data_dir.exists() || !data_dir.isDirectory())
1143 return;
1144
1145 File file = getDataDirectory().getChildFile("errors.txt");
1146 file.appendText(error_log + "\n");
1147}
1148
1150#if defined(JUCE_DATA_STRUCTURES_H_INCLUDED)
1151 PropertiesFile::Options config_options;
1152 config_options.applicationName = "Vial";
1153 config_options.osxLibrarySubFolder = "Application Support";
1154 config_options.filenameSuffix = "favorites";
1155
1156#ifdef LINUX
1157 config_options.folderName = "." + String(ProjectInfo::projectName).toLowerCase();
1158#else
1159 config_options.folderName = String(ProjectInfo::projectName).toLowerCase();
1160#endif
1161
1162 return config_options.getDefaultFile();
1163#else
1164 return File();
1165#endif
1166}
1167
1169#if defined(JUCE_DATA_STRUCTURES_H_INCLUDED)
1170 PropertiesFile::Options config_options;
1171 config_options.applicationName = "Vial";
1172 config_options.osxLibrarySubFolder = "Application Support";
1173 config_options.filenameSuffix = "skin";
1174
1175#ifdef LINUX
1176 config_options.folderName = "." + String(ProjectInfo::projectName).toLowerCase();
1177#else
1178 config_options.folderName = String(ProjectInfo::projectName).toLowerCase();
1179#endif
1180
1181 return config_options.getDefaultFile();
1182#else
1183 return File();
1184#endif
1185}
1186
1188 File config_file = getConfigFile();
1189 if (!config_file.exists())
1190 return json();
1191
1192 try {
1193 json parsed = json::parse(config_file.loadFileAsString().toStdString(), nullptr, false);
1194 if (parsed.is_discarded())
1195 return json();
1196 return parsed;
1197 }
1198 catch (const json::exception& e) {
1199 return json();
1200 }
1201}
1202
1204 File favorites_file = getFavoritesFile();
1205 if (!favorites_file.exists())
1206 return json();
1207
1208 try {
1209 json parsed = json::parse(favorites_file.loadFileAsString().toStdString(), nullptr, false);
1210 if (parsed.is_discarded())
1211 return json();
1212 return parsed;
1213 }
1214 catch (const json::exception& e) {
1215 return json();
1216 }
1217}
1218
1219void LoadSave::addFavorite(const File& new_favorite) {
1220 json favorites = getFavoritesJson();
1221 favorites[new_favorite.getFullPathName().toStdString()] = 1;
1222 saveJsonToFavorites(favorites);
1223}
1224
1225void LoadSave::removeFavorite(const File& old_favorite) {
1226 json favorites = getFavoritesJson();
1227 std::string path = old_favorite.getFullPathName().toStdString();
1228
1229 if (favorites.count(path)) {
1230 favorites.erase(path);
1231 saveJsonToFavorites(favorites);
1232 }
1233}
1234
1235std::set<std::string> LoadSave::getFavorites() {
1236 json favorites_json = getFavoritesJson();
1237
1238 std::set<std::string> favorites;
1239 for (auto& pair : favorites_json.items())
1240 favorites.insert(pair.key());
1241
1242 return favorites;
1243}
1244
1246 File config_file = getConfigFile();
1247
1248 if (!config_file.exists())
1249 config_file.create();
1250 config_file.replaceWithText(config_state.dump());
1251}
1252
1254 File favorites_file = getFavoritesFile();
1255
1256 if (!favorites_file.exists())
1257 favorites_file.create();
1258 favorites_file.replaceWithText(favorites_json.dump());
1259}
1260
1261void LoadSave::saveAuthor(std::string author) {
1262 json data = getConfigJson();
1263
1264 data["author"] = author;
1265 saveJsonToConfig(data);
1266}
1267
1268void LoadSave::savePreferredTTWTLanguage(std::string language) {
1269 json data = getConfigJson();
1270 data["ttwt_language"] = language;
1271 saveJsonToConfig(data);
1272}
1273
1275 json data = getConfigJson();
1276
1277 data["synth_version"] = ProjectInfo::versionString;
1278 saveJsonToConfig(data);
1279}
1280
1281void LoadSave::saveContentVersion(std::string version) {
1282 json data = getConfigJson();
1283
1284 data["content_version"] = version;
1285 saveJsonToConfig(data);
1286}
1287
1288void LoadSave::saveUpdateCheckConfig(bool check_for_updates) {
1289 json data = getConfigJson();
1290 data["check_for_updates"] = check_for_updates;
1291 saveJsonToConfig(data);
1292}
1293
1294void LoadSave::saveWorkOffline(bool work_offline) {
1295 json data = getConfigJson();
1296 data["work_offline"] = work_offline;
1297 saveJsonToConfig(data);
1298}
1299
1300void LoadSave::saveLoadedSkin(const std::string& name) {
1301 json data = getConfigJson();
1302 data["loaded_skin"] = name;
1303 saveJsonToConfig(data);
1304}
1305
1306void LoadSave::saveAnimateWidgets(bool animate_widgets) {
1307 json data = getConfigJson();
1308 data["animate_widgets"] = animate_widgets;
1309 saveJsonToConfig(data);
1310}
1311
1312void LoadSave::saveDisplayHzFrequency(bool hz_frequency) {
1313 json data = getConfigJson();
1314 data["hz_frequency"] = hz_frequency;
1315 saveJsonToConfig(data);
1316}
1317
1318void LoadSave::saveAuthenticated(bool authenticated) {
1319 json data = getConfigJson();
1320 data["authenticated"] = authenticated;
1321 saveJsonToConfig(data);
1322}
1323
1324void LoadSave::saveWindowSize(float window_size) {
1325 json data = getConfigJson();
1326 data["window_size"] = window_size;
1327 saveJsonToConfig(data);
1328}
1329
1331 std::wstring chromatic_layout;
1332 wchar_t up_key;
1333 wchar_t down_key;
1334
1335 if (layout) {
1336 chromatic_layout = layout->getLayout();
1337 up_key = layout->getUpKey();
1338 down_key = layout->getDownKey();
1339 }
1340 else {
1341 chromatic_layout = getComputerKeyboardLayout();
1342 std::pair<wchar_t, wchar_t> octave_controls = getComputerKeyboardOctaveControls();
1343 down_key = octave_controls.first;
1344 up_key = octave_controls.second;
1345 }
1346
1347 json layout_data;
1348
1349 layout_data["chromatic_layout"] = chromatic_layout;
1350 layout_data["octave_up"] = up_key;
1351 layout_data["octave_down"] = down_key;
1352
1353 json data = getConfigJson();
1354 data["keyboard_layout"] = layout_data;
1355 saveJsonToConfig(data);
1356}
1357
1359 MidiManager::midi_map midi_learn_map = midi_manager->getMidiLearnMap();
1360
1361 json midi_mapping_data;
1362
1363 for (auto& midi_mapping : midi_learn_map) {
1364 json midi_map_data;
1365 midi_map_data["source"] = midi_mapping.first;
1366
1367 json destinations_data;
1368 for (auto& midi_destination : midi_mapping.second) {
1369 json destination_data;
1370
1371 destination_data["destination"] = midi_destination.first;
1372 destination_data["min_range"] = midi_destination.second->min;
1373 destination_data["max_range"] = midi_destination.second->max;
1374 destinations_data.push_back(destination_data);
1375 }
1376
1377 midi_map_data["destinations"] = destinations_data;
1378 midi_mapping_data.push_back(midi_map_data);
1379 }
1380
1381 json data = getConfigJson();
1382 data["midi_learn"] = midi_mapping_data;
1383 saveJsonToConfig(data);
1384}
1385
1387 json data = getConfigJson();
1388
1389 // Computer Keyboard Layout
1390 if (layout) {
1392 std::pair<wchar_t, wchar_t> octave_controls = getComputerKeyboardOctaveControls();
1393 layout->setDownKey(octave_controls.first);
1394 layout->setUpKey(octave_controls.second);
1395 }
1396
1397 // Midi Learn Map
1398 if (data.count("midi_learn")) {
1399 MidiManager::midi_map midi_learn_map = midi_manager->getMidiLearnMap();
1400
1401 json midi_mapping_data = data["midi_learn"];
1402 for (json& midi_map_data : midi_mapping_data) {
1403 int source = midi_map_data["source"];
1404
1405 if (midi_map_data.count("destinations")) {
1406 json destinations_data = midi_map_data["destinations"];
1407 for (json& midi_destination : destinations_data) {
1408 std::string dest = midi_destination["destination"];
1409 midi_learn_map[source][dest] = &vital::Parameters::getDetails(dest);
1410 }
1411 }
1412 }
1413 midi_manager->setMidiLearnMap(midi_learn_map);
1414 }
1415}
1416
1418 json data = getConfigJson();
1419 if (data.count("data_directory")) {
1420 std::string path = data["data_directory"];
1421 File directory(path);
1422 File packages = directory.getChildFile(kInstalledPacksFile);
1423 return directory.exists() && directory.isDirectory() && packages.exists();
1424 }
1425 return false;
1426}
1427
1429 json data = getConfigJson();
1430 if (data.count("data_directory") == 0)
1431 return File();
1432
1433 std::string path = data["data_directory"];
1434 File directory(path);
1435 if (!directory.exists() || !directory.isDirectory())
1436 return File();
1437
1438 return directory.getChildFile(kAvailablePacksFile);
1439}
1440
1442 File packs_file = getAvailablePacksFile();
1443 if (!packs_file.exists())
1444 return json();
1445
1446 try {
1447 json parsed = json::parse(packs_file.loadFileAsString().toStdString(), nullptr, false);
1448 if (parsed.is_discarded())
1449 return json();
1450 return parsed;
1451 }
1452 catch (const json::exception& e) {
1453 return json();
1454 }
1455}
1456
1458 json data = getConfigJson();
1459 if (data.count("data_directory") == 0)
1460 return File();
1461
1462 std::string path = data["data_directory"];
1463 File directory(path);
1464 if (!directory.exists() || !directory.isDirectory())
1465 return File();
1466
1467 return directory.getChildFile(kInstalledPacksFile);
1468}
1469
1471 File packs_file = getInstalledPacksFile();
1472 if (!packs_file.exists())
1473 return json();
1474
1475 try {
1476 json parsed = json::parse(packs_file.loadFileAsString().toStdString(), nullptr, false);
1477 if (parsed.is_discarded())
1478 return json();
1479 return parsed;
1480 }
1481 catch (const json::exception& e) {
1482 return json();
1483 }
1484}
1485
1487 File packs_file = getInstalledPacksFile();
1488
1489 if (!packs_file.exists())
1490 packs_file.create();
1491 packs_file.replaceWithText(packs.dump());
1492}
1493
1495 json packs = getInstalledPacks();
1496 packs[std::to_string(id)] = 1;
1497 saveInstalledPacks(packs);
1498}
1499
1500void LoadSave::markPackInstalled(const std::string& name) {
1501 json packs = getInstalledPacks();
1502 std::string cleaned = String(name).removeCharacters(" ._").toLowerCase().toStdString();
1503
1504 packs[cleaned] = 1;
1505 saveInstalledPacks(packs);
1506}
1507
1508void LoadSave::saveDataDirectory(const File& data_directory) {
1509 json data = getConfigJson();
1510 std::string path = data_directory.getFullPathName().toStdString();
1511 data["data_directory"] = path;
1512 saveJsonToConfig(data);
1513}
1514
1516 return getDataDirectory().exists();
1517}
1518
1520 json data = getConfigJson();
1521
1522 if (!data.count("synth_version"))
1523 return true;
1524
1525 std::string version = data["synth_version"];
1526 return compareVersionStrings(version, ProjectInfo::versionString) < 0;
1527}
1528
1530 return getDaysToExpire() < 0;
1531}
1532
1534#ifdef EXPIRE_DAYS
1535 return true;
1536#else
1537 return false;
1538#endif
1539}
1540
1542#ifdef EXPIRE_DAYS
1543 Time current_time = Time::getCurrentTime();
1544 Time build_time = getBuildTime();
1545
1546 RelativeTime time_since_compile = current_time - build_time;
1547 int days_since_compile = time_since_compile.inDays();
1548 return EXPIRE_DAYS - days_since_compile;
1549#else
1550 return 0;
1551#endif
1552}
1553
1555 json data = getConfigJson();
1556
1557 if (!data.count("check_for_updates"))
1558 return true;
1559
1560 return data["check_for_updates"];
1561}
1562
1564 json data = getConfigJson();
1565
1566 if (!data.count("work_offline"))
1567 return false;
1568
1569 return data["work_offline"];
1570}
1571
1573 json data = getConfigJson();
1574
1575 if (!data.count("loaded_skin"))
1576 return "";
1577
1578 return data["loaded_skin"];
1579}
1580
1582 json data = getConfigJson();
1583
1584 if (!data.count("animate_widgets"))
1585 return true;
1586
1587 return data["animate_widgets"];
1588}
1589
1591 json data = getConfigJson();
1592
1593 if (!data.count("hz_frequency"))
1594 return false;
1595
1596 return data["hz_frequency"];
1597}
1598
1600 json data = getConfigJson();
1601
1602 if (!data.count("authenticated"))
1603 return false;
1604
1605 return data["authenticated"];
1606}
1607
1609 json data = getConfigJson();
1610
1611 if (!data.count("oversampling_amount"))
1612 return 2;
1613
1614 return data["oversampling_amount"];
1615}
1616
1618 static constexpr float kMinWindowSize = 0.25f;
1619
1620 json data = getConfigJson();
1621
1622 if (!data.count("window_size"))
1623 return 1.0f;
1624
1625 return std::max<float>(kMinWindowSize, data["window_size"]);
1626}
1627
1629 json data = getConfigJson();
1630
1631 if (!data.count("synth_version"))
1632 return "0.0.0";
1633
1634 std::string version = data["synth_version"];
1635 return version;
1636}
1637
1639 json data = getConfigJson();
1640
1641 if (!data.count("content_version"))
1642 return "0.0";
1643
1644 std::string version = data["content_version"];
1645 return version;
1646}
1647
1649 json data = getConfigJson();
1650
1651 if (data.count("keyboard_layout")) {
1652 json layout = data["keyboard_layout"];
1653
1654 if (layout.count("chromatic_layout"))
1655 return layout["chromatic_layout"];
1656 }
1657
1659}
1660
1662 json data = getConfigJson();
1663
1664 if (!data.count("ttwt_language"))
1665 return "";
1666
1667 std::string language = data["ttwt_language"];
1668 return language;
1669}
1670
1671std::string LoadSave::getAuthor() {
1672 json data = getConfigJson();
1673
1674 if (data.count("author"))
1675 return data["author"];
1676
1677 return "";
1678}
1679
1680std::pair<wchar_t, wchar_t> LoadSave::getComputerKeyboardOctaveControls() {
1681 std::pair<wchar_t, wchar_t> octave_controls(vital::kDefaultKeyboardOctaveDown, vital::kDefaultKeyboardOctaveUp);
1682 json data = getConfigJson();
1683
1684 if (data.count("keyboard_layout")) {
1685 json layout = data["keyboard_layout"];
1686 std::wstring down = layout["octave_down"];
1687 std::wstring up = layout["octave_up"];
1688 octave_controls.first = down[0];
1689 octave_controls.second = up[0];
1690 }
1691
1692 return octave_controls;
1693}
1694
1695void LoadSave::saveAdditionalFolders(const std::string& name, std::vector<std::string> folders) {
1696 json data = getConfigJson();
1697 json wavetable_folders;
1698 for (std::string& folder : folders)
1699 wavetable_folders.push_back(folder);
1700 data[name] = wavetable_folders;
1701
1702 saveJsonToConfig(data);
1703}
1704
1705std::vector<std::string> LoadSave::getAdditionalFolders(const std::string& name) {
1706 json data = getConfigJson();
1707 std::vector<std::string> folders;
1708
1709 if (data.count(name)) {
1710 json folder_list = data[name];
1711 for (json& folder : folder_list)
1712 folders.push_back(folder);
1713 }
1714
1715 return folders;
1716}
1717
1719 json data = getConfigJson();
1720 if (data.count("data_directory")) {
1721 std::string path = data["data_directory"];
1722 File folder(path);
1723 if (folder.exists() && folder.isDirectory())
1724 return folder;
1725 }
1726
1727#ifdef LINUX
1728 File directory = File(kLinuxUserDataDirectory);
1729 String xdg_data_home = SystemStats::getEnvironmentVariable ("XDG_DATA_HOME", {});
1730
1731 if (!xdg_data_home.trim().isEmpty())
1732 directory = File(xdg_data_home).getChildFile("vial");
1733
1734#elif defined(__APPLE__)
1735 File home_directory = File::getSpecialLocation(File::userHomeDirectory);
1736 File directory = home_directory.getChildFile("Music").getChildFile("Vial");
1737#else
1738 File documents_dir = File::getSpecialLocation(File::userDocumentsDirectory);
1739 File directory = documents_dir.getChildFile("Vial");
1740#endif
1741
1742 return directory;
1743}
1744
1745std::vector<File> LoadSave::getDirectories(const String& folder_name) {
1746 File data_dir = getDataDirectory();
1747 std::vector<File> directories;
1748
1749 if (!data_dir.exists() || !data_dir.isDirectory())
1750 return directories;
1751
1752 Array<File> sub_folders;
1753 sub_folders.add(data_dir);
1754 data_dir.findChildFiles(sub_folders, File::findDirectories, false);
1755 for (const File& sub_folder : sub_folders) {
1756 File directory = sub_folder.getChildFile(folder_name);
1757 if (directory.exists() && directory.isDirectory())
1758 directories.push_back(directory);
1759 }
1760
1761 return directories;
1762}
1763
1766}
1767
1771
1772std::vector<File> LoadSave::getSkinDirectories() {
1774}
1775
1778}
1779
1780std::vector<File> LoadSave::getLfoDirectories() {
1782}
1783
1785 File directory = getDataDirectory().getChildFile(kUserDirectoryName);
1786 if (!directory.exists())
1787 directory.createDirectory();
1788 return directory;
1789}
1790
1792 File directory = getUserDirectory().getChildFile(kPresetFolderName);
1793 if (!directory.exists())
1794 directory.createDirectory();
1795 return directory;
1796}
1797
1799 File directory = getUserDirectory().getChildFile(kWavetableFolderName);
1800 if (!directory.exists())
1801 directory.createDirectory();
1802 return directory;
1803}
1804
1806 File directory = getUserDirectory().getChildFile(kSkinFolderName);
1807 if (!directory.exists())
1808 directory.createDirectory();
1809 return directory;
1810}
1811
1813 File directory = getUserDirectory().getChildFile(kSampleFolderName);
1814 if (!directory.exists())
1815 directory.createDirectory();
1816 return directory;
1817}
1818
1820 File directory = getUserDirectory().getChildFile(kLfoFolderName);
1821 if (!directory.exists())
1822 directory.createDirectory();
1823 return directory;
1824}
1825
1826void LoadSave::getAllFilesOfTypeInDirectories(Array<File>& files, const String& extensions,
1827 const std::vector<File>& directories) {
1828 files.clear();
1829 for (const File& directory : directories) {
1830 if (directory.exists() && directory.isDirectory())
1831 directory.findChildFiles(files, File::findFiles, true, extensions);
1832 }
1833}
1834
1835void LoadSave::getAllPresets(Array<File>& presets) {
1837}
1838
1842
1843void LoadSave::getAllSkins(Array<File>& skins) {
1845}
1846
1847void LoadSave::getAllLfos(Array<File>& lfos) {
1849}
1850
1851void LoadSave::getAllSamples(Array<File>& samples) {
1853}
1854
1855void LoadSave::getAllUserPresets(Array<File>& presets) {
1856 std::vector<File> directories = {
1857 getDataDirectory().getChildFile(kPresetFolderName),
1859 };
1860 getAllFilesOfTypeInDirectories(presets, String("*.") + vital::kPresetExtension, directories);
1861}
1862
1863void LoadSave::getAllUserWavetables(Array<File>& wavetables) {
1864 std::vector<File> directories = {
1865 getDataDirectory().getChildFile(kWavetableFolderName),
1867 };
1869}
1870
1871void LoadSave::getAllUserLfos(Array<File>& lfos) {
1872 std::vector<File> directories = {
1873 getDataDirectory().getChildFile(kLfoFolderName),
1875 };
1876 getAllFilesOfTypeInDirectories(lfos, String("*.") + vital::kLfoExtension, directories);
1877}
1878
1879void LoadSave::getAllUserSamples(Array<File>& samples) {
1880 std::vector<File> directories = {
1881 getDataDirectory().getChildFile(kSampleFolderName),
1883 };
1884 getAllFilesOfTypeInDirectories(samples, "*.wav", directories);
1885}
1886
1888 a.trim();
1889 b.trim();
1890
1891 return compareVersionStrings(a.upToLastOccurrenceOf(".", false, true),
1892 b.upToLastOccurrenceOf(".", false, true));
1893}
1894
1895int LoadSave::compareVersionStrings(String a, String b) {
1896 a.trim();
1897 b.trim();
1898
1899 if (a.isEmpty() && b.isEmpty())
1900 return 0;
1901
1902 String major_version_a = a.upToFirstOccurrenceOf(".", false, true);
1903 String major_version_b = b.upToFirstOccurrenceOf(".", false, true);
1904
1905 if (!major_version_a.containsOnly("0123456789"))
1906 major_version_a = "0";
1907 if (!major_version_b.containsOnly("0123456789"))
1908 major_version_b = "0";
1909
1910 int major_value_a = major_version_a.getIntValue();
1911 int major_value_b = major_version_b.getIntValue();
1912
1913 if (major_value_a > major_value_b)
1914 return 1;
1915 else if (major_value_a < major_value_b)
1916 return -1;
1917 return compareVersionStrings(a.fromFirstOccurrenceOf(".", false, true),
1918 b.fromFirstOccurrenceOf(".", false, true));
1919}
1920
1921File LoadSave::getShiftedFile(const String directory_name, const String& extensions,
1922 const std::string& additional_folders_name, const File& current_file, int shift) {
1923 FileSorterAscending file_sorter;
1924
1925 std::vector<File> directories = getDirectories(directory_name);
1926 std::vector<std::string> additional = getAdditionalFolders(additional_folders_name);
1927 for (const std::string& path : additional)
1928 directories.push_back(File(path));
1929
1930 Array<File> all_files;
1931 getAllFilesOfTypeInDirectories(all_files, extensions, directories);
1932 if (all_files.isEmpty())
1933 return File();
1934
1935 all_files.sort(file_sorter);
1936 int index = all_files.indexOf(current_file);
1937 if (index < 0)
1938 return all_files[0];
1939 return all_files[(index + shift + all_files.size()) % all_files.size()];
1940}
A class for generating and storing a line shape, defined by a series of points and associated powers.
Definition line_generator.h:20
void render()
Renders the line into the internal buffer based on the current points and settings.
Definition line_generator.cpp:149
force_inline void setPoint(int index, std::pair< float, float > point)
Sets the position of a specific point.
Definition line_generator.h:337
force_inline bool linear() const
Indicates whether the line is currently a simple linear shape.
Definition line_generator.h:273
void jsonToState(json data)
Restores the line state from a given JSON object.
Definition line_generator.cpp:125
force_inline void setNumPoints(int num_points)
Sets the number of points currently in use.
Definition line_generator.h:360
json stateToJson()
Converts the current state of the line into a JSON object.
Definition line_generator.cpp:96
void initLinear()
Initializes the line to a simple linear shape (from 1.0 at x=0 to 0.0 at x=1).
Definition line_generator.cpp:11
A helper class for sorting files in ascending order based on their names.
Definition load_save.h:34
static void saveWindowSize(float window_size)
Saves the window size scaling factor.
Definition load_save.cpp:1324
static const std::string kPresetFolderName
Definition load_save.h:74
static void saveJsonToConfig(json config_state)
Saves a given JSON object to the configuration file.
Definition load_save.cpp:1245
static std::vector< File > getSkinDirectories()
Gets directories that should contain skins.
Definition load_save.cpp:1772
static std::string getLoadedSkin()
Retrieves the currently loaded skin name.
Definition load_save.cpp:1572
static void getAllUserLfos(Array< File > &lfos)
Retrieves all user LFO shapes (from data and user directories).
Definition load_save.cpp:1871
static void getAllWavetables(Array< File > &wavetables)
Retrieves all wavetables from wavetable directories.
Definition load_save.cpp:1839
static const std::string kSkinFolderName
Definition load_save.h:76
static String getStyleFromFile(const File &file)
Extracts the style from a given preset file.
Definition load_save.cpp:1078
static File getAvailablePacksFile()
Retrieves the file listing available packs.
Definition load_save.cpp:1428
static void getAllSamples(Array< File > &samples)
Retrieves all samples (wav files) from sample directories.
Definition load_save.cpp:1851
static void saveAuthor(std::string author)
Saves the provided author name to the config.
Definition load_save.cpp:1261
static std::vector< File > getPresetDirectories()
Gets directories that should contain presets.
Definition load_save.cpp:1764
static float loadWindowSize()
Loads the saved window size scaling factor.
Definition load_save.cpp:1617
static void saveAdditionalFolders(const std::string &name, std::vector< std::string > folders)
Saves additional folder paths for presets, wavetables, or samples.
Definition load_save.cpp:1695
static const std::string kSampleFolderName
Definition load_save.h:77
static void markPackInstalled(int id)
Marks a pack as installed by ID in the packs file.
Definition load_save.cpp:1494
static bool shouldAnimateWidgets()
Determines if widget animations are enabled.
Definition load_save.cpp:1581
static String loadContentVersion()
Loads the saved content version string.
Definition load_save.cpp:1638
static std::pair< wchar_t, wchar_t > getComputerKeyboardOctaveControls()
Retrieves the keys used for octave shifts on the computer keyboard layout.
Definition load_save.cpp:1680
static const std::string kAdditionalWavetableFoldersName
Definition load_save.h:79
static File getUserDirectory()
Retrieves the user directory inside the data directory.
Definition load_save.cpp:1784
static bool shouldWorkOffline()
Checks if Vital should operate in offline mode.
Definition load_save.cpp:1563
static void writeCrashLog(String crash_log)
Writes a crash log to a file in the data directory.
Definition load_save.cpp:1132
static File getUserPresetDirectory()
Retrieves the user's preset directory.
Definition load_save.cpp:1791
static bool isInstalled()
Checks if Vital is fully installed (data directory present).
Definition load_save.cpp:1515
static File getDataDirectory()
Gets the current data directory from the config.
Definition load_save.cpp:1718
static void getAllFilesOfTypeInDirectories(Array< File > &files, const String &extensions, const std::vector< File > &directories)
Scans a set of directories for files matching certain extensions.
Definition load_save.cpp:1826
static void getAllUserPresets(Array< File > &presets)
Retrieves all user presets (from data and user directories).
Definition load_save.cpp:1855
static void saveContentVersion(std::string version)
Saves the current content version to the config file.
Definition load_save.cpp:1281
static void saveInstalledPacks(const json &packs)
Saves the given JSON pack configuration to the installed packs file.
Definition load_save.cpp:1486
static std::vector< File > getLfoDirectories()
Gets directories that should contain LFO shapes.
Definition load_save.cpp:1780
static String loadVersion()
Loads the saved synth version string.
Definition load_save.cpp:1628
static std::vector< std::string > getAdditionalFolders(const std::string &name)
Retrieves a list of additional folder paths for a given category.
Definition load_save.cpp:1705
static void saveMidiMapConfig(MidiManager *midi_manager)
Saves MIDI mapping configuration.
Definition load_save.cpp:1358
static void loadControls(SynthBase *synth, const json &data)
Loads controls from the given JSON data into a SynthBase instance.
Definition load_save.cpp:137
static void convertPcmToFloatBuffer(json &data, const std::string &field)
Converts a PCM buffer field in JSON to a float buffer in base64.
Definition load_save.cpp:61
static void saveUpdateCheckConfig(bool check_for_updates)
Saves the user's preference regarding update checks.
Definition load_save.cpp:1288
static bool doesExpire()
Checks if this build of Vital includes an expiration mechanism.
Definition load_save.cpp:1533
static void saveJsonToFavorites(json favorites_json)
Saves a JSON object of favorites to the favorites file.
Definition load_save.cpp:1253
static void saveVersionConfig()
Saves the current synth version to the config file.
Definition load_save.cpp:1274
static void loadLfos(SynthBase *synth, const json &lfos)
Loads LFO states (line shapes) from a JSON array into a SynthBase.
Definition load_save.cpp:201
static bool displayHzFrequency()
Determines if frequencies should be displayed in Hz.
Definition load_save.cpp:1590
static void saveLayoutConfig(vital::StringLayout *layout)
Saves layout configuration (keyboard layout and octave controls).
Definition load_save.cpp:1330
static File getUserWavetableDirectory()
Retrieves the user's wavetable directory.
Definition load_save.cpp:1798
static void addFavorite(const File &new_favorite)
Adds a new favorite preset or item to the favorites file.
Definition load_save.cpp:1219
static void saveAnimateWidgets(bool animate_widgets)
Saves the widget animation preference.
Definition load_save.cpp:1306
static void getAllPresets(Array< File > &presets)
Retrieves all preset files from preset directories.
Definition load_save.cpp:1835
static void savePreferredTTWTLanguage(std::string language)
Saves a preferred Text-To-Wavetable (TTWT) language to the config.
Definition load_save.cpp:1268
static File getInstalledPacksFile()
Retrieves the file that stores information about installed packs.
Definition load_save.cpp:1457
static void initSaveInfo(std::map< std::string, String > &save_info)
Initializes save_info with default values for preset information.
Definition load_save.cpp:243
static void getAllSkins(Array< File > &skins)
Retrieves all skins from skin directories.
Definition load_save.cpp:1843
static File getUserSkinDirectory()
Retrieves the user's skin directory.
Definition load_save.cpp:1805
static File getShiftedFile(const String directory_name, const String &extensions, const std::string &additional_folders_name, const File &current_file, int shift)
Given a directory name and extensions, returns a file shifted by some offset from the current file.
Definition load_save.cpp:1921
static int getOversamplingAmount()
Retrieves the current oversampling amount.
Definition load_save.cpp:1608
static json stateToJson(SynthBase *synth, const CriticalSection &critical_section)
Converts the state of a given SynthBase to JSON.
Definition load_save.cpp:78
static std::string getLicense(json state)
Extracts the license information from a JSON state, if present.
Definition load_save.cpp:1107
static std::string getPreferredTTWTLanguage()
Returns the preferred Text-To-Wavetable language, if set.
Definition load_save.cpp:1661
static void loadModulations(SynthBase *synth, const json &modulations)
Loads modulation connections from JSON data into a SynthBase instance.
Definition load_save.cpp:154
static bool jsonToState(SynthBase *synth, std::map< std::string, String > &save_info, json state)
Loads a JSON state into the given SynthBase, applying older version updates if necessary.
Definition load_save.cpp:1011
static json getInstalledPacks()
Returns a JSON list of installed packs.
Definition load_save.cpp:1470
static json getFavoritesJson()
Parses and returns the favorites JSON data.
Definition load_save.cpp:1203
static void removeFavorite(const File &old_favorite)
Removes a favorite item from the favorites.
Definition load_save.cpp:1225
static json updateFromOldVersion(json state)
Updates a JSON state from an older version of Vital's format to the current version.
Definition load_save.cpp:253
static json getAvailablePacks()
Parses and returns JSON data about available packs.
Definition load_save.cpp:1441
static void saveAuthenticated(bool authenticated)
Saves the user's authentication status.
Definition load_save.cpp:1318
static File getConfigFile()
Retrieves the main configuration file path for Vital.
Definition load_save.cpp:1113
static const std::string kLfoFolderName
Definition load_save.h:78
static bool authenticated()
Checks if the user is authenticated.
Definition load_save.cpp:1599
static void saveDataDirectory(const File &data_directory)
Saves the given directory as the data directory in the configuration.
Definition load_save.cpp:1508
static std::vector< File > getDirectories(const String &folder_name)
Retrieves directories of a given folder name under the data directory structure.
Definition load_save.cpp:1745
static bool isExpired()
Checks if this build of Vital has expired.
Definition load_save.cpp:1529
static void getAllUserWavetables(Array< File > &wavetables)
Retrieves all user wavetables (from data and user directories).
Definition load_save.cpp:1863
static bool shouldCheckForUpdates()
Checks if Vital should perform update checks.
Definition load_save.cpp:1554
static int compareVersionStrings(String a, String b)
Compares two version strings.
Definition load_save.cpp:1895
static void loadConfig(MidiManager *midi_manager, vital::StringLayout *layout=nullptr)
Loads configuration data into a MidiManager and optional StringLayout.
Definition load_save.cpp:1386
static std::string getAuthor()
Retrieves the saved author name from the config.
Definition load_save.cpp:1671
static int getDaysToExpire()
Returns the number of days remaining until expiration.
Definition load_save.cpp:1541
static void convertBufferToPcm(json &data, const std::string &field)
Converts a float buffer field in JSON to PCM format in base64.
Definition load_save.cpp:44
static std::vector< File > getWavetableDirectories()
Gets directories that should contain wavetables.
Definition load_save.cpp:1768
static void loadSaveState(std::map< std::string, String > &save_info, json data)
Extracts and stores basic preset info (name, author, comments, style, macros) from JSON data.
Definition load_save.cpp:211
static void saveDisplayHzFrequency(bool display_hz)
Saves the preference to display frequency in Hz.
Definition load_save.cpp:1312
static std::vector< File > getSampleDirectories()
Gets directories that should contain samples.
Definition load_save.cpp:1776
static File getDefaultSkin()
Retrieves the file specifying the default skin.
Definition load_save.cpp:1168
static const std::string kAdditionalSampleFoldersName
Definition load_save.h:80
static void writeErrorLog(String error_log)
Appends an error message to an error log file.
Definition load_save.cpp:1140
static void getAllLfos(Array< File > &lfos)
Retrieves all LFO shapes from LFO directories.
Definition load_save.cpp:1847
static String getAuthorFromFile(const File &file)
Extracts the author's name from a given preset file.
Definition load_save.cpp:1039
static const std::string kWavetableFolderName
Definition load_save.h:75
static bool hasDataDirectory()
Checks if a data directory is properly configured (exists and has packs.json).
Definition load_save.cpp:1417
static File getUserSampleDirectory()
Retrieves the user's sample directory.
Definition load_save.cpp:1812
static std::wstring getComputerKeyboardLayout()
Retrieves the saved computer keyboard layout for playing notes.
Definition load_save.cpp:1648
static int compareFeatureVersionStrings(String a, String b)
Compares two feature version strings (ignoring patch-level differences).
Definition load_save.cpp:1887
static File getUserLfoDirectory()
Retrieves the user's LFO directory.
Definition load_save.cpp:1819
static void loadWavetables(SynthBase *synth, const json &wavetables)
Loads wavetable configurations into a SynthBase from a JSON array.
Definition load_save.cpp:188
static json getConfigJson()
Parses and returns the main configuration JSON.
Definition load_save.cpp:1187
static File getFavoritesFile()
Retrieves the file storing the user's favorites.
Definition load_save.cpp:1149
static void saveLoadedSkin(const std::string &name)
Saves the currently loaded skin name to the config.
Definition load_save.cpp:1300
static const std::string kUserDirectoryName
Various folder and directory name constants.
Definition load_save.h:73
static bool wasUpgraded()
Checks if Vital was upgraded from a previous version.
Definition load_save.cpp:1519
static void getAllUserSamples(Array< File > &samples)
Retrieves all user samples (from data and user directories).
Definition load_save.cpp:1879
static void saveWorkOffline(bool work_offline)
Saves the user's preference for working offline.
Definition load_save.cpp:1294
static void loadSample(SynthBase *synth, const json &sample)
Loads a sample configuration into the SynthBase from a JSON object.
Definition load_save.cpp:182
static std::set< std::string > getFavorites()
Retrieves all favorites as a set of string paths.
Definition load_save.cpp:1235
The MidiManager class handles all incoming MIDI messages and directs them to the synthesizer engine.
Definition midi_manager.h:44
midi_map getMidiLearnMap()
Returns the current MIDI learn map.
Definition midi_manager.h:317
void setMidiLearnMap(const midi_map &midi_learn_map)
Sets the current MIDI learn map, overriding existing mappings.
Definition midi_manager.h:324
std::map< int, std::map< std::string, const vital::ValueDetails * > > midi_map
A nested type defining a map from MIDI controls to a map of parameter names and their ValueDetails.
Definition midi_manager.h:52
A base class providing foundational functionality for the Vital synthesizer’s engine,...
Definition synth_base.h:42
bool connectModulation(const std::string &source, const std::string &destination)
Connects a modulation source to a destination parameter.
Definition synth_base.cpp:165
String getMacroName(int index)
Gets the name of a macro control by index.
Definition synth_base.cpp:717
vital::ModulationConnectionBank & getModulationBank()
Retrieves the ModulationConnectionBank managing all modulation connections.
Definition synth_base.cpp:730
String getAuthor()
Gets the author of the current preset.
Definition synth_base.cpp:701
void checkOversampling()
Checks and updates oversampling settings. May be called if parameters affecting oversampling change.
Definition synth_base.cpp:741
String getComments()
Gets the comments for the current preset.
Definition synth_base.cpp:705
LineGenerator * getLfoSource(int index)
Retrieves an LFO source by index.
Definition synth_base.cpp:278
void modWheelGuiChanged(vital::mono_float value)
Called when the mod wheel changes via the GUI or another external source.
Definition synth_base.cpp:80
String getPresetName()
Gets the current preset’s name.
Definition synth_base.cpp:713
WavetableCreator * getWavetableCreator(int index)
Gets a WavetableCreator for a given oscillator index.
Definition synth_base.cpp:270
vital::Sample * getSample()
Gets the Sample object used by the engine.
Definition synth_base.cpp:274
vital::control_map & getControls()
Provides access to the controls map (parameter name to Parameter pointer).
Definition synth_base.h:477
void clearModulations()
Clears all modulation connections.
Definition synth_base.cpp:196
vital::SoundEngine * getEngine()
Returns a pointer to the SoundEngine used for audio and modulation processing.
Definition synth_base.h:484
String getStyle()
Gets the style of the current preset.
Definition synth_base.cpp:709
A class responsible for creating complete wavetables from groups of wavetable components.
Definition wavetable_creator.h:27
void initPredefinedWaves()
Definition wavetable_creator.cpp:171
json stateToJson()
Definition wavetable_creator.cpp:477
void jsonToState(json data)
Definition wavetable_creator.cpp:493
void setName(const std::string &name)
Sets the name of the wavetable.
Definition wavetable_creator.h:90
float render(int position)
Definition wavetable_creator.cpp:59
A container managing a fixed number of ModulationConnections.
Definition synth_types.h:87
ModulationConnection * atIndex(int index)
Retrieves a ModulationConnection by index.
Definition synth_types.h:114
static const ValueDetails & getDetails(const std::string &name)
Definition synth_parameters.h:200
Holds and manages a single sampled waveform, including stereo or mono data and multiple band-limited ...
Definition sample_source.h:25
void jsonToState(json data)
Restores the sample's state from a JSON object (including audio data).
Definition sample_source.cpp:351
json stateToJson()
Exports the sample state (metadata and sample data) to a JSON object.
Definition sample_source.cpp:333
Manages a keyboard layout mapping for a computer keyboard used as a MIDI input device.
Definition synth_types.h:134
void setDownKey(wchar_t down_key)
Sets the character assigned to decrease the octave.
Definition synth_types.h:181
void setUpKey(wchar_t up_key)
Sets the character assigned to increase the octave.
Definition synth_types.h:167
wchar_t getUpKey()
Gets the character assigned to increase the octave.
Definition synth_types.h:160
std::wstring getLayout()
Retrieves the current keyboard layout (a wstring of character-to-note mappings).
Definition synth_types.h:146
void setLayout(const std::wstring &layout)
Sets the current keyboard layout.
Definition synth_types.h:153
wchar_t getDownKey()
Gets the character assigned to decrease the octave.
Definition synth_types.h:174
Processor * getMonoModulationDestination(std::string name)
Retrieves a mono modulation destination by name.
Definition synth_module.cpp:382
Output * getModulationSource(std::string name)
Retrieves a modulation source output by name.
Definition synth_module.cpp:350
@ kFormant
Formant shifting.
Definition synth_oscillator.h:148
@ kSync
Sync distortion.
Definition synth_oscillator.h:147
@ kLowPass
Lowpass morph.
Definition synth_oscillator.h:134
A class representing a wavetable, holding multiple frames of waveforms and their frequency-domain rep...
Definition wavetable.h:20
nlohmann::json json
Definition line_generator.h:7
#define STRINGIFY(x)
Definition load_save.cpp:11
@ kNumEffects
Definition synth_constants.h:187
@ kFilterFx
Definition synth_constants.h:183
void floatToPcmData(int16_t *pcm_data, const float *float_data, int size)
Converts floating-point audio data to 16-bit PCM data.
Definition utils.cpp:77
void decodeFloatToOrder(int *order, mono_float float_code, int size)
Decodes a float-encoded permutation back into order.
Definition utils.cpp:55
mono_float encodeOrderToFloat(int *order, int size)
Encodes a permutation (stored in order) into a single float.
Definition utils.cpp:32
void pcmToFloatData(float *float_data, const int16_t *pcm_data, int size)
Converts 16-bit PCM data to floating-point audio data.
Definition utils.cpp:94
force_inline poly_float interpolate(poly_float from, poly_float to, mono_float t)
Performs a linear interpolation between two poly_floats using a scalar t in [0..1].
Definition poly_utils.h:182
constexpr int kNumOscillators
Number of oscillators available in Vital.
Definition synth_constants.h:16
constexpr wchar_t kDefaultKeyboardOctaveUp
Default key for octave-up action in the computer keyboard layout.
Definition synth_constants.h:76
const std::string kSkinExtension
File extension for Vital skin/theme files.
Definition synth_constants.h:97
constexpr int kNotesPerOctave
Number of semitones per octave.
Definition common.h:51
const std::wstring kDefaultKeyboard
The default keyboard layout (QWERTY-based) mapping keys to notes.
Definition synth_constants.h:82
constexpr int kNumRandomLfos
Number of random LFO sources (random modulation generators).
Definition synth_constants.h:25
const std::string kWavetableExtensionsList
A semicolon-separated list of supported wavetable file extensions, including external formats like ....
Definition synth_constants.h:91
constexpr int kNumEnvelopes
Number of envelope generators in Vital.
Definition synth_constants.h:22
std::map< std::string, Value * > control_map
Maps parameter names to Value pointers representing synth control parameters.
Definition synth_types.h:214
constexpr int kNumOscillatorWaveFrames
Number of wave frames in each oscillator’s wavetable.
Definition synth_constants.h:19
constexpr wchar_t kDefaultKeyboardOctaveDown
Default key for octave-down action in the computer keyboard layout.
Definition synth_constants.h:79
constexpr int kNumLfos
Number of LFO sources available in the Vital synthesizer.
Definition synth_constants.h:13
constexpr int kMaxModulationConnections
Maximum number of modulation connections allowed.
Definition synth_constants.h:49
const std::string kLfoExtension
File extension for Vital LFO shape files.
Definition synth_constants.h:100
constexpr int kNumMacros
Number of macro controls available.
Definition synth_constants.h:28
const std::string kPresetExtension
File extension for Vital preset files.
Definition synth_constants.h:85
float mono_float
Definition common.h:33
Declares the Sample and SampleSource classes for loading, managing, and playing back audio samples in...
A structure representing a single modulation connection between a modulation source and a destination...
Definition synth_types.h:30
std::unique_ptr< ModulationConnectionProcessor > modulation_processor
Processor applying scaling/mapping.
Definition synth_types.h:75
std::string destination_name
The name of the destination parameter.
Definition synth_types.h:74
std::string source_name
The name of the modulation source.
Definition synth_types.h:73
Holds metadata about a single parameter (control) in the Vital synthesizer.
Definition synth_parameters.h:23
mono_float default_value
Default value for the parameter.
Definition synth_parameters.h:42