Vital
Loading...
Searching...
No Matches
wavetable_edit_section.cpp
Go to the documentation of this file.
2
3#include "skin.h"
4#include "paths.h"
5#include "filter_section.h"
6#include "full_interface.h"
7#include "bar_renderer.h"
8#include "load_save.h"
10#include "synth_slider.h"
11#include "synth_gui_interface.h"
12#include "text_look_and_feel.h"
13#include "utils.h"
18
19namespace {
20 void barViewerCallback(int result, WavetableEditSection* edit_section) {
22 return;
23
25 edit_section->setPowerScale(true);
27 edit_section->setPowerScale(false);
28 else
29 edit_section->setZoom(WavetableEditSection::getZoomScale(result));
30 }
31
32 force_inline int chunkNameToData(const char* chunk_name) {
33 return static_cast<int>(ByteOrder::littleEndianInt(chunk_name));
34 }
35
37 if (data.isEmpty())
39
40 if (data.substring(0, 3) == "<!>") {
41 StringArray tokens;
42 tokens.addTokens(data.substring(3), " ", "");
43 if (tokens.size() < 2 || tokens[1].isEmpty())
45
46 char fade_character = tokens[1][0];
47 if (fade_character == '0')
49 if (fade_character == '1')
51
53 }
54
56 }
57
58 String getAuthorFromWavetableString(String data) {
59 if (data.substring(0, 3) == "<!>") {
60 int start = data.indexOf("[");
61 int end = data.indexOf("]");
62 if (start < end && start >= 0)
63 return data.substring(start + 1, end);
64 }
65
66 return "";
67 }
68
69 void menuCallback(int result, WavetableEditSection* wavetable_edit_section) {
71 wavetable_edit_section->saveAsWavetable();
73 wavetable_edit_section->importWavetable();
75 wavetable_edit_section->exportWavetable();
76 else if (result == WavetableEditSection::kExportWav)
77 wavetable_edit_section->exportToWav();
79 wavetable_edit_section->resynthesizeToWavetable();
80 }
81}
82
83String WavetableEditSection::getWavetableDataString(InputStream* input_stream) {
84 int first_chunk = input_stream->readInt();
85 if (first_chunk != chunkNameToData("RIFF"))
86 return "";
87
88 int length = input_stream->readInt();
89 int data_end = static_cast<int>(input_stream->getPosition()) + length;
90
91 if (input_stream->readInt() != chunkNameToData("WAVE"))
92 return "";
93
94 while (!input_stream->isExhausted() && input_stream->getPosition() < data_end) {
95 int chunk_label = input_stream->readInt();
96 int chunk_length = input_stream->readInt();
97
98 if (chunk_label == chunkNameToData("clm ")) {
99 MemoryBlock memory_block;
100 input_stream->readIntoMemoryBlock(memory_block, chunk_length);
101 return memory_block.toString();
102 }
103
104 input_stream->setPosition(input_stream->getPosition() + chunk_length);
105 }
106
107 return "";
108}
109
111 SynthSection("oscillator " + String(index + 1)), index_(index), zoom_(8),
112 power_scale_(true), obscure_time_domain_(false), obscure_freq_amplitude_(false), obscure_freq_phase_(false),
113 wavetable_creator_(wavetable_creator) {
114 format_manager_.registerBasicFormats();
115 current_overlay_ = nullptr;
117 int num_frames = vital::kNumOscillatorWaveFrames;
118 int waveform_size = vital::Wavetable::kWaveformSize;
119 wave_frame_slider_ = nullptr;
120
121 oscillator_waveform_ = std::make_unique<WaveSourceEditor>(waveform_size);
122 addOpenGlComponent(oscillator_waveform_.get());
123 oscillator_waveform_->setFill(true);
124 oscillator_waveform_->addRoundedCorners();
125
126 frequency_amplitudes_ = std::make_unique<BarRenderer>(num_bars);
127 addOpenGlComponent(frequency_amplitudes_.get());
128 frequency_amplitudes_->setSquareScale(true);
129 frequency_amplitudes_->addRoundedCorners();
130
131 frequency_phases_ = std::make_unique<BarRenderer>(num_bars);
132 addOpenGlComponent(frequency_phases_.get());
133 frequency_phases_->addRoundedCorners();
134
135 wavetable_organizer_ = std::make_unique<WavetableOrganizer>(wavetable_creator_, num_frames);
136 addSubSection(wavetable_organizer_.get());
137 wavetable_organizer_->addListener(this);
138
139 wavetable_component_list_ = std::make_unique<WavetableComponentList>(wavetable_creator_);
140 addSubSection(wavetable_component_list_.get());
141 wavetable_component_list_->addListener(this);
142 wavetable_component_list_->addListener(wavetable_organizer_.get());
143
144 wavetable_playhead_ = std::make_unique<WavetablePlayhead>(num_frames);
145 addSubSection(wavetable_playhead_.get());
146 wavetable_playhead_->addListener(wavetable_organizer_.get());
147 wavetable_playhead_->addListener(this);
148
149 wavetable_playhead_info_ = std::make_unique<WavetablePlayheadInfo>();
150 addAndMakeVisible(wavetable_playhead_info_.get());
151 wavetable_playhead_->addListener(wavetable_playhead_info_.get());
152
153 exit_button_ = std::make_unique<OpenGlShapeButton>("Exit");
154 addAndMakeVisible(exit_button_.get());
155 addOpenGlComponent(exit_button_->getGlComponent());
156 exit_button_->addListener(this);
157 exit_button_->setShape(Paths::exitX());
158
159 frequency_amplitude_settings_ = std::make_unique<OpenGlShapeButton>("Settings");
160 addAndMakeVisible(frequency_amplitude_settings_.get());
161 addOpenGlComponent(frequency_amplitude_settings_->getGlComponent());
162 frequency_amplitude_settings_->addListener(this);
163 frequency_amplitude_settings_->setAlwaysOnTop(true);
164 frequency_amplitude_settings_->setShape(Paths::gear());
165
166 preset_selector_ = std::make_unique<PresetSelector>();
167 addSubSection(preset_selector_.get());
168 preset_selector_->addListener(this);
169
170 menu_button_ = std::make_unique<OpenGlShapeButton>("Menu");
171 addAndMakeVisible(menu_button_.get());
172 addOpenGlComponent(menu_button_->getGlComponent());
173 menu_button_->addListener(this);
174 menu_button_->setTriggeredOnMouseDown(true);
175 menu_button_->setShape(Paths::menu());
176
177 for (int i = 0; i < WavetableComponentFactory::kNumComponentTypes; ++i) {
179 overlays_[i].reset(WavetableOverlayFactory::createOverlay(type));
180 overlays_[i]->setParent(this);
181 overlays_[i]->addFrameListener(this);
182 addSubSection(overlays_[i].get());
183 overlays_[i]->setVisible(false);
184 wavetable_organizer_->addListener(overlays_[i].get());
185 }
186
187 init();
188
189 hideCurrentOverlay();
190 obscure_time_domain_ = false;
191 setZoom(zoom_);
192 setPowerScale(power_scale_);
193 wavetable_organizer_->selectDefaultFrame();
194
195 setWantsKeyboardFocus(true);
196 setMouseClickGrabsKeyboardFocus(true);
197 setPresetSelectorText();
198
200}
201
203 current_overlay_ = nullptr;
204}
205
207 static constexpr float kHeightRatio = 0.66f;
208
209 int title_width = getTopHeight();
210 int large_padding = findValue(Skin::kLargePadding);
211 int height = (getHeight() - title_width) * kHeightRatio;
212 return Rectangle<int>(large_padding, title_width, getWidth() - 2 * large_padding, height);
213}
214
216 Rectangle<int> edit_bounds = getFrameEditBounds();
217 int large_padding = findValue(Skin::kLargePadding);
218 int height = getHeight() - edit_bounds.getBottom() - large_padding - getPadding();
219 return Rectangle<int>(large_padding, edit_bounds.getBottom() + large_padding, edit_bounds.getWidth(), height);
220}
221
225
227
228 g.saveState();
229 Rectangle<int> bounds = getLocalArea(preset_selector_.get(), preset_selector_->getLocalBounds());
230 g.reduceClipRegion(bounds);
231 g.setOrigin(bounds.getTopLeft());
232 preset_selector_->paintBackground(g);
233 g.restoreState();
234}
235
240
242 setColors();
243
244 int padding = getPadding();
245
246 if (current_overlay_)
247 current_overlay_->setPadding(padding);
248
249 int title_width = getTopHeight();
250 int button_height = 20 * getSizeRatio();
251
252 title_bounds_ = Rectangle<int>(0, 0, getWidth(), title_width);
253
254 exit_button_->setBounds(title_bounds_.getRight() - title_width, title_bounds_.getY() + padding,
255 title_width, title_width);
256
257 Rectangle<int> edit_bounds = getFrameEditBounds();
258 int widget_margin = getWidgetMargin();
259 int edit_x = edit_bounds.getX() + widget_margin;
260 int edit_width = edit_bounds.getWidth() - 2 * widget_margin;
261 int osc_height = edit_bounds.getHeight() * 0.58f;
262 int amp_height = edit_bounds.getHeight() * 0.26f;
263 int phase_height = edit_bounds.getHeight() - osc_height - amp_height - 4 * widget_margin;
264 oscillator_waveform_->setBounds(edit_x, edit_bounds.getY() + widget_margin, edit_width, osc_height);
265 frequency_amplitudes_->setBounds(edit_x, oscillator_waveform_->getBottom() + widget_margin, edit_width, amp_height);
266 frequency_amplitude_settings_->setBounds(edit_x, frequency_amplitudes_->getY(), button_height, button_height);
267 frequency_phases_->setBounds(edit_x, frequency_amplitudes_->getBottom() + widget_margin, edit_width, phase_height);
268
269 Rectangle<int> timeline_bounds = getTimelineBounds();
270 int wavetable_y = timeline_bounds.getY();
271 int playhead_height = timeline_bounds.getHeight() * WavetableOrganizer::kHandleHeightPercent;
272 int organizer_x = timeline_bounds.getX() + timeline_bounds.getWidth() / 4;
273 int organizer_width = timeline_bounds.getRight() - organizer_x;
274 int info_width = organizer_x - timeline_bounds.getX();
275 wavetable_playhead_info_->setBounds(timeline_bounds.getX(), wavetable_y, info_width, playhead_height);
276 wavetable_playhead_->setBounds(organizer_x, wavetable_y, organizer_width, playhead_height);
277 wavetable_component_list_->setBounds(timeline_bounds.getX(), wavetable_y + playhead_height,
278 info_width, timeline_bounds.getHeight() - playhead_height);
279
280 wavetable_organizer_->setBounds(organizer_x, wavetable_y + playhead_height,
281 organizer_width, timeline_bounds.getHeight() - playhead_height);
282 wavetable_playhead_->setPadding(wavetable_organizer_->handleWidth() / 2.0f);
283 wavetable_component_list_->setRowHeight(wavetable_organizer_->handleWidth());
284
285 int preset_selector_width = getWidth() / 3;
286 int preset_selector_height = title_width * 0.6f;
287 int preset_selector_buffer = (title_width - preset_selector_height) * 0.5f;
288 int preset_selector_x = (getWidth() - preset_selector_width + 2 * preset_selector_height) / 2;
289 preset_selector_->setBounds(preset_selector_x, preset_selector_buffer,
290 preset_selector_width - preset_selector_height, preset_selector_height);
291 preset_selector_->setRoundAmount(preset_selector_height / 2.0f);
292
293 menu_button_->setBounds(preset_selector_->getRight(), preset_selector_buffer,
294 preset_selector_height, preset_selector_height);
295 menu_button_->setShape(Paths::menu(preset_selector_height));
296
297 setOverlayPosition();
298
300}
301
303 clear();
304 wavetable_organizer_->clear();
305 wavetable_component_list_->clear();
306
307 wavetable_organizer_->init();
308 wavetable_component_list_->init();
309 init();
310 if (isVisible())
311 wavetable_organizer_->selectDefaultFrame();
313}
314
316 setPresetSelectorText();
317 if (isVisible()) {
318 if (!wavetable_organizer_->hasSelectedFrames())
319 wavetable_organizer_->selectDefaultFrame();
320
321 updateGlDisplay();
322 }
323}
324
325void WavetableEditSection::mouseWheelMove(const MouseEvent& e, const MouseWheelDetails& wheel) {
326 static constexpr float kMouseWheelSensitivity = 0.75f;
327 static constexpr float kMinZoom = 1.0f;
328 static constexpr float kMaxZoom = 32.0f;
329
330 Point<int> position = e.getPosition();
331 if (frequency_phases_->getBounds().contains(position) || frequency_amplitudes_->getBounds().contains(position)) {
332 zoom_ *= std::pow(2.0f, kMouseWheelSensitivity * wheel.deltaY);
333 zoom_ = std::max(std::min(zoom_, kMaxZoom), kMinZoom);
334
335 frequency_amplitudes_->setScale(zoom_);
336 frequency_phases_->setScale(zoom_);
337 if (current_overlay_)
338 current_overlay_->setFrequencyZoom(zoom_);
339 }
340}
341
343 updateGlDisplay();
344 if (wave_frame_slider_)
345 wave_frame_slider_->setValue(position);
346}
347
349 render();
350}
351
353 int max_frame = std::max(0, wavetable_creator_->getWavetable()->numFrames() - 1);
354 int position = std::min(max_frame, wavetable_playhead_->position());
355 render(position);
356}
357
364
371
372void WavetableEditSection::textMouseDown(const MouseEvent& e) {
373 static constexpr int kBrowserWidth = 600;
374 static constexpr int kBrowserHeight = 400;
375 Rectangle<int> bounds(preset_selector_->getX(), preset_selector_->getBottom(),
376 kBrowserWidth * size_ratio_, kBrowserHeight * size_ratio_);
377 bounds = getLocalArea(this, bounds);
380}
381
382void WavetableEditSection::setPresetSelectorText() {
383 std::string name = wavetable_creator_->getName();
384 std::string author = wavetable_creator_->getAuthor();
385 if (author.size() == 0)
386 preset_selector_->setText(name);
387 else
388 preset_selector_->setText(name, "-", author);
389}
390
391void WavetableEditSection::showPopupMenu() {
392 PopupItems options;
393
394 options.addItem(kSaveAsWavetable, "Save As Wavetable");
395 options.addItem(kImportWavetable, "Import Wavetable");
396 options.addItem(kExportWavetable, "Export Wavetable");
397 options.addItem(kExportWav, "Export to .wav File");
398 options.addItem(kResynthesizeWavetable, "Synthesize Preset to Table");
399
400 showPopupSelector(this, Point<int>(menu_button_->getX(), menu_button_->getBottom()), options,
401 [=](int selection) { menuCallback(selection, this); });
402}
403
404void WavetableEditSection::hideCurrentOverlay() {
405 if (current_overlay_)
406 current_overlay_->setVisible(false);
407
408 current_overlay_ = nullptr;
409 obscure_time_domain_ = false;
410 obscure_freq_amplitude_ = false;
411 obscure_freq_phase_ = false;
412}
413
414void WavetableEditSection::clearOverlays() {
415 hideCurrentOverlay();
416
417 for (int i = 0; i < WavetableComponentFactory::kNumComponentTypes; ++i) {
418 overlays_[i]->setVisible(false);
419 overlays_[i]->reset();
420 }
421
422 type_lookup_.clear();
423}
424
425void WavetableEditSection::setColors() {
426 Colour primary_color = findColour(Skin::kWidgetPrimaryDisabled, true);
427 Colour background = primary_color.withAlpha(0.0f);
428 Colour secondary_color = findColour(Skin::kWidgetSecondaryDisabled, true);
429
430 float fade_alpha = 1.0f - findValue(Skin::kWidgetFillFade);
431 if (obscure_time_domain_) {
432 oscillator_waveform_->setColor(primary_color.interpolatedWith(background, kObscureAmount));
433
434 Colour fill_color = secondary_color.interpolatedWith(background, kObscureAmount);
435 oscillator_waveform_->setFillColors(fill_color.withMultipliedAlpha(fade_alpha), fill_color);
436 }
437 else {
438 oscillator_waveform_->setColor(primary_color);
439 oscillator_waveform_->setFillColors(secondary_color.withMultipliedAlpha(fade_alpha), secondary_color);
440 }
441
442 if (obscure_freq_amplitude_)
443 frequency_amplitudes_->setColor(secondary_color.interpolatedWith(background, kObscureAmount));
444 else
445 frequency_amplitudes_->setColor(secondary_color);
446
447 if (obscure_freq_phase_)
448 frequency_phases_->setColor(secondary_color.interpolatedWith(background, kObscureAmount));
449 else
450 frequency_phases_->setColor(secondary_color);
451}
452
453void WavetableEditSection::render() {
454 wavetable_creator_->render();
455 updateGlDisplay();
456}
457
458void WavetableEditSection::render(int position) {
459 wavetable_creator_->render(position);
460 updateGlDisplay();
461}
462
463void WavetableEditSection::updateGlDisplay() {
464 int position = wavetable_playhead_->position();
465 VITAL_ASSERT(position >= 0 && position <= vital::kNumOscillatorWaveFrames);
466 updateTimeDomain(wavetable_creator_->getWavetable()->getBuffer(position));
467 updateFrequencyDomain(wavetable_creator_->getWavetable()->getBuffer(position));
468}
469
470void WavetableEditSection::setOverlayPosition() {
471 int edit_height = frequency_amplitudes_->getHeight() * 0.33f;
472 edit_bounds_ = Rectangle<int>(0, oscillator_waveform_->getBottom() + getPadding(), getWidth(), edit_height);
473
474 if (current_overlay_) {
475 current_overlay_->setBounds(0, 0, getWidth(), wavetable_playhead_->getY());
476 obscure_time_domain_ = current_overlay_->setTimeDomainBounds(oscillator_waveform_->getBounds());
477 obscure_freq_amplitude_ = current_overlay_->setFrequencyAmplitudeBounds(frequency_amplitudes_->getBounds());
478 obscure_freq_phase_ = current_overlay_->setPhaseBounds(frequency_phases_->getBounds());
479 current_overlay_->setPadding(getPadding());
480 current_overlay_->setEditBounds(edit_bounds_);
481 }
482}
483
484void WavetableEditSection::updateTimeDomain(float* time_domain) {
485 oscillator_waveform_->loadWaveform(time_domain);
486}
487
488void WavetableEditSection::updateFrequencyDomain(float* time_domain) {
489 static constexpr float kAmplitudeEpsilon = 0.0000001f;
490 static constexpr float kPhaseEpsilon = 0.0001f;
491 compute_frame_.loadTimeDomain(time_domain);
492
493 for (int i = 0; i < vital::WaveFrame::kWaveformSize / 2; ++i) {
494 std::complex<float> val = compute_frame_.frequency_domain[i];
495 float amplitude = std::abs(val) / vital::WaveFrame::kWaveformSize;
496 float phase = amplitude > kAmplitudeEpsilon ? std::arg(val) : -vital::kPi / 2.0f;
497 frequency_amplitudes_->setScaledY(i, amplitude);
498 if (phase >= vital::kPi - kPhaseEpsilon)
499 phase = -vital::kPi;
500 frequency_phases_->setY(i, phase / vital::kPi);
501 }
502}
503
504int WavetableEditSection::loadAudioFile(AudioSampleBuffer& destination, InputStream* audio_stream) {
505 audio_stream->setPosition(0);
506 std::unique_ptr<AudioFormatReader> format_reader(
507 format_manager_.createReaderFor(std::unique_ptr<InputStream>(audio_stream)));
508 if (format_reader == nullptr)
509 return 0;
510
511 int num_samples = static_cast<int>(format_reader->lengthInSamples);
512 destination.setSize(format_reader->numChannels, num_samples);
513 format_reader->read(&destination, 0, num_samples, 0, true, true);
514 return format_reader->sampleRate;
515}
516
518 hideCurrentOverlay();
519
521 type_lookup_[component] = type;
522 current_overlay_ = overlays_[type].get();
523 current_overlay_->setComponent(component);
524 current_overlay_->setVisible(true);
525
526 current_overlay_->setPadding(getPadding());
527 current_overlay_->setPowerScale(power_scale_);
528 current_overlay_->setFrequencyZoom(zoom_);
529 setOverlayPosition();
530}
531
533 type_lookup_.erase(component);
534
535 for (int i = 0; i < WavetableComponentFactory::kNumComponentTypes; ++i) {
536 if (overlays_[i]->getComponent() == component) {
537 overlays_[i]->setVisible(false);
538 overlays_[i]->resetOverlay();
539 overlays_[i]->reset();
540 if (overlays_[i].get() == current_overlay_)
541 hideCurrentOverlay();
542 }
543 }
544}
545
547 render();
548}
549
551 wavetable_creator_->init();
552 reset();
553}
554
556 FullInterface* parent = findParentComponentOfClass<FullInterface>();
557 if (parent)
558 parent->saveWavetable(index_);
559}
560
562 FileChooser open_box("Import Wavetable", File(), vital::kWavetableExtensionsList);
563 if (open_box.browseForFileToOpen()) {
564 if (!open_box.getResult().exists())
565 return;
566 loadFile(open_box.getResult());
567 }
568}
569
571 FileChooser save_box("Export Wavetable", File(), String("*.") + vital::kWavetableExtension);
572 if (save_box.browseForFileToSave(true)) {
573 json wavetable_data = wavetable_creator_->stateToJson();
574 File file = save_box.getResult().withFileExtension(vital::kWavetableExtension);
575 file.replaceWithText(wavetable_data.dump());
576 }
577}
578
580 static constexpr int kWavetableSampleRate = 88200;
581 static constexpr int kNumWaveframes = 256;
582
583 FileChooser save_box("Export to .wav File", File(), String("*.wav"));
584 if (!save_box.browseForFileToSave(true))
585 return;
586
587 File file = save_box.getResult().withFileExtension("wav");
588 if (!file.hasWriteAccess())
589 return;
590
591 file.deleteFile();
592 std::unique_ptr<FileOutputStream> file_stream = file.createOutputStream();
593 WavAudioFormat wav_format;
594 StringPairArray meta_data;
595 meta_data.set("clm ", "<!>2048 20000000 wavetable (vital.audio)");
596 std::unique_ptr<AudioFormatWriter> writer(wav_format.createWriterFor(file_stream.get(), kWavetableSampleRate,
597 1, 16, meta_data, 0));
598
599 int total_samples = vital::WaveFrame::kWaveformSize * kNumWaveframes;
600 std::unique_ptr<float[]> buffer = std::make_unique<float[]>(total_samples);
601 wavetable_creator_->renderToBuffer(buffer.get(), kNumWaveframes, vital::WaveFrame::kWaveformSize);
602
603 float* channel = buffer.get();
604 writer->writeFromFloatArrays(&channel, 1, total_samples);
605 writer->flush();
606 file_stream->flush();
607
608 writer = nullptr;
609 file_stream.release();
610}
611
612void WavetableEditSection::loadFile(const File& wavetable_file) {
613 clear();
614 if (wavetable_file.getFileExtension() == ".wav") {
615 FileInputStream* input_stream = new FileInputStream(wavetable_file);
616 loadAudioAsWavetable(wavetable_file.getFileNameWithoutExtension(), input_stream,
618 }
619 else {
620 String data_string = wavetable_file.loadFileAsString();
621
622 try {
623 json wavetable_data = json::parse(data_string.toStdString(), nullptr, false);
624 wavetable_creator_->jsonToState(wavetable_data);
625 }
626 catch (const json::exception& e) {
627 return;
628 }
629
630 wavetable_creator_->setName(wavetable_file.getFileNameWithoutExtension().toStdString());
631 }
632
633 setPresetSelectorText();
634 std::string path = wavetable_file.getFullPathName().toStdString();
635 wavetable_creator_->setFileLoaded(path);
636 reset();
637 render();
638}
639
641 clear();
642 try {
643 wavetable_creator_->jsonToState(wavetable_data);
644 }
645 catch (const json::exception& e) { }
646 reset();
647}
648
649bool WavetableEditSection::loadAudioAsWavetable(String name, InputStream* audio_stream,
651 AudioSampleBuffer sample_buffer;
652 String wavetable_string = getWavetableDataString(audio_stream);
653 int sample_rate = loadAudioFile(sample_buffer, audio_stream);
654 if (sample_rate == 0)
655 return false;
656
657 FileSource::FadeStyle fade_style = getFadeStyleFromWavetableString(wavetable_string);
658 clear();
659 wavetable_creator_->initFromAudioFile(sample_buffer.getReadPointer(0), sample_buffer.getNumSamples(),
660 sample_rate, style, fade_style);
661 wavetable_creator_->setName(name.toStdString());
662 wavetable_creator_->setAuthor(getAuthorFromWavetableString(wavetable_string).toStdString());
663 reset();
664 return true;
665}
666
668 static constexpr float kResynthesizeTime = 4.0f;
669 static constexpr int kResynthesizeNote = 16;
670
671 SynthGuiInterface* synth_interface = findParentComponentOfClass<SynthGuiInterface>();
672 if (synth_interface == nullptr)
673 return;
674
675 int sample_rate = synth_interface->getSynth()->getSampleRate();
676 int total_samples = sample_rate * kResynthesizeTime;
677 std::unique_ptr<float[]> data = std::make_unique<float[]>(total_samples);
678
679 synth_interface->getSynth()->renderAudioForResynthesis(data.get(), total_samples, kResynthesizeNote);
680 clear();
681 wavetable_creator_->initFromAudioFile(data.get(), total_samples, sample_rate,
683 wavetable_creator_->setName("Resynthesize");
684 FileSource* file_source = dynamic_cast<FileSource*>(wavetable_creator_->getGroup(0)->getComponent(0));
685 if (file_source)
686 file_source->setWindowSize(sample_rate / vital::utils::midiNoteToFrequency(kResynthesizeNote));
687 wavetable_creator_->render();
688 reset();
689}
690
691void WavetableEditSection::buttonClicked(Button* clicked_button) {
692 if (clicked_button == menu_button_.get())
693 showPopupMenu();
694 else if (clicked_button == exit_button_.get()) {
695 FullInterface* parent = findParentComponentOfClass<FullInterface>();
696 if (parent)
697 parent->hideWavetableEditSection();
698 }
699 else if (clicked_button == frequency_amplitude_settings_.get()) {
700 PopupItems options;
701 options.addItem(kPowerScale, "Power Scale");
702 options.addItem(kAmplitudeScale, "Amplitude Scale");
703 options.addItem(-1, "");
704 options.addItem(kZoom1, "Zoom 1x");
705 options.addItem(kZoom2, "Zoom 2x");
706 options.addItem(kZoom4, "Zoom 4x");
707 options.addItem(kZoom8, "Zoom 8x");
708 options.addItem(kZoom16, "Zoom 16x");
709
710 showPopupSelector(this, Point<int>(clicked_button->getX(), clicked_button->getBottom()), options,
711 [=](int selection) { barViewerCallback(selection, this); });
712 }
713 else
714 SynthSection::buttonClicked(clicked_button);
715}
716
718 render();
719}
720
722 if (keyframe) {
723 WavetableComponent* component = keyframe->owner();
724 if (current_overlay_ && current_overlay_->getComponent() == component)
725 return;
726
728
729 current_overlay_ = overlays_[type].get();
730 current_overlay_->setComponent(component);
731 current_overlay_->setVisible(true);
732 current_overlay_->setPadding(getPadding());
733 current_overlay_->setPowerScale(power_scale_);
734 current_overlay_->setFrequencyZoom(zoom_);
735 setOverlayPosition();
736 }
737 else
738 hideCurrentOverlay();
739}
740
742 wavetable_playhead_->setPosition(position);
743}
744
745void WavetableEditSection::wheelMoved(const MouseEvent& e, const MouseWheelDetails& wheel) {
746 wavetable_component_list_->scroll(e, wheel);
747}
748
750 setColors();
752
753 WavetableComponentOverlay* current_overlay = current_overlay_;
754 if (current_overlay) {
755 if (!current_overlay->initialized())
756 current_overlay->initOpenGlComponents(open_gl);
757
758 current_overlay->renderOpenGlComponents(open_gl, animate);
759 }
760
761 oscillator_waveform_->renderCorners(open_gl, animate);
762 frequency_amplitudes_->renderCorners(open_gl, animate);
763 frequency_phases_->renderCorners(open_gl, animate);
764}
765
767 power_scale_ = power_scale;
768 frequency_amplitudes_->setPowerScale(power_scale_);
769 if (current_overlay_)
770 current_overlay_->setPowerScale(power_scale_);
771}
772
774 zoom_ = zoom;
775 frequency_amplitudes_->setScale(zoom_);
776 frequency_phases_->setScale(zoom_);
777 if (current_overlay_)
778 current_overlay_->setFrequencyZoom(zoom_);
779}
780
782 clearOverlays();
783}
784
786 for (int g = 0; g < wavetable_creator_->numGroups(); ++g) {
787 WavetableGroup* group = wavetable_creator_->getGroup(g);
788 for (int i = 0; i < group->numComponents(); ++i)
789 componentAdded(group->getComponent(i));
790 }
791 hideCurrentOverlay();
792}
A WavetableComponent that uses an external audio sample as its source.
Definition file_source.h:23
FadeStyle
Different methods to blend or interpolate the loaded audio window into a wavetable frame.
Definition file_source.h:38
@ kFreqInterpolate
Interpolate in frequency domain between cycles.
Definition file_source.h:42
@ kTimeInterpolate
Interpolate in time domain between cycles.
Definition file_source.h:41
@ kWaveBlend
Blend windowed segments into each other.
Definition file_source.h:39
@ kNoInterpolate
Use a single segment, no blending.
Definition file_source.h:40
void setWindowSize(double window_size)
Definition file_source.h:177
The main GUI container for the entire synthesizer interface.
Definition full_interface.h:61
void hideWavetableEditSection()
Hides any open wavetable editing section, returning to the normal view.
Definition full_interface.cpp:811
void saveWavetable(int index)
Opens a save dialog to save the current wavetable of an oscillator.
Definition full_interface.cpp:835
static const std::string kAdditionalWavetableFoldersName
Definition load_save.h:79
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 std::vector< File > getWavetableDirectories()
Gets directories that should contain wavetables.
Definition load_save.cpp:1768
static const std::string kWavetableFolderName
Definition load_save.h:75
static Path menu()
Creates a menu icon path (three horizontal lines).
Definition paths.h:271
static Path gear()
Definition paths.h:565
static Path exitX()
Definition paths.h:416
@ kWidgetFillFade
Definition skin.h:108
@ kLargePadding
Definition skin.h:82
@ kWidgetPrimaryDisabled
Definition skin.h:167
@ kWidgetSecondaryDisabled
Definition skin.h:170
@ kWavetableEditor
Definition skin.h:60
void renderAudioForResynthesis(float *data, int samples, int note)
Renders audio for the purpose of resynthesis into a provided buffer.
Definition synth_base.cpp:492
int getSampleRate()
Retrieves the current audio sample rate used by the engine.
Definition synth_base.cpp:286
An interface class linking the Vital synthesizer backend (SynthBase) with a GUI.
Definition synth_gui_interface.h:56
SynthBase * getSynth()
Returns the SynthBase instance this interface is managing.
Definition synth_gui_interface.h:85
Base class for all synthesizer sections, providing UI layout, painting, and interaction logic.
Definition synth_section.h:193
virtual void buttonClicked(Button *clicked_button) override
Called when a button is clicked. Updates the synth parameter accordingly.
Definition synth_section.cpp:398
virtual void renderOpenGlComponents(OpenGlWrapper &open_gl, bool animate)
Renders all OpenGL components in this section and sub-sections.
Definition synth_section.cpp:357
float getPadding()
Definition synth_section.cpp:660
virtual void animate(bool animate)
Triggers animation state change in sub-sections if needed.
Definition synth_section.cpp:822
void addSubSection(SynthSection *section, bool show=true)
Adds a subsection (another SynthSection) as a child.
Definition synth_section.cpp:457
virtual void resized() override
Called when the component is resized. Arranges layout of child components.
Definition synth_section.cpp:35
virtual void paintBody(Graphics &g, Rectangle< int > bounds)
Paints the body background within given bounds.
Definition synth_section.cpp:165
void paintChildrenBackgrounds(Graphics &g)
Paints the backgrounds for all child sections.
Definition synth_section.cpp:274
void showPopupSelector(Component *source, Point< int > position, const PopupItems &options, std::function< void(int)> callback, std::function< void()> cancel={ })
Shows a popup selector with options.
Definition synth_section.cpp:119
float size_ratio_
Definition synth_section.h:821
float findValue(Skin::ValueId value_id) const
Finds a value in the skin overrides or from the parent if not found locally.
Definition synth_section.cpp:18
void addOpenGlComponent(OpenGlComponent *open_gl_component, bool to_beginning=false)
Definition synth_section.cpp:489
float getSizeRatio() const
Definition synth_section.h:765
virtual void reset()
Resets the section and all sub-sections.
Definition synth_section.cpp:30
void setSkinOverride(Skin::SectionOverride skin_override)
Definition synth_section.h:303
virtual void paintTabShadow(Graphics &g)
Paints a tab-like shadow effect around the component.
Definition synth_section.cpp:188
void showPopupBrowser(SynthSection *owner, Rectangle< int > bounds, std::vector< File > directories, String extensions, std::string passthrough_name, std::string additional_folders_name)
Shows a file browser popup (e.g., for loading samples or wavetables).
Definition synth_section.cpp:105
float getWidgetMargin()
Definition synth_section.cpp:676
ComponentType
Enumerates all known WavetableComponents, including sources and modifiers.
Definition wavetable_component_factory.h:28
@ kNumComponentTypes
Total count of all component types.
Definition wavetable_component_factory.h:42
A base class representing a component in a wavetable synthesis chain.
Definition wavetable_component.h:32
virtual WavetableComponentFactory::ComponentType getType()=0
Returns the type of this WavetableComponent.
A base overlay component for editing and interacting with a wavetable component's parameters.
Definition wavetable_component_overlay.h:22
virtual bool setFrequencyAmplitudeBounds(Rectangle< int > bounds)
Optionally set bounds for frequency-amplitude editing UI.
Definition wavetable_component_overlay.h:181
void setComponent(WavetableComponent *component)
Sets the WavetableComponent that this overlay is editing.
Definition wavetable_component_overlay.cpp:81
virtual void setEditBounds(Rectangle< int > bounds)
Sets the editing bounds within which controls and titles are placed.
Definition wavetable_component_overlay.cpp:67
void setPadding(int padding)
Sets padding around controls and triggers a repaint.
Definition wavetable_component_overlay.h:242
virtual void setPowerScale(bool scale)
Sets whether to scale values like frequency display (optional override).
Definition wavetable_component_overlay.h:230
void initOpenGlComponents(OpenGlWrapper &open_gl) override
Initializes OpenGL components.
Definition wavetable_component_overlay.h:199
bool initialized()
Checks if the overlay has been initialized.
Definition wavetable_component_overlay.h:208
virtual void setFrequencyZoom(float zoom)
Sets the frequency zoom factor (optional override).
Definition wavetable_component_overlay.h:236
WavetableComponent * getComponent()
Gets the currently associated WavetableComponent.
Definition wavetable_component_overlay.h:260
virtual bool setTimeDomainBounds(Rectangle< int > bounds)
Optionally set bounds for time-domain editing UI.
Definition wavetable_component_overlay.h:174
virtual bool setPhaseBounds(Rectangle< int > bounds)
Optionally set bounds for phase editing UI.
Definition wavetable_component_overlay.h:188
A class responsible for creating complete wavetables from groups of wavetable components.
Definition wavetable_creator.h:27
void setFileLoaded(const std::string &path)
Records the path of the last file loaded to create this wavetable.
Definition wavetable_creator.h:104
WavetableGroup * getGroup(int index) const
Retrieves a WavetableGroup by index.
Definition wavetable_creator.h:71
void setAuthor(const std::string &author)
Sets the author of the wavetable.
Definition wavetable_creator.h:97
std::string getAuthor() const
Gets the author of the wavetable.
Definition wavetable_creator.h:118
void init()
Definition wavetable_creator.cpp:151
AudioFileLoadStyle
Defines how audio files are interpreted when loading into a wavetable.
Definition wavetable_creator.h:33
@ kWavetableSplice
Slice the audio into segments mapping onto wavetable frames.
Definition wavetable_creator.h:35
@ kPitched
Attempts to extract pitch-based cycles from the audio.
Definition wavetable_creator.h:38
json stateToJson()
Definition wavetable_creator.cpp:477
void jsonToState(json data)
Definition wavetable_creator.cpp:493
int numGroups() const
Gets the total number of WavetableGroups.
Definition wavetable_creator.h:63
void initFromAudioFile(const float *audio_buffer, int num_samples, int sample_rate, AudioFileLoadStyle load_style, FileSource::FadeStyle fade_style)
Definition wavetable_creator.cpp:196
vital::Wavetable * getWavetable()
Gets the internal wavetable object being created.
Definition wavetable_creator.h:144
std::string getName() const
Gets the name of the wavetable.
Definition wavetable_creator.h:111
void renderToBuffer(float *buffer, int num_frames, int frame_size)
Definition wavetable_creator.cpp:117
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 UI section for editing, visualizing, and managing wavetables.
Definition wavetable_edit_section.h:35
void componentsChanged() override
Callback when components in the list change.
Definition wavetable_edit_section.cpp:546
void exportToWav()
Exports the current wavetable frames as a .wav file.
Definition wavetable_edit_section.cpp:579
void setPowerScale(bool power_scale)
Sets whether the frequency display uses power scale or amplitude scale.
Definition wavetable_edit_section.cpp:766
Rectangle< int > getFrameEditBounds()
Gets the bounds of the frame editing area.
Definition wavetable_edit_section.cpp:206
void loadWavetable(json &wavetable_data)
Loads a wavetable from JSON data.
Definition wavetable_edit_section.cpp:640
static float getZoomScale(int zoom)
Computes a zoom scale factor from a zoom menu selection.
Definition wavetable_edit_section.h:45
virtual void positionsUpdated() override
Callback for when positions in the wavetable organizer are updated.
Definition wavetable_edit_section.cpp:717
virtual void frameDragged(WavetableKeyframe *keyframe, int position) override
Callback when a frame is dragged to a new position.
Definition wavetable_edit_section.cpp:741
File getCurrentFile() override
Gets the current wavetable file being edited.
Definition wavetable_edit_section.h:236
void resynthesizeToWavetable()
Resynthesizes the current preset into a wavetable.
Definition wavetable_edit_section.cpp:667
void resized() override
Called when the component is resized, arranges the layout of UI elements.
Definition wavetable_edit_section.cpp:241
void componentRemoved(WavetableComponent *component) override
Callback when a wavetable component is removed.
Definition wavetable_edit_section.cpp:532
void visibilityChanged() override
Called when visibility changes, e.g., updating UI if made visible.
Definition wavetable_edit_section.cpp:315
void frameDoneEditing() override
Callback when a frame finishes editing, triggers a waveform re-render.
Definition wavetable_edit_section.cpp:348
static constexpr float kObscureAmount
Opacity factor for obscuring certain visuals.
Definition wavetable_edit_section.h:37
virtual void buttonClicked(Button *clicked_button) override
Handles button clicks for menu, settings, exit, etc.
Definition wavetable_edit_section.cpp:691
void renderOpenGlComponents(OpenGlWrapper &open_gl, bool animate) override
Renders the OpenGL components, including overlays.
Definition wavetable_edit_section.cpp:749
void loadFile(const File &wavetable_file) override
Loads a wavetable file from disk.
Definition wavetable_edit_section.cpp:612
void paintBackgroundShadow(Graphics &g) override
Paints any background shadow or tab shadows for the section.
Definition wavetable_edit_section.cpp:236
void saveAsWavetable()
Saves the current wavetable state as a file.
Definition wavetable_edit_section.cpp:555
@ kZoom8
Definition wavetable_edit_section.h:75
@ kZoom2
Definition wavetable_edit_section.h:73
@ kCancel
Definition wavetable_edit_section.h:69
@ kZoom16
Definition wavetable_edit_section.h:76
@ kZoom1
Definition wavetable_edit_section.h:72
@ kPowerScale
Definition wavetable_edit_section.h:70
@ kAmplitudeScale
Definition wavetable_edit_section.h:71
@ kZoom4
Definition wavetable_edit_section.h:74
virtual void frameSelected(WavetableKeyframe *keyframe) override
Callback when a frame is selected in the wavetable organizer.
Definition wavetable_edit_section.cpp:721
void playheadMoved(int position) override
Callback for when the playhead moves to a different frame.
Definition wavetable_edit_section.cpp:342
void importWavetable()
Imports an external wavetable file.
Definition wavetable_edit_section.cpp:561
void clear()
Clears the current wavetable editing state.
Definition wavetable_edit_section.cpp:781
void componentAdded(WavetableComponent *component) override
Callback when a wavetable component is added to the list.
Definition wavetable_edit_section.cpp:517
void nextClicked() override
Callback when 'next' is clicked, attempts to load next wavetable.
Definition wavetable_edit_section.cpp:365
void textMouseDown(const MouseEvent &e) override
Callback when text is clicked, possibly showing a browser to load wavetable.
Definition wavetable_edit_section.cpp:372
void frameChanged() override
Callback when a frame changes, triggers a display re-render.
Definition wavetable_edit_section.cpp:352
void init()
Initializes the wavetable state after loading or clearing.
Definition wavetable_edit_section.cpp:785
static String getWavetableDataString(InputStream *input_stream)
Extracts wavetable-specific data embedded in a .wav file's chunk.
Definition wavetable_edit_section.cpp:83
void paintBackground(Graphics &g) override
Paints the background of the wavetable edit section, including children.
Definition wavetable_edit_section.cpp:222
int getTopHeight()
Gets the top section height for title and controls.
Definition wavetable_edit_section.h:158
@ kExportWavetable
Definition wavetable_edit_section.h:61
@ kImportWavetable
Definition wavetable_edit_section.h:60
@ kResynthesizeWavetable
Definition wavetable_edit_section.h:63
@ kSaveAsWavetable
Definition wavetable_edit_section.h:59
@ kExportWav
Definition wavetable_edit_section.h:62
void reset() override
Resets the editing section, clearing and re-initializing components.
Definition wavetable_edit_section.cpp:302
void exportWavetable()
Exports the current wavetable as a .vitaltable file.
Definition wavetable_edit_section.cpp:570
Rectangle< int > getTimelineBounds()
Gets the bounds of the timeline area.
Definition wavetable_edit_section.cpp:215
virtual void wheelMoved(const MouseEvent &e, const MouseWheelDetails &wheel) override
Callback for wheel movements in the component list area.
Definition wavetable_edit_section.cpp:745
bool loadAudioAsWavetable(String name, InputStream *audio_stream, WavetableCreator::AudioFileLoadStyle style)
Loads audio data as a wavetable.
Definition wavetable_edit_section.cpp:649
void setZoom(int zoom)
Sets the zoom level for frequency domain rendering.
Definition wavetable_edit_section.cpp:773
WavetableEditSection(int index, WavetableCreator *wavetable_creator)
Constructs a WavetableEditSection.
Definition wavetable_edit_section.cpp:110
virtual ~WavetableEditSection()
Destructor.
Definition wavetable_edit_section.cpp:202
void prevClicked() override
Callback when 'previous' is clicked, attempts to load previous wavetable.
Definition wavetable_edit_section.cpp:358
void loadDefaultWavetable()
Loads the default wavetable (initializes a blank state).
Definition wavetable_edit_section.cpp:550
void mouseWheelMove(const MouseEvent &e, const MouseWheelDetails &wheel) override
Handles mouse wheel movement for zooming frequency domain views.
Definition wavetable_edit_section.cpp:325
A class representing a group of WavetableComponents combined to form part of a wavetable.
Definition wavetable_group.h:24
WavetableComponent * getComponent(int index) const
Retrieves a component by index.
Definition wavetable_group.h:92
int numComponents() const
Gets the number of WavetableComponents in this group.
Definition wavetable_group.h:84
Represents a single state of a waveform at a specific position in a wavetable.
Definition wavetable_keyframe.h:35
WavetableComponent * owner()
Gets the WavetableComponent that owns this keyframe.
Definition wavetable_keyframe.h:152
static constexpr float kHandleHeightPercent
Fraction of the total height used for the handle area.
Definition wavetable_organizer.h:75
static WavetableComponentOverlay * createOverlay(WavetableComponentFactory::ComponentType component_type)
Create an overlay for a given wavetable component type.
Definition wavetable_overlay_factory.cpp:13
std::complex< float > frequency_domain[kWaveformSize]
The frequency-domain representation (complex spectrum).
Definition wave_frame.h:125
static constexpr int kWaveformSize
The size of the waveform (number of samples per frame).
Definition wave_frame.h:21
static constexpr int kNumRealComplex
The number of real-valued frequency components (half the size + 1).
Definition wave_frame.h:23
void loadTimeDomain(float *buffer)
Loads time-domain data from a given buffer and updates the frequency domain accordingly.
Definition wave_frame.cpp:23
force_inline mono_float * getBuffer(int frame_index)
Get a pointer to the time-domain waveform buffer for a given frame.
Definition wavetable.h:184
static constexpr int kWaveformSize
Size of each waveform frame.
Definition wavetable.h:25
force_inline int numFrames() const
Get the number of frames in the current wavetable data.
Definition wavetable.h:312
#define VITAL_ASSERT(x)
Definition common.h:11
#define force_inline
Definition common.h:23
nlohmann::json json
Definition line_generator.h:7
force_inline poly_float midiNoteToFrequency(poly_float value)
Converts a MIDI note to a frequency (vectorized).
Definition poly_utils.h:123
Contains classes and functions used within the Vital synthesizer framework.
const std::string kWavetableExtension
File extension for Vital wavetable files.
Definition synth_constants.h:88
constexpr mono_float kPi
Pi constant.
Definition common.h:36
const std::string kWavetableExtensionsList
A semicolon-separated list of supported wavetable file extensions, including external formats like ....
Definition synth_constants.h:91
constexpr int kNumOscillatorWaveFrames
Number of wave frames in each oscillator’s wavetable.
Definition synth_constants.h:19
FileSource::FadeStyle getFadeStyleFromWavetableString(String data)
Determines the fading style to use when interpreting a wavetable from data strings.
Definition main.cpp:77
A helper struct containing references to OpenGL context, shaders, and display scale.
Definition shaders.h:174
A hierarchical structure of popup menu items for a selector component.
Definition synth_section.h:29
void addItem(int sub_id, const std::string &sub_name, bool sub_selected=false)
Adds a new item as a submenu entry.
Definition synth_section.h:51
Declares the SynthSlider and related classes, providing various slider styles and functionality in th...
Provides various utility functions, classes, and constants for audio, math, and general-purpose opera...