Vital
Loading...
Searching...
No Matches
synth_base.cpp
Go to the documentation of this file.
1#include "synth_base.h"
2
3#include "sample_source.h"
4#include "sound_engine.h"
5#include "load_save.h"
6#include "memory.h"
8#include "startup.h"
10#include "synth_parameters.h"
11#include "utils.h"
12
13SynthBase::SynthBase() : expired_(false) {
15 self_reference_ = std::make_shared<SynthBase*>();
16 *self_reference_ = this;
17
18 engine_ = std::make_unique<vital::SoundEngine>();
19 engine_->setTuning(&tuning_);
20
22
23 for (int i = 0; i < vital::kNumOscillators; ++i) {
24 vital::Wavetable* wavetable = engine_->getWavetable(i);
25 if (wavetable) {
26 wavetable_creators_[i] = std::make_unique<WavetableCreator>(wavetable);
27 wavetable_creators_[i]->init();
28 }
29 }
30
31 keyboard_state_ = std::make_unique<MidiKeyboardState>();
32 midi_manager_ = std::make_unique<MidiManager>(this, keyboard_state_.get(), &save_info_, this);
33
34 last_played_note_ = 0.0f;
36 audio_memory_ = std::make_unique<vital::StereoMemory>(vital::kAudioMemorySamples);
41 memory_index_ = 0;
42
43 controls_ = engine_->getControls();
44
46}
47
49
50void SynthBase::valueChanged(const std::string& name, vital::mono_float value) {
51 controls_[name]->set(value);
52}
53
54void SynthBase::valueChangedInternal(const std::string& name, vital::mono_float value) {
55 valueChanged(name, value);
56 setValueNotifyHost(name, value);
57}
58
59void SynthBase::valueChangedThroughMidi(const std::string& name, vital::mono_float value) {
60 controls_[name]->set(value);
61 ValueChangedCallback* callback = new ValueChangedCallback(self_reference_, name, value);
62 setValueNotifyHost(name, value);
63 callback->post();
64}
65
67 ValueChangedCallback* callback = new ValueChangedCallback(self_reference_, "pitch_wheel", value);
68 callback->post();
69}
70
72 ValueChangedCallback* callback = new ValueChangedCallback(self_reference_, "mod_wheel", value);
73 callback->post();
74}
75
77 engine_->setZonedPitchWheel(value, 0, vital::kNumMidiChannels - 1);
78}
79
81 engine_->setModWheelAllChannels(value);
82}
83
85 SynthGuiInterface* gui_interface = getGuiInterface();
86 if (gui_interface) {
87 gui_interface->updateFullGui();
88 gui_interface->notifyFresh();
89 }
90}
91
92void SynthBase::valueChangedExternal(const std::string& name, vital::mono_float value) {
93 valueChanged(name, value);
94 if (name == "mod_wheel")
95 engine_->setModWheelAllChannels(value);
96 else if (name == "pitch_wheel")
97 engine_->setZonedPitchWheel(value, 0, vital::kNumMidiChannels - 1);
98
99 ValueChangedCallback* callback = new ValueChangedCallback(self_reference_, name, value);
100 callback->post();
101}
102
103vital::ModulationConnection* SynthBase::getConnection(const std::string& source, const std::string& destination) {
105 if (connection->source_name == source && connection->destination_name == destination)
106 return connection;
107 }
108 return nullptr;
109}
110
111int SynthBase::getConnectionIndex(const std::string& source, const std::string& destination) {
113 for (int i = 0; i < vital::kMaxModulationConnections; ++i) {
114 vital::ModulationConnection* connection = modulation_bank.atIndex(i);
115 if (connection->source_name == source && connection->destination_name == destination)
116 return i;
117 }
118 return -1;
119}
120
123 change.source = engine_->getModulationSource(connection->source_name);
124 change.mono_destination = engine_->getMonoModulationDestination(connection->destination_name);
125 change.mono_modulation_switch = engine_->getMonoModulationSwitch(connection->destination_name);
126 VITAL_ASSERT(change.source != nullptr);
127 VITAL_ASSERT(change.mono_destination != nullptr);
128 VITAL_ASSERT(change.mono_modulation_switch != nullptr);
129
131 change.poly_modulation_switch = engine_->getPolyModulationSwitch(connection->destination_name);
132 change.poly_destination = engine_->getPolyModulationDestination(connection->destination_name);
133 change.modulation_processor = connection->modulation_processor.get();
134
135 int num_audio_rate = 0;
137 for (int i = 0; i < vital::kMaxModulationConnections; ++i) {
138 if (modulation_bank.atIndex(i)->source_name == connection->source_name &&
139 modulation_bank.atIndex(i)->destination_name != connection->destination_name &&
140 !modulation_bank.atIndex(i)->modulation_processor->isControlRate()) {
141 num_audio_rate++;
142 }
143 }
144 change.num_audio_rate = num_audio_rate;
145 return change;
146}
147
151
154 if (isInvalidConnection(change)) {
155 connection->destination_name = "";
156 connection->source_name = "";
157 }
158 else if (mod_connections_.count(connection) == 0) {
159 change.disconnecting = false;
160 mod_connections_.push_back(connection);
161 modulation_change_queue_.enqueue(change);
162 }
163}
164
165bool SynthBase::connectModulation(const std::string& source, const std::string& destination) {
166 vital::ModulationConnection* connection = getConnection(source, destination);
167 bool create = connection == nullptr;
168 if (create)
169 connection = getModulationBank().createConnection(source, destination);
170
171 if (connection)
172 connectModulation(connection);
173
174 return create;
175}
176
178 if (mod_connections_.count(connection) == 0)
179 return;
180
182 connection->source_name = "";
183 connection->destination_name = "";
184
185 mod_connections_.remove(connection);
186 change.disconnecting = true;
187 modulation_change_queue_.enqueue(change);
188}
189
190void SynthBase::disconnectModulation(const std::string& source, const std::string& destination) {
191 vital::ModulationConnection* connection = getConnection(source, destination);
192 if (connection)
193 disconnectModulation(connection);
194}
195
198
199 while (mod_connections_.size()) {
201 mod_connections_.remove(connection);
203 change.disconnecting = true;
204 engine_->disconnectModulation(change);
205 connection->source_name = "";
206 connection->destination_name = "";
207 }
208
209 int num_connections = static_cast<int>(getModulationBank().numConnections());
210 for (int i = 0; i < num_connections; ++i)
211 getModulationBank().atIndex(i)->modulation_processor->lineMapGenerator()->initLinear();
212
213 engine_->disableUnnecessaryModSources();
214}
215
216void SynthBase::forceShowModulation(const std::string& source, bool force) {
217 if (force)
218 engine_->enableModSource(source);
219 else if (!isSourceConnected(source))
220 engine_->disableModSource(source);
221}
222
223bool SynthBase::isModSourceEnabled(const std::string& source) {
224 return engine_->isModSourceEnabled(source);
225}
226
227int SynthBase::getNumModulations(const std::string& destination) {
228 int connections = 0;
230 if (connection->destination_name == destination)
231 connections++;
232 }
233 return connections;
234}
235
236std::vector<vital::ModulationConnection*> SynthBase::getSourceConnections(const std::string& source) {
237 std::vector<vital::ModulationConnection*> connections;
239 if (connection->source_name == source)
240 connections.push_back(connection);
241 }
242 return connections;
243}
244
245bool SynthBase::isSourceConnected(const std::string& source) {
247 if (connection->source_name == source)
248 return true;
249 }
250 return false;
251}
252
253std::vector<vital::ModulationConnection*> SynthBase::getDestinationConnections(const std::string& destination) {
254 std::vector<vital::ModulationConnection*> connections;
256 if (connection->destination_name == destination)
257 connections.push_back(connection);
258 }
259 return connections;
260}
261
262const vital::StatusOutput* SynthBase::getStatusOutput(const std::string& name) {
263 return engine_->getStatusOutput(name);
264}
265
267 return engine_->getWavetable(index);
268}
269
271 return wavetable_creators_[index].get();
272}
273
275 return engine_->getSample();
276}
277
279 return engine_->getLfoSource(index);
280}
281
285
287 return engine_->getSampleRate();
288}
289
292 if (getWavetableCreator(0)) {
293 for (int i = 0; i < vital::kNumOscillators; ++i)
295
296 engine_->getSample()->init();
297 }
298
299 for (int i = 0; i < vital::kNumLfos; ++i)
301
302 vital::control_map controls = engine_->getControls();
303 for (auto& control : controls) {
304 vital::ValueDetails details = vital::Parameters::getDetails(control.first);
305 control.second->set(details.default_value);
306 }
308
310}
311
312void SynthBase::loadTuningFile(const File& file) {
313 tuning_.loadFile(file);
314}
315
317 pauseProcessing(true);
318 engine_->allSoundsOff();
319 initEngine();
321 pauseProcessing(false);
322}
323
324bool SynthBase::loadFromJson(const json& data) {
325 pauseProcessing(true);
326 engine_->allSoundsOff();
327 try {
328 bool result = LoadSave::jsonToState(this, save_info_, data);
329 pauseProcessing(false);
330 return result;
331 }
332 catch (const json::exception& e) {
333 pauseProcessing(false);
334 throw e;
335 }
336}
337
338bool SynthBase::loadFromFile(File preset, std::string& error) {
339 if (!preset.exists())
340 return false;
341
342 try {
343 json parsed_json_state = json::parse(preset.loadFileAsString().toStdString(), nullptr);
344 if (!loadFromJson(parsed_json_state)) {
345 error = "Preset was created with a newer version.";
346 return false;
347 }
348
349 active_file_ = preset;
350 }
351 catch (const json::exception& e) {
352 error = "Preset file is corrupted.";
353 return false;
354 }
355
356 setPresetName(preset.getFileNameWithoutExtension());
357
358 SynthGuiInterface* gui_interface = getGuiInterface();
359 if (gui_interface) {
360 gui_interface->updateFullGui();
361 gui_interface->notifyFresh();
362 }
363
364 return true;
365}
366
367void SynthBase::renderAudioToFile(File file, float seconds, float bpm, std::vector<int> notes, bool render_images) {
368 static constexpr int kSampleRate = 44100;
369 static constexpr int kPreProcessSamples = 44100;
370 static constexpr int kFadeSamples = 200;
371 static constexpr int kBufferSize = 64;
372 static constexpr int kVideoRate = 30;
373 static constexpr int kImageNumberPlaces = 3;
374 static constexpr int kImageWidth = 500;
375 static constexpr int kImageHeight = 250;
376 static constexpr int kOscilloscopeResolution = 512;
377 static constexpr float kFadeRatio = 0.3f;
378
379 ScopedLock lock(getCriticalSection());
380
382 engine_->setSampleRate(kSampleRate);
383 engine_->setBpm(bpm);
384 engine_->updateAllModulationSwitches();
385
386 double sample_time = 1.0 / getSampleRate();
387 double current_time = -kPreProcessSamples * sample_time;
388
389 for (int samples = 0; samples < kPreProcessSamples; samples += kBufferSize) {
390 engine_->correctToTime(current_time);
391 current_time += kBufferSize * sample_time;
392 engine_->process(kBufferSize);
393 }
394
395 for (int note : notes)
396 engine_->noteOn(note, 0.7f, 0, 0);
397
398 file.deleteFile();
399 std::unique_ptr<FileOutputStream> file_stream = file.createOutputStream();
400 WavAudioFormat wav_format;
401 std::unique_ptr<AudioFormatWriter> writer(wav_format.createWriterFor(file_stream.get(), kSampleRate, 2, 16, {}, 0));
402
403 int on_samples = seconds * kSampleRate;
404 int total_samples = on_samples + seconds * kSampleRate * kFadeRatio;
405 std::unique_ptr<float[]> left_buffer = std::make_unique<float[]>(kBufferSize);
406 std::unique_ptr<float[]> right_buffer = std::make_unique<float[]>(kBufferSize);
407 float* buffers[2] = { left_buffer.get(), right_buffer.get() };
408 const vital::mono_float* engine_output = (const vital::mono_float*)engine_->output(0)->buffer;
409
410#if JUCE_MODULE_AVAILABLE_juce_graphics
411 int current_image_index = -1;
412 PNGImageFormat png;
413 File images_folder = File::getCurrentWorkingDirectory().getChildFile("images");
414 if (!images_folder.exists() && render_images)
415 images_folder.createDirectory();
417#endif
418
419 for (int samples = 0; samples < total_samples; samples += kBufferSize) {
420 engine_->correctToTime(current_time);
421 current_time += kBufferSize * sample_time;
422 engine_->process(kBufferSize);
423 updateMemoryOutput(kBufferSize, engine_->output(0)->buffer);
424
425 if (on_samples > samples && on_samples <= samples + kBufferSize) {
426 for (int note : notes)
427 engine_->noteOff(note, 0.5f, 0, 0);
428 }
429
430 for (int i = 0; i < kBufferSize; ++i) {
431 vital::mono_float t = (total_samples - samples) / (1.0f * kFadeSamples);
432 t = vital::utils::min(t, 1.0f);
433 left_buffer[i] = t * engine_output[vital::poly_float::kSize * i];
434 right_buffer[i] = t * engine_output[vital::poly_float::kSize * i + 1];
435 }
436
437 writer->writeFromFloatArrays(buffers, 2, kBufferSize);
438
439 #if JUCE_MODULE_AVAILABLE_juce_graphics
440 int image_index = (samples * kVideoRate) / kSampleRate;
441 if (image_index > current_image_index && render_images) {
442 current_image_index = image_index;
443 String number(image_index);
444 while (number.length() < kImageNumberPlaces)
445 number = "0" + number;
446
447 File image_file = images_folder.getChildFile("rendered_image" + number + ".png");
448 FileOutputStream image_file_stream(image_file);
449 Image image(Image::RGB, kImageWidth, kImageHeight, true);
450 Graphics g(image);
451 g.fillAll(Colour(0xff1d2125));
452
453 Path left_path;
454 Path right_path;
455 left_path.startNewSubPath(-2.0f, kImageHeight / 2);
456 right_path.startNewSubPath(-2.0f, kImageHeight / 2);
457
458 for (int i = 0; i < kOscilloscopeResolution; ++i) {
459 float t = i / (kOscilloscopeResolution - 1.0f);
460 float memory_spot = (1.0f * i * vital::kOscilloscopeMemoryResolution) / kOscilloscopeResolution;
461 int memory_index = memory_spot;
462 float remainder = memory_spot - memory_index;
463 vital::poly_float from = memory[memory_index];
464 vital::poly_float to = memory[memory_index + 1];
465 vital::poly_float y = -vital::utils::interpolate(from, to, remainder) * kImageHeight / 2.0f + kImageHeight / 2;
466 left_path.lineTo(t * kImageWidth, y[0]);
467 right_path.lineTo(t * kImageWidth, y[1]);
468 }
469 left_path.lineTo(kImageWidth + 2.0f, kImageHeight / 2.0f);
470 right_path.lineTo(kImageWidth + 2.0f, kImageHeight / 2.0f);
471
472 g.setColour(Colour(0x64aa88ff));
473 g.fillPath(left_path);
474 g.fillPath(right_path);
475
476 g.setColour(Colour(0xffaa88ff));
477 g.strokePath(left_path, PathStrokeType(2.0f, PathStrokeType::curved, PathStrokeType::rounded));
478 g.strokePath(right_path, PathStrokeType(2.0f, PathStrokeType::curved, PathStrokeType::rounded));
479
480 png.writeImageToStream(image, image_file_stream);
481 }
482 #endif
483 }
484
485 writer->flush();
486 file_stream->flush();
487
488 writer = nullptr;
489 file_stream.release();
490}
491
492void SynthBase::renderAudioForResynthesis(float* data, int samples, int note) {
493 static constexpr int kPreProcessSamples = 44100;
494 static constexpr int kBufferSize = 64;
495
496 ScopedLock lock(getCriticalSection());
497
498 double sample_time = 1.0 / getSampleRate();
499 double current_time = -kPreProcessSamples * sample_time;
500
501 engine_->allSoundsOff();
502 for (int s = 0; s < kPreProcessSamples; s += kBufferSize) {
503 engine_->correctToTime(current_time);
504 current_time += kBufferSize * sample_time;
505 engine_->process(kBufferSize);
506 }
507
508 engine_->noteOn(note, 0.7f, 0, 0);
509 const vital::poly_float* engine_output = engine_->output(0)->buffer;
510 float max_value = 0.01f;
511 for (int s = 0; s < samples; s += kBufferSize) {
512 int num_samples = std::min(samples - s, kBufferSize);
513 engine_->correctToTime(current_time);
514 current_time += num_samples * sample_time;
515 engine_->process(num_samples);
516
517 for (int i = 0; i < num_samples; ++i) {
518 float sample = engine_output[i][0];
519 data[s + i] = sample;
520 max_value = std::max(max_value, fabsf(sample));
521 }
522 }
523
524 float scale = 1.0f / max_value;
525 for (int s = 0; s < samples; ++s)
526 data[s] *= scale;
527
528 engine_->allSoundsOff();
529}
530
531bool SynthBase::saveToFile(File preset) {
532 preset = preset.withFileExtension(String(vital::kPresetExtension));
533
534 File parent = preset.getParentDirectory();
535 if (!parent.exists()) {
536 if (!parent.createDirectory().wasOk() || !parent.hasWriteAccess())
537 return false;
538 }
539
540 setPresetName(preset.getFileNameWithoutExtension());
541
542 SynthGuiInterface* gui_interface = getGuiInterface();
543 if (gui_interface)
544 gui_interface->notifyFresh();
545
546 if (preset.replaceWithText(saveToJson().dump())) {
547 active_file_ = preset;
548 return true;
549 }
550 return false;
551}
552
554 if (!active_file_.exists() || !active_file_.hasWriteAccess())
555 return false;
556
557 return saveToFile(active_file_);
558}
559
560void SynthBase::setMpeEnabled(bool enabled) {
561 midi_manager_->setMpeEnabled(enabled);
562}
563
564void SynthBase::processAudio(AudioSampleBuffer* buffer, int channels, int samples, int offset) {
565 if (expired_)
566 return;
567
568 engine_->process(samples);
569 writeAudio(buffer, channels, samples, offset);
570}
571
572void SynthBase::processAudioWithInput(AudioSampleBuffer* buffer, const vital::poly_float* input_buffer,
573 int channels, int samples, int offset) {
574 if (expired_)
575 return;
576
577 engine_->processWithInput(input_buffer, samples);
578 writeAudio(buffer, channels, samples, offset);
579}
580
581void SynthBase::writeAudio(AudioSampleBuffer* buffer, int channels, int samples, int offset) {
582 const vital::mono_float* engine_output = (const vital::mono_float*)engine_->output(0)->buffer;
583 for (int channel = 0; channel < channels; ++channel) {
584 float* channel_data = buffer->getWritePointer(channel, offset);
585
586 for (int i = 0; i < samples; ++i) {
587 channel_data[i] = engine_output[vital::poly_float::kSize * i + channel];
588 VITAL_ASSERT(std::isfinite(channel_data[i]));
589 }
590 }
591
592 updateMemoryOutput(samples, engine_->output(0)->buffer);
593}
594
595void SynthBase::processMidi(MidiBuffer& midi_messages, int start_sample, int end_sample) {
596 bool process_all = end_sample == 0;
597 for (const MidiMessageMetadata message : midi_messages) {
598 int midi_sample = message.samplePosition;
599 if (process_all || (midi_sample >= start_sample && midi_sample < end_sample))
600 midi_manager_->processMidiMessage(message.getMessage(), midi_sample - start_sample);
601 }
602}
603
604void SynthBase::processKeyboardEvents(MidiBuffer& buffer, int num_samples) {
605 midi_manager_->replaceKeyboardMessages(buffer, num_samples);
606}
607
610 while (getNextModulationChange(change)) {
611 if (change.disconnecting)
612 engine_->disconnectModulation(change);
613 else
614 engine_->connectModulation(change);
615 }
616}
617
618void SynthBase::updateMemoryOutput(int samples, const vital::poly_float* audio) {
619 for (int i = 0; i < samples; ++i)
620 audio_memory_->push(audio[i]);
621
622 vital::mono_float last_played = engine_->getLastActiveNote();
624
625 int num_pressed = engine_->getNumPressedNotes();
626 int output_inc = std::max<int>(1, engine_->getSampleRate() / vital::kOscilloscopeMemorySampleRate);
627 int oscilloscope_samples = 2 * vital::kOscilloscopeMemoryResolution;
628
629 if (last_played && (last_played_note_ != last_played || num_pressed > last_num_pressed_)) {
630 last_played_note_ = last_played;
631
633 vital::mono_float period = engine_->getSampleRate() / frequency;
634 int window_length = output_inc * vital::kOscilloscopeMemoryResolution;
635
636 memory_reset_period_ = period;
637 while (memory_reset_period_ < window_length)
639
640 memory_reset_period_ = std::min(memory_reset_period_, 2.0f * window_length);
641 memory_index_ = 0;
643 }
644 last_num_pressed_ = num_pressed;
645
646 for (; memory_input_offset_ < samples; memory_input_offset_ += output_inc) {
647 int input_index = vital::utils::iclamp(memory_input_offset_, 0, samples);
648 memory_index_ = vital::utils::iclamp(memory_index_, 0, oscilloscope_samples - 1);
649 VITAL_ASSERT(input_index >= 0);
650 VITAL_ASSERT(input_index < samples);
652 VITAL_ASSERT(memory_index_ < oscilloscope_samples);
653 oscilloscope_memory_write_[memory_index_++] = audio[input_index];
654
655 if (memory_index_ * output_inc >= memory_reset_period_) {
657 memory_index_ = 0;
659 }
660 }
661
662 memory_input_offset_ -= samples;
663}
664
665void SynthBase::armMidiLearn(const std::string& name) {
666 midi_manager_->armMidiLearn(name);
667}
668
670 midi_manager_->cancelMidiLearn();
671}
672
673void SynthBase::clearMidiLearn(const std::string& name) {
674 midi_manager_->clearMidiLearn(name);
675}
676
677bool SynthBase::isMidiMapped(const std::string& name) {
678 return midi_manager_->isMidiMapped(name);
679}
680
681void SynthBase::setAuthor(const String& author) {
682 save_info_["author"] = author;
683}
684
685void SynthBase::setComments(const String& comments) {
686 save_info_["comments"] = comments;
687}
688
689void SynthBase::setStyle(const String& style) {
690 save_info_["style"] = style;
691}
692
693void SynthBase::setPresetName(const String& preset_name) {
694 save_info_["preset_name"] = preset_name;
695}
696
697void SynthBase::setMacroName(int index, const String& macro_name) {
698 save_info_["macro" + std::to_string(index + 1)] = macro_name;
699}
700
702 return save_info_["author"];
703}
704
706 return save_info_["comments"];
707}
708
710 return save_info_["style"];
711}
712
714 return save_info_["preset_name"];
715}
716
717String SynthBase::getMacroName(int index) {
718 String name = save_info_["macro" + std::to_string(index + 1)];
719 if (name.trim().isEmpty())
720 return "MACRO " + String(index + 1);
721 return name;
722}
723
725 if (engine_)
726 return engine_->getEqualizerMemory();
727 return nullptr;
728}
729
733
735 pauseProcessing(true);
736 engine_->allSoundsOff();
738 pauseProcessing(false);
739}
740
742 return engine_->checkOversampling();
743}
744
746 if (auto synth_base = listener.lock()) {
747 SynthGuiInterface* gui_interface = (*synth_base)->getGuiInterface();
748 if (gui_interface) {
749 gui_interface->updateGuiControl(control_name, value);
750 if (control_name != "pitch_wheel")
751 gui_interface->notifyChange();
752 }
753 }
754}
A class for generating and storing a line shape, defined by a series of points and associated powers.
Definition line_generator.h:20
void initTriangle()
Initializes the line as a triangle shape.
Definition line_generator.cpp:23
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 json stateToJson(SynthBase *synth, const CriticalSection &critical_section)
Converts the state of a given SynthBase to JSON.
Definition load_save.cpp:78
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 bool isExpired()
Checks if this build of Vital has expired.
Definition load_save.cpp:1529
static void doStartupChecks(MidiManager *midi_manager, vital::StringLayout *layout=nullptr)
Performs initial startup checks and configuration loading.
Definition startup.cpp:6
std::unique_ptr< WavetableCreator > wavetable_creators_[vital::kNumOscillators]
Definition synth_base.h:703
File active_file_
Definition synth_base.h:706
void setAuthor(const String &author)
Sets the author metadata of the current preset.
Definition synth_base.cpp:681
void processKeyboardEvents(MidiBuffer &buffer, int num_samples)
Processes keyboard events from a MidiBuffer, integrating them with the MidiKeyboardState.
Definition synth_base.cpp:604
bool saveToActiveFile()
Saves the current preset state to the active file (if any).
Definition synth_base.cpp:553
bool getNextModulationChange(vital::modulation_change &change)
Attempts to dequeue a modulation_change for processing.
Definition synth_base.h:624
std::vector< vital::ModulationConnection * > getSourceConnections(const std::string &source)
Returns all modulation connections from a particular source.
Definition synth_base.cpp:236
void valueChangedInternal(const std::string &name, vital::mono_float value)
Handles internal value changes, updating the parameter and optionally notifying the host.
Definition synth_base.cpp:54
void writeAudio(AudioSampleBuffer *buffer, int channels, int samples, int offset)
Writes audio data from the engine to the output buffer.
Definition synth_base.cpp:581
void pitchWheelMidiChanged(vital::mono_float value) override
Called when the pitch wheel value changes via MIDI.
Definition synth_base.cpp:66
void setMacroName(int index, const String &macro_name)
Sets the name of a macro control by index.
Definition synth_base.cpp:697
bool expired_
Definition synth_base.h:715
void valueChangedExternal(const std::string &name, vital::mono_float value)
Handles external (non-GUI, non-MIDI) value changes to parameters.
Definition synth_base.cpp:92
bool isMidiMapped(const std::string &name)
Checks if a given parameter name is MIDI mapped.
Definition synth_base.cpp:677
Tuning tuning_
Definition synth_base.h:722
vital::poly_float oscilloscope_memory_[2 *vital::kOscilloscopeMemoryResolution]
Definition synth_base.h:707
bool connectModulation(const std::string &source, const std::string &destination)
Connects a modulation source to a destination parameter.
Definition synth_base.cpp:165
void presetChangedThroughMidi(File preset) override
Called when a preset is changed through MIDI (e.g., program change messages).
Definition synth_base.cpp:84
std::unique_ptr< MidiManager > midi_manager_
Definition synth_base.h:700
String getMacroName(int index)
Gets the name of a macro control by index.
Definition synth_base.cpp:717
std::unique_ptr< MidiKeyboardState > keyboard_state_
Definition synth_base.h:701
vital::control_map controls_
Definition synth_base.h:718
void setComments(const String &comments)
Sets the comments or description metadata of the current preset.
Definition synth_base.cpp:685
std::unique_ptr< vital::StereoMemory > audio_memory_
Definition synth_base.h:709
int getConnectionIndex(const std::string &source, const std::string &destination)
Gets the index of a modulation connection given its source and destination.
Definition synth_base.cpp:111
bool isModSourceEnabled(const std::string &source)
Checks if a modulation source is currently enabled.
Definition synth_base.cpp:223
vital::poly_float oscilloscope_memory_write_[2 *vital::kOscilloscopeMemoryResolution]
Definition synth_base.h:708
std::shared_ptr< SynthBase * > self_reference_
Definition synth_base.h:704
vital::ModulationConnectionBank & getModulationBank()
Retrieves the ModulationConnectionBank managing all modulation connections.
Definition synth_base.cpp:730
bool saveToFile(File preset)
Saves the current preset state to the specified file.
Definition synth_base.cpp:531
virtual ~SynthBase()
Destroys the SynthBase, cleaning up resources such as sound engine and memory buffers.
Definition synth_base.cpp:48
void initEngine()
Initializes the engine to a default state, clearing modulations and resetting parameters.
Definition synth_base.cpp:290
void setStyle(const String &style)
Sets the style metadata of the current preset (e.g., bass, lead, etc.).
Definition synth_base.cpp:689
bool loadFromFile(File preset, std::string &error)
Attempts to load a preset from a file.
Definition synth_base.cpp:338
void clearActiveFile()
Clears the currently active preset file, meaning changes are not saved to a previously loaded file.
Definition synth_base.h:335
static constexpr float kOutputWindowMaxNote
Definition synth_base.h:46
void clearMidiLearn(const std::string &name)
Clears the MIDI mapping for a given parameter name.
Definition synth_base.cpp:673
String getAuthor()
Gets the author of the current preset.
Definition synth_base.cpp:701
bool loadFromJson(const json &state)
Deserializes and applies the synth state from a JSON object.
Definition synth_base.cpp:324
bool isSourceConnected(const std::string &source)
Checks if a given modulation source has any active connections.
Definition synth_base.cpp:245
void clearModulationQueue()
Clears the modulation change queue, removing all pending changes.
Definition synth_base.h:631
void setMpeEnabled(bool enabled)
Enables or disables MPE (MIDI Polyphonic Expression) mode.
Definition synth_base.cpp:560
void processAudio(AudioSampleBuffer *buffer, int channels, int samples, int offset)
Processes audio into the given buffer. May be overridden or extended by subclasses.
Definition synth_base.cpp:564
virtual void pauseProcessing(bool pause)=0
Pauses or resumes audio processing.
json saveToJson()
Serializes the current synth state into a JSON object.
Definition synth_base.cpp:282
void checkOversampling()
Checks and updates oversampling settings. May be called if parameters affecting oversampling change.
Definition synth_base.cpp:741
std::map< std::string, String > save_info_
Definition synth_base.h:717
void cancelMidiLearn()
Cancels a previously armed MIDI learn operation.
Definition synth_base.cpp:669
int last_num_pressed_
Definition synth_base.h:711
String getComments()
Gets the comments for the current preset.
Definition synth_base.cpp:705
void processMidi(MidiBuffer &buffer, int start_sample=0, int end_sample=0)
Processes MIDI messages from a MidiBuffer, applying them to the engine’s sound generation.
Definition synth_base.cpp:595
void forceShowModulation(const std::string &source, bool force)
Forces a modulation source to remain active even if not currently connected.
Definition synth_base.cpp:216
LineGenerator * getLfoSource(int index)
Retrieves an LFO source by index.
Definition synth_base.cpp:278
void disconnectModulation(const std::string &source, const std::string &destination)
Disconnects a modulation source from a destination parameter.
Definition synth_base.cpp:190
void renderAudioForResynthesis(float *data, int samples, int note)
Renders audio for the purpose of resynthesis into a provided buffer.
Definition synth_base.cpp:492
static constexpr float kOutputWindowMinNote
Minimum and maximum note values considered for output window display or related processing.
Definition synth_base.h:45
void processAudioWithInput(AudioSampleBuffer *buffer, const vital::poly_float *input_buffer, int channels, int samples, int offset)
Processes audio with an input buffer, often used for sidechain or feedback loops.
Definition synth_base.cpp:572
void updateMemoryOutput(int samples, const vital::poly_float *audio)
Updates the oscilloscope memory with the latest audio samples.
Definition synth_base.cpp:618
void modWheelGuiChanged(vital::mono_float value)
Called when the mod wheel changes via the GUI or another external source.
Definition synth_base.cpp:80
virtual const CriticalSection & getCriticalSection()=0
Provides access to the synth’s internal CriticalSection for thread safety.
virtual SynthGuiInterface * getGuiInterface()=0
Retrieves the GUI interface if available, for updating controls or notifications.
vital::ModulationConnection * getConnection(const std::string &source, const std::string &destination)
Finds a ModulationConnection by source and destination names.
Definition synth_base.cpp:103
String getPresetName()
Gets the current preset’s name.
Definition synth_base.cpp:713
const vital::poly_float * getOscilloscopeMemory()
Retrieves the oscilloscope memory for visualization of audio output waveforms.
Definition synth_base.h:498
WavetableCreator * getWavetableCreator(int index)
Gets a WavetableCreator for a given oscillator index.
Definition synth_base.cpp:270
std::unique_ptr< vital::SoundEngine > engine_
Definition synth_base.h:699
vital::CircularQueue< vital::ModulationConnection * > mod_connections_
Definition synth_base.h:719
virtual void setValueNotifyHost(const std::string &name, vital::mono_float value)
Called when a parameter changes to notify a potential host environment. Typically not implemented her...
Definition synth_base.h:371
int getSampleRate()
Retrieves the current audio sample rate used by the engine.
Definition synth_base.cpp:286
int getNumModulations(const std::string &destination)
Counts how many modulations target a given parameter.
Definition synth_base.cpp:227
const vital::StereoMemory * getEqualizerMemory()
Retrieves memory used for equalizer visualization, if available.
Definition synth_base.cpp:724
vital::Wavetable * getWavetable(int index)
Gets a wavetable object from the engine.
Definition synth_base.cpp:266
std::vector< vital::ModulationConnection * > getDestinationConnections(const std::string &destination)
Returns all modulation connections targeting a given destination parameter.
Definition synth_base.cpp:253
void pitchWheelGuiChanged(vital::mono_float value)
Called when the pitch wheel changes via the GUI or another external source.
Definition synth_base.cpp:76
bool isInvalidConnection(const vital::modulation_change &change)
Checks if a modulation_change is invalid (e.g., creates a loop).
Definition synth_base.cpp:148
moodycamel::ConcurrentQueue< vital::modulation_change > modulation_change_queue_
Definition synth_base.h:721
SynthBase()
Constructs a SynthBase, initializing the sound engine, MIDI manager, wavetables, and settings.
Definition synth_base.cpp:13
vital::Sample * getSample()
Gets the Sample object used by the engine.
Definition synth_base.cpp:274
void modWheelMidiChanged(vital::mono_float value) override
Called when the mod wheel value changes via MIDI.
Definition synth_base.cpp:71
vital::mono_float memory_input_offset_
Definition synth_base.h:713
void renderAudioToFile(File file, float seconds, float bpm, std::vector< int > notes, bool render_images)
Renders audio to a WAV file for a given duration and note sequence.
Definition synth_base.cpp:367
const vital::StatusOutput * getStatusOutput(const std::string &name)
Retrieves a status output by name.
Definition synth_base.cpp:262
void clearModulations()
Clears all modulation connections.
Definition synth_base.cpp:196
void loadInitPreset()
Loads an "init" preset, resetting Vital to its default initial state.
Definition synth_base.cpp:316
void loadTuningFile(const File &file)
Loads a tuning file into the synthesizer’s tuning system.
Definition synth_base.cpp:312
vital::mono_float last_played_note_
Definition synth_base.h:710
void valueChanged(const std::string &name, vital::mono_float value)
Updates the value of a control parameter.
Definition synth_base.cpp:50
void processModulationChanges()
Processes pending modulation changes and updates the engine accordingly.
Definition synth_base.cpp:608
vital::mono_float memory_reset_period_
Definition synth_base.h:712
vital::modulation_change createModulationChange(vital::ModulationConnection *connection)
Creates a modulation_change structure for a given connection, preparing it for engine operations.
Definition synth_base.cpp:121
int memory_index_
Definition synth_base.h:714
void valueChangedThroughMidi(const std::string &name, vital::mono_float value) override
Handles parameter changes triggered through MIDI mappings.
Definition synth_base.cpp:59
void notifyOversamplingChanged()
Notifies that oversampling settings have changed, reinitializing the engine if needed.
Definition synth_base.cpp:734
void armMidiLearn(const std::string &name)
Arms the given parameter name for MIDI learn, associating the next received MIDI control with it.
Definition synth_base.cpp:665
void setPresetName(const String &preset_name)
Sets the preset name.
Definition synth_base.cpp:693
String getStyle()
Gets the style of the current preset.
Definition synth_base.cpp:709
An interface class linking the Vital synthesizer backend (SynthBase) with a GUI.
Definition synth_gui_interface.h:56
void notifyChange()
Notifies the GUI that a parameter or modulation changed, prompting GUI updates.
Definition synth_gui_interface.cpp:165
virtual void updateGuiControl(const std::string &name, vital::mono_float value)
Updates a single GUI control to reflect a new parameter value.
Definition synth_gui_interface.cpp:71
virtual void updateFullGui()
Updates the entire GUI to reflect the current synth state.
Definition synth_gui_interface.cpp:62
void notifyFresh()
Notifies the GUI that a fresh state (like a new preset load) has occurred, prompting a full refresh.
Definition synth_gui_interface.cpp:172
void loadFile(File file)
Loads a tuning from a given file, automatically detecting its format (.scl, .kbm, ....
Definition tuning.cpp:147
A class responsible for creating complete wavetables from groups of wavetable components.
Definition wavetable_creator.h:27
void init()
Definition wavetable_creator.cpp:151
int count(T entry) const
Counts how many times entry appears in the queue.
Definition circular_queue.h:362
force_inline void remove(T entry)
Removes the first occurrence of an element if found.
Definition circular_queue.h:283
force_inline int size() const
Returns the current number of elements in the queue.
Definition circular_queue.h:410
void reserve(int capacity)
Ensures that the queue has at least the given capacity.
Definition circular_queue.h:159
force_inline iterator begin() const
Returns an iterator to the first element of the queue.
Definition circular_queue.h:425
force_inline void push_back(T entry)
Pushes an element to the back of the queue.
Definition circular_queue.h:220
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
size_t numConnections()
Returns the total number of connections allocated (including unused ones).
Definition synth_types.h:121
ModulationConnection * createConnection(const std::string &from, const std::string &to)
Creates a new modulation connection by finding an empty slot and assigning source/destination.
Definition synth_types.cpp:60
static const ValueDetails & getDetails(const std::string &name)
Definition synth_parameters.h:200
static const mono_float getParameterRange(const std::string &name)
Definition synth_parameters.h:216
force_inline void router(ProcessorRouter *router)
Sets the ProcessorRouter that owns or manages this Processor.
Definition processor.h:507
Holds and manages a single sampled waveform, including stereo or mono data and multiple band-limited ...
Definition sample_source.h:25
A helper class to track the "status" of a particular Output as a poly_float value.
Definition synth_module.h:35
A specialized MemoryTemplate for two-channel (stereo) audio.
Definition memory.h:216
A class representing a wavetable, holding multiple frames of waveforms and their frequency-domain rep...
Definition wavetable.h:20
#define VITAL_ASSERT(x)
Definition common.h:11
nlohmann::json json
Definition line_generator.h:7
Declares classes for time-domain memory storage and retrieval with cubic interpolation.
force_inline int iclamp(int value, int min_val, int max_val)
Clamps an integer between [min_val, max_val].
Definition utils.h:250
force_inline poly_float clamp(poly_float value, mono_float min, mono_float max)
Clamps each lane of a vector to [min, max].
Definition poly_utils.h:306
force_inline poly_float min(poly_float left, poly_float right)
Returns the minimum of two poly_floats lane-by-lane.
Definition poly_utils.h:334
force_inline void copyBuffer(mono_float *dest, const mono_float *source, int size)
Copies data from a source mono buffer to a destination mono buffer.
Definition poly_utils.h:586
force_inline poly_float midiNoteToFrequency(poly_float value)
Converts a MIDI note to a frequency (vectorized).
Definition poly_utils.h:123
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 kNumMidiChannels
MIDI channels available per device.
Definition common.h:57
constexpr int kNumOscillators
Number of oscillators available in Vital.
Definition synth_constants.h:16
constexpr int kOscilloscopeMemoryResolution
Resolution (number of samples) in the oscilloscope memory buffer.
Definition synth_constants.h:55
constexpr int kOscilloscopeMemorySampleRate
Sample rate (in Hz) at which the oscilloscope memory is sampled.
Definition synth_constants.h:52
constexpr int kAudioMemorySamples
Size of the stereo audio memory buffer used for visualization.
Definition synth_constants.h:58
std::map< std::string, Value * > control_map
Maps parameter names to Value pointers representing synth control parameters.
Definition synth_types.h:214
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 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 callback message used when values change, allowing asynchronous updates to GUI or host.
Definition synth_base.h:559
void messageCallback() override
Definition synth_base.cpp:745
vital::mono_float value
Definition synth_base.h:567
std::string control_name
Definition synth_base.h:566
std::weak_ptr< SynthBase * > listener
Definition synth_base.h:565
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
A structure describing changes to the modulation routing in the engine.
Definition synth_types.h:199
Processor * poly_destination
The poly modulation destination (if any).
Definition synth_types.h:202
Processor * mono_destination
The mono modulation destination (if any).
Definition synth_types.h:201
ValueSwitch * poly_modulation_switch
Switch to enable/disable poly modulation.
Definition synth_types.h:205
int num_audio_rate
Count of audio-rate modulations connected from the same source.
Definition synth_types.h:208
bool disconnecting
True if this change represents a disconnection.
Definition synth_types.h:207
Output * source
The modulation source output.
Definition synth_types.h:200
mono_float destination_scale
Scaling factor for the destination parameter.
Definition synth_types.h:203
ModulationConnectionProcessor * modulation_processor
The processor for applying modulation shape/curve.
Definition synth_types.h:206
ValueSwitch * mono_modulation_switch
Switch to enable/disable mono modulation.
Definition synth_types.h:204
Represents a vector of floating-point values using SIMD instructions.
Definition poly_values.h:600
Provides various utility functions, classes, and constants for audio, math, and general-purpose opera...