Vital
Loading...
Searching...
No Matches
wavetable_3d.cpp
Go to the documentation of this file.
1
3
4#include "wavetable_3d.h"
5
7#include "fourier_transform.h"
8#include "full_interface.h"
9#include "fonts.h"
10#include "skin.h"
11#include "synth_constants.h"
12#include "synth_gui_interface.h"
13#include "synth_oscillator.h"
14#include "utils.h"
15
16void Wavetable3d::paint3dLine(Graphics& g, vital::Wavetable* wavetable, int index, Colour color,
17 float width, float height, float wave_height_percent,
18 float wave_range_x, float frame_range_x, float wave_range_y, float frame_range_y,
19 float start_x, float start_y, float offset_x, float offset_y) {
20 PathStrokeType stroke(2.5f, PathStrokeType::beveled, PathStrokeType::butt);
21
22 float frame_t = index / (vital::kNumOscillatorWaveFrames - 1.0f);
23 float wave_start_x = start_x + frame_t * frame_range_x;
24 float wave_start_y = start_y + frame_t * frame_range_y;
25
26 float* buffer = wavetable->getBuffer(index);
27
28 Path path;
29 float loop_value = 0.5f * (buffer[0] + buffer[vital::Wavetable::kWaveformSize - 1]);
30 float loop_y_offset = -wave_height_percent * loop_value;
31 path.startNewSubPath(wave_start_x * width, (wave_start_y + loop_y_offset) * height);
32
33 g.setColour(color);
35
36 for (int i = 0; i < vital::Wavetable::kWaveformSize; i += inc) {
37 float wave_t = i / (vital::Wavetable::kWaveformSize - 1.0f);
38 float value = buffer[i];
39 float y_offset = -wave_height_percent * value;
40 float x = wave_start_x + wave_t * wave_range_x;
41 float y = wave_start_y + wave_t * wave_range_y + y_offset;
42 path.lineTo(x * width, y * height);
43 }
44
45 path.lineTo((wave_start_x + wave_range_x) * width, (wave_start_y + wave_range_y + loop_y_offset) * height);
46
47 g.strokePath(path, stroke);
48}
49
50void Wavetable3d::paint3dBackground(Graphics& g, vital::Wavetable* wavetable, bool active,
51 Colour background_color, Colour wave_color1, Colour wave_color2,
52 float width, float height,
53 float wave_height_percent,
54 float wave_range_x, float frame_range_x, float wave_range_y, float frame_range_y,
55 float start_x, float start_y, float offset_x, float offset_y) {
56 PathStrokeType stroke(1.0f, PathStrokeType::beveled, PathStrokeType::butt);
57
58 for (int f = vital::kNumOscillatorWaveFrames - 1; f >= -kExtraShadows; --f) {
59 float frame_t = f / (vital::kNumOscillatorWaveFrames - 1.0f);
60 float wave_start_x = start_x + frame_t * frame_range_x;
61 float wave_start_y = start_y + frame_t * frame_range_y;
62
63 if (f >= 0) {
64 float* buffer = wavetable->getBuffer(f);
65
66 Path path;
67 float loop_value = 0.5f * (buffer[0] + buffer[vital::Wavetable::kWaveformSize - 1]);
68 float loop_y_offset = -wave_height_percent * loop_value;
69 path.startNewSubPath(wave_start_x * width, (wave_start_y + loop_y_offset) * height);
70
71 Colour wave_color = wave_color1;
72 if (f % kColorJump)
73 wave_color = wave_color2;
74 if (!active)
75 wave_color = wave_color.withSaturation(0.0f).interpolatedWith(background_color, 0.5f);
76
77 Colour wave_dip = background_color;
78 wave_dip = wave_dip.withAlpha(wave_color.getAlpha());
79
80 g.setGradientFill(ColourGradient(wave_color, wave_start_x * width, start_y * height,
81 wave_dip, (wave_start_x + offset_x) * width,
82 (start_y + offset_y) * height, false));
84
85 for (int i = 0; i < vital::Wavetable::kWaveformSize; i += inc) {
86 float wave_t = i / (vital::Wavetable::kWaveformSize - 1.0f);
87 float value = buffer[i];
88 float y_offset = -wave_height_percent * value;
89 float x = wave_start_x + wave_t * wave_range_x;
90 float y = wave_start_y + wave_t * wave_range_y + y_offset;
91 path.lineTo(x * width, y * height);
92 }
93
94 path.lineTo((wave_start_x + wave_range_x) * width, (wave_start_y + wave_range_y + loop_y_offset) * height);
95
96 g.strokePath(path, stroke);
97 }
98 }
99}
100
101Wavetable3d::Wavetable3d(int index, const vital::output_map& mono_modulations,
102 const vital::output_map& poly_modulations) :
103 left_line_renderer_(kResolution + 2), right_line_renderer_(kResolution + 2),
104 end_caps_(2, Shaders::kRingFragment),
105 import_overlay_(Shaders::kColorFragment), drag_load_style_(WavetableCreator::kNone), transform_(kNumBits),
106 size_(kResolution), index_(index), wavetable_(nullptr) {
107 wavetable_index_ = 0;
108 std::string number = std::to_string(index_ + 1);
109 std::string wave_frame_name = "osc_" + number + "_wave_frame";
110 wave_frame_outputs_ = {
111 mono_modulations.at(wave_frame_name),
112 poly_modulations.at(wave_frame_name)
113 };
114
115 std::string spectral_morph_name = "osc_" + number + "_spectral_morph_amount";
116 spectral_morph_outputs_ = {
117 mono_modulations.at(spectral_morph_name),
118 poly_modulations.at(spectral_morph_name)
119 };
120
121 std::string distortion_name = "osc_" + number + "_distortion_amount";
122 distortion_outputs_ = {
123 mono_modulations.at(distortion_name),
124 poly_modulations.at(distortion_name)
125 };
126
127 std::string distortion_phase_name = "osc_" + number + "_distortion_phase";
128 distortion_phase_outputs_ = {
129 mono_modulations.at(distortion_phase_name),
130 poly_modulations.at(distortion_phase_name)
131 };
132
133 import_overlay_.setTargetComponent(this);
134 import_overlay_.setQuad(0, -1.0f, -1.0f, 2.0f, 2.0f);
135 wavetable_import_text_ = std::make_unique<PlainTextComponent>("wavetable", "WAVETABLE");
136 wavetable_import_text_->setJustification(Justification::centred);
137 wavetable_import_text_->setFontType(PlainTextComponent::kLight);
138 addAndMakeVisible(wavetable_import_text_.get());
139 vocode_import_text_ = std::make_unique<PlainTextComponent>("vocode", "VOCODE");
140 vocode_import_text_->setJustification(Justification::centred);
141 vocode_import_text_->setFontType(PlainTextComponent::kLight);
142 addAndMakeVisible(vocode_import_text_.get());
143 pitch_splice_import_text_ = std::make_unique<PlainTextComponent>("pitch splice", "PITCH SPLICE");
144 pitch_splice_import_text_->setJustification(Justification::centred);
145 pitch_splice_import_text_->setFontType(PlainTextComponent::kLight);
146 addAndMakeVisible(pitch_splice_import_text_.get());
147
148 wavetable_ = nullptr;
149 frame_slider_ = nullptr;
150 last_spectral_morph_type_ = vital::SynthOscillator::kNumSpectralMorphTypes;
151 last_distortion_type_ = vital::SynthOscillator::kNumDistortionTypes;
152 spectral_morph_type_ = vital::SynthOscillator::kNoSpectralMorph;
153 distortion_type_ = vital::SynthOscillator::kNone;
154 spectral_morph_slider_ = nullptr;
155 distortion_slider_ = nullptr;
156 distortion_phase_slider_ = nullptr;
157 animate_ = false;
158 loading_wavetable_ = false;
159 last_loading_wavetable_ = false;
160 render_type_ = kFrequencyAmplitudes;
161 last_render_type_ = kFrequencyAmplitudes;
162 active_ = true;
163 current_value_ = 0.0;
164
165 vertical_angle_ = kDefaultVerticalAngle;
166 horizontal_angle_ = kDefaultHorizontalAngle;
167 draw_width_percent_ = kDefaultDrawWidthPercent;
168 wave_height_percent_ = kDefaultWaveHeightPercent;
169 y_offset_ = 0.0f;
170 setDimensionValues();
171
172 addAndMakeVisible(left_line_renderer_);
173 addAndMakeVisible(right_line_renderer_);
174 addAndMakeVisible(end_caps_);
175
176 left_line_renderer_.setInterceptsMouseClicks(false, false);
177 right_line_renderer_.setInterceptsMouseClicks(false, false);
178}
179
180Wavetable3d::~Wavetable3d() = default;
181
184 left_line_renderer_.setParent(parent_);
185 right_line_renderer_.setParent(parent_);
186
187 if (wavetable_ == nullptr) {
188 SynthGuiInterface* parent = findParentComponentOfClass<SynthGuiInterface>();
189 wavetable_ = parent->getSynth()->getWavetable(index_);
190 }
191 if (render_type_ != kWave3d)
192 return;
193
194 PathStrokeType stroke(1.0f, PathStrokeType::beveled, PathStrokeType::butt);
195 Colour background_color = findColour(Skin::kBody, true);
196 Colour wave_color1 = findColour(Skin::kWidgetAccent1, true);
197 Colour wave_color2 = findColour(Skin::kWidgetAccent2, true);
198
199 paint3dBackground(g, wavetable_, isActive(), background_color, wave_color1, wave_color2,
200 getWidth(), getHeight(),
201 wave_height_percent_, wave_range_x_, frame_range_x_, wave_range_y_, frame_range_y_,
202 start_x_, start_y_, offset_x_, offset_y_);
203}
204
206 static constexpr float kTextHeightPercent = 0.1f;
207
208 setDimensionValues();
209 setColors();
210
211 left_line_renderer_.setBounds(getLocalBounds());
212 right_line_renderer_.setBounds(getLocalBounds());
213 end_caps_.setBounds(getLocalBounds());
215
216 float font_height = getHeight() * kTextHeightPercent;
217 int text_height = getHeight() / 2;
218 int text_y_adjust = getHeight() / 4;
219 int width = getWidth();
220
221 wavetable_import_text_->setTextSize(font_height);
222 vocode_import_text_->setTextSize(font_height);
223 pitch_splice_import_text_->setTextSize(font_height);
224
225 wavetable_import_text_->setBounds(0, 0, width, text_height);
226 vocode_import_text_->setBounds(0, text_y_adjust, width, text_height);
227 pitch_splice_import_text_->setBounds(0, 2 * text_y_adjust, width, text_height);
228 wavetable_import_text_->redrawImage(false);
229 vocode_import_text_->redrawImage(false);
230 pitch_splice_import_text_->redrawImage(false);
231
232 import_text_color_ = findColour(Skin::kTextComponentText, true);
233 import_overlay_.setColor(findColour(Skin::kOverlayScreen, true));
234}
235
236inline vital::poly_float Wavetable3d::getOutputsTotal(
237 std::pair<vital::Output*, vital::Output*> outputs, vital::poly_float default_value) {
238 if (!outputs.first->owner->enabled() || !animate_)
239 return default_value;
240 if (num_voices_readout_ == nullptr || num_voices_readout_->value()[0] <= 0.0f)
241 return outputs.first->trigger_value;
242
243 return outputs.first->trigger_value + outputs.second->trigger_value;
244}
245
246void Wavetable3d::mouseDown(const MouseEvent& e) {
247 Component::mouseDown(e);
248 if (e.mods.isPopupMenu()) {
249 PopupItems options;
250
251 options.addItem(kSave, "Save to Wavetables");
252 options.addItem(kCopy, "Copy");
254 options.addItem(kPaste, "Paste");
255
256 options.addItem(-1, "");
257 options.addItem(kInit, "Initialize");
258
259 FullInterface* full_interface = findParentComponentOfClass<FullInterface>();
260 if (full_interface && !full_interface->getSignedInName().empty())
261 options.addItem(kTextToWavetable, "Text to Wavetable");
262 else
263 options.addItem(kLogIn, "Text to Wavetable - Log in");
264
265 options.addItem(kResynthesizePreset, "Resynthesize Preset to Wavetable");
266
267 SynthSection* parent = findParentComponentOfClass<SynthSection>();
268 parent->showPopupSelector(this, e.getPosition(), options, [=](int selection) { respondToMenuCallback(selection); });
269 }
270 else {
271 if (frame_slider_ == nullptr)
272 return;
273
274 current_value_ = frame_slider_->getValue();
275 last_edit_position_ = e.getPosition();
276 frame_slider_->showPopup(true);
277 }
278}
279
280void Wavetable3d::mouseDrag(const MouseEvent& e) {
281 Component::mouseDrag(e);
282 if (frame_slider_ == nullptr || e.mods.isRightButtonDown())
283 return;
284
285 Point<int> position = e.getPosition();
286 int delta = position.y - last_edit_position_.y;
287 float range = frame_slider_->getMaximum() - frame_slider_->getMinimum();
288 current_value_ -= delta * range / getHeight();
289 current_value_ = std::max(std::min(current_value_, frame_slider_->getMaximum()), frame_slider_->getMinimum());
290 frame_slider_->setValue(current_value_);
291 frame_slider_->showPopup(true);
292 last_edit_position_ = position;
293}
294
295void Wavetable3d::mouseWheelMove(const MouseEvent& e, const MouseWheelDetails& wheel) {
296 frame_slider_->mouseWheelMove(e, wheel);
297}
298
299void Wavetable3d::mouseExit(const MouseEvent& e) {
300 frame_slider_->hidePopup(true);
301}
302
303bool Wavetable3d::updateRenderValues() {
304 bool new_morph = last_spectral_morph_type_ != spectral_morph_type_ ||
305 last_distortion_type_ != distortion_type_ ||
306 last_render_type_ != render_type_ || last_loading_wavetable_ != loading_wavetable_;
307 last_spectral_morph_type_ = spectral_morph_type_;
308 last_distortion_type_ = distortion_type_;
309 last_render_type_ = render_type_;
310 last_loading_wavetable_ = loading_wavetable_;
311
312 vital::poly_float wave_frame = getOutputsTotal(wave_frame_outputs_, frame_slider_->getValue());
313 vital::poly_float spectral_morph_value = getSpectralMorphValue();
314 vital::poly_float distortion_value = getDistortionValue();
315 vital::poly_int distortion_phase = getDistortionPhaseValue();
316
318 equal = equal & vital::poly_float::equal(wave_frame_, wave_frame);
319 equal = equal & vital::poly_float::equal(spectral_morph_value_, spectral_morph_value);
320 equal = equal & vital::poly_float::equal(distortion_value_, distortion_value);
321 equal = equal & vital::poly_int::equal(distortion_phase_, distortion_phase);
322
323 wave_frame_ = wave_frame;
324 spectral_morph_value_ = spectral_morph_value;
325 distortion_value_ = distortion_value;
326 distortion_phase_ = distortion_phase;
327
328 return !loading_wavetable_ && ((~equal).anyMask() || new_morph);
329}
330
331void Wavetable3d::loadWaveData(int index) {
332 if (wavetable_ == nullptr)
333 return;
334
335 float width = getWidth();
336 float height = getHeight();
337
338 float wave_height = k2dWaveHeightPercent * height;
339 float wave_width = width;
340 float wave_range_y = 0.0f;
341 float start_x = 0.0f;
342 float start_y = height / 2.0f;
343
344 if (last_render_type_ == kWave3d) {
345 float wave_frame = getOutputsTotal(wave_frame_outputs_, frame_slider_->getValue())[index];
346 float frame_t = vital::utils::clamp(wave_frame / (vital::kNumOscillatorWaveFrames - 1.0f), 0.0f, 1.0f);
347 start_x = (0.5f * (1.0f - wave_range_x_ - frame_range_x_) + frame_range_x_ * frame_t) * width;
348 start_y = (0.5f * (1.0f - wave_range_y_ - frame_range_y_) + y_offset_ + frame_range_y_ * frame_t) * height;
349 wave_width = wave_range_x_ * width;
350 wave_range_y = wave_range_y_ * height;
351 wave_height = wave_height_percent_ * height;
352 }
353
354 loadIntoTimeDomain(index);
355
356 OpenGlLineRenderer* renderer = &left_line_renderer_;
357 if (index)
358 renderer = &right_line_renderer_;
359
360 vital::poly_float spread(1.0f, 2.0f, 3.0f, 4.0f);
361 float* time_domain = process_frame_.time_domain;
362 float delta = 1.0f / size_;
363 for (int i = 0; i < size_ - vital::poly_float::kSize + 1; i += vital::poly_float::kSize) {
364 vital::poly_float t = (spread + i) * delta;
365
366 for (int v = 0; v < vital::poly_float::kSize; ++v) {
367 int point_index = i + v + 1;
368 renderer->setXAt(point_index, start_x + t[v] * wave_width);
369 float y = start_y - time_domain[i + v] * wave_height + t[v] * wave_range_y;
370 renderer->setYAt(point_index, y);
371 }
372 }
373
374 float average = (renderer->yAt(1) + renderer->yAt(size_) - wave_range_y) * 0.5f;
375 renderer->setXAt(0, start_x);
376 renderer->setYAt(0, average);
377 int line_end_index = size_ + 1;
378 renderer->setXAt(line_end_index, start_x + wave_width);
379 renderer->setYAt(line_end_index, average + wave_range_y);
380}
381
382void Wavetable3d::loadSpectrumData(int index) {
383 static constexpr float kMinDb = -30.0f;
384 static constexpr float kMaxDb = 50.0f;
385 static constexpr float kDbRange = kMaxDb - kMinDb;
386 static constexpr float kDbBoostPerOctave = 3.0f;
387
388 loadIntoTimeDomain(index);
389 process_frame_.toFrequencyDomain();
390 std::complex<float>* frequency_domain = process_frame_.frequency_domain;
391
392 OpenGlLineRenderer* renderer = &left_line_renderer_;
393 if (index)
394 renderer = &right_line_renderer_;
395
396 int width = getWidth();
397 int height = getHeight();
398 float center = height * 0.5f;
399 int num_points = std::min(width, vital::Wavetable::kWaveformSize / 2);
400 float scale = 1.0f / num_points;
401 int last_frequency = 0;
402 for (int i = 0; i <= num_points; ++i) {
403 int invert_i = vital::Wavetable::kWaveformSize + 1 - i;
404 float t = i * 1.0f / num_points;
405 float x = t * width;
406 renderer->setXAt(i, x);
407 renderer->setXAt(invert_i, x);
408
409 float position = vital::futils::exp2(t * (vital::Wavetable::kFrequencyBins - 1.0f));
410 int frequency = std::min<int>(position, vital::Wavetable::kWaveformSize / 2 - 1);
411 float frequency_t = position - frequency;
412
413 float amplitude_from = std::abs(frequency_domain[frequency]);
414 float amplitude_to = std::abs(frequency_domain[frequency + 1]);
415 float amplitude = vital::utils::interpolate(amplitude_from, amplitude_to, frequency_t) * scale;
416
417 for (int f = last_frequency + 1; f < frequency; ++f)
418 amplitude = std::max(std::abs(frequency_domain[f]) * scale, amplitude);
419
420 last_frequency = frequency;
421
422 float db = vital::utils::magnitudeToDb(amplitude) + t * vital::Wavetable::kFrequencyBins * kDbBoostPerOctave;
423 float y = std::max(db - kMinDb, 0.0f) / kDbRange;
424 renderer->setYAt(i, y * center + center);
425 renderer->setYAt(invert_i, -y * center + center);
426 }
427
428 float end = width * 1.5f;
429 for (int i = width; i <= vital::Wavetable::kWaveformSize / 2; ++i) {
430 int invert_i = vital::Wavetable::kWaveformSize + 1 - i;
431 renderer->setXAt(i, end);
432 renderer->setXAt(invert_i, end);
433 renderer->setYAt(i, center);
434 renderer->setYAt(invert_i, center);
435 }
436}
437
439 left_line_renderer_.init(open_gl);
440 right_line_renderer_.init(open_gl);
441 end_caps_.init(open_gl);
442 import_overlay_.init(open_gl);
443 wavetable_import_text_->init(open_gl);
444 vocode_import_text_->init(open_gl);
445 pitch_splice_import_text_->init(open_gl);
446}
447
448void Wavetable3d::render(OpenGlWrapper& open_gl, bool animate) {
449 animate_ = animate;
450
451 if (render_type_ == kFrequencyAmplitudes)
452 renderSpectrum(open_gl);
453 else
454 renderWave(open_gl);
455
456 if (drag_load_style_ != WavetableCreator::kNone) {
457 import_overlay_.render(open_gl, animate);
458 Colour background = import_overlay_.getColor();
459
460 wavetable_import_text_->setColor(import_text_color_.interpolatedWith(background, 0.5f));
461 vocode_import_text_->setColor(import_text_color_.interpolatedWith(background, 0.5f));
462 pitch_splice_import_text_->setColor(import_text_color_.interpolatedWith(background, 0.5f));
463
464 if (drag_load_style_ == WavetableCreator::kWavetableSplice)
465 wavetable_import_text_->setColor(import_text_color_);
466 else if (drag_load_style_ == WavetableCreator::kVocoded)
467 vocode_import_text_->setColor(import_text_color_);
468 else if (drag_load_style_ == WavetableCreator::kPitched)
469 pitch_splice_import_text_->setColor(import_text_color_);
470
471 wavetable_import_text_->render(open_gl, animate);
472 vocode_import_text_->render(open_gl, animate);
473 pitch_splice_import_text_->render(open_gl, animate);
474 }
475
476 left_line_renderer_.renderCorners(open_gl, animate);
477}
478
480 if (wavetable_ == nullptr)
481 return;
482
483 left_line_renderer_.setFill(render_type_ == kWave2d);
484 right_line_renderer_.setFill(render_type_ == kWave2d);
485
486 float fill_fade = findValue(Skin::kWidgetFillFade);
487 float line_width = findValue(Skin::kWidgetLineWidth);
488 float fill_center = findValue(Skin::kWidgetFillCenter);
489
490 left_line_renderer_.setLineWidth(line_width);
491 right_line_renderer_.setLineWidth(line_width);
492
493 left_line_renderer_.setFillCenter(fill_center);
494 right_line_renderer_.setFillCenter(fill_center);
495
496 bool new_line_data = updateRenderValues();
497
498 if (new_line_data) {
499 loadWaveData(0);
500 loadWaveData(1);
501 }
502
503 Colour left_fill;
504 Colour right_fill;
505 if (isActive()) {
506 left_line_renderer_.setColor(line_left_color_);
507 right_line_renderer_.setColor(line_right_color_);
508 left_fill = fill_left_color_;
509 right_fill = fill_right_color_;
510 }
511 else {
512 left_line_renderer_.setColor(line_disabled_color_);
513 right_line_renderer_.setColor(line_disabled_color_);
514 left_fill = fill_disabled_color_;
515 right_fill = fill_disabled_color_;
516 }
517
518 left_line_renderer_.setFillColors(left_fill.withMultipliedAlpha(1.0f - fill_fade), left_fill);
519 right_line_renderer_.setFillColors(right_fill.withMultipliedAlpha(1.0f - fill_fade), right_fill);
520 left_line_renderer_.render(open_gl, animate_);
521 right_line_renderer_.render(open_gl, animate_);
522
523 if (render_type_ == kWave3d) {
524 drawPosition(open_gl, 1);
525 drawPosition(open_gl, 0);
526 }
527}
528
530 float fill_fade = findValue(Skin::kWidgetFillFade);
531 left_line_renderer_.setFill(true);
532 right_line_renderer_.setFill(true);
533 left_line_renderer_.setLineWidth(2.5f);
534 right_line_renderer_.setLineWidth(2.5f);
535
536 bool new_data = updateRenderValues();
537
538 if (new_data) {
539 loadSpectrumData(0);
540 loadSpectrumData(1);
541 }
542
543 Colour right_fill = fill_right_color_;
544 Colour left_fill = fill_left_color_;
545 if (isActive()) {
546 right_line_renderer_.setColor(line_right_color_);
547 left_line_renderer_.setColor(line_left_color_);
548 right_fill = fill_right_color_;
549 left_fill = fill_left_color_;
550 }
551 else {
552 right_line_renderer_.setColor(line_disabled_color_);
553 left_line_renderer_.setColor(line_disabled_color_);
554 left_line_renderer_.setColor(line_disabled_color_);
555 right_fill = fill_disabled_color_;
556 left_fill = fill_disabled_color_;
557 }
558
559 right_line_renderer_.setFillColors(right_fill.withMultipliedAlpha(1.0f - fill_fade), right_fill);
560 left_line_renderer_.setFillColors(left_fill.withMultipliedAlpha(1.0f - fill_fade), left_fill);
561
562 right_line_renderer_.render(open_gl, animate_);
563 left_line_renderer_.render(open_gl, animate_);
564}
565
567 left_line_renderer_.destroy(open_gl);
568 right_line_renderer_.destroy(open_gl);
569 end_caps_.destroy(open_gl);
570 import_overlay_.destroy(open_gl);
571 wavetable_import_text_->destroy(open_gl);
572 vocode_import_text_->destroy(open_gl);
573 pitch_splice_import_text_->destroy(open_gl);
574}
575
576void Wavetable3d::drawPosition(OpenGlWrapper& open_gl, int index) {
577 Colour color;
578 if (index)
579 color = line_right_color_;
580 else
581 color = line_left_color_;
582
583 if (!isActive())
584 color = color.withSaturation(0.0f).interpolatedWith(body_color_, 0.5f);
585 end_caps_.setColor(color);
586 Colour background = findColour(Skin::kWidgetBackground, true);
587 end_caps_.setAltColor(color.interpolatedWith(background, 0.5f));
588
589 int draw_width = getWidth();
590 int draw_height = getHeight();
591 float position_raw_width = kPositionLineWidthRatio * findValue(Skin::kWidgetLineWidth);
592 float position_height = 2.0f * position_raw_width / draw_height;
593 float position_width = 2.0f * position_raw_width / draw_width;
594 end_caps_.setThickness(position_raw_width / 5.0f);
595
596 OpenGlLineRenderer* renderer = &left_line_renderer_;
597 if (index)
598 renderer = &right_line_renderer_;
599
600 float x = 2.0f * renderer->xAt(0) / draw_width - 1.0f;
601 float y = 1.0f - 2.0f * renderer->yAt(0) / draw_height;
602 float end_x = 2.0f * renderer->xAt(size_) / draw_width - 1.0f;
603 float end_y = 1.0f - 2.0f * renderer->yAt(size_) / draw_height;
604 end_caps_.setQuad(0, x - 0.5f * position_width, y - 0.5f * position_height, position_width, position_height);
605 end_caps_.setQuad(1, end_x - 0.5f * position_width, end_y - 0.5f * position_height, position_width, position_height);
606 end_caps_.render(open_gl, true);
607}
608
609void Wavetable3d::setViewSettings(float horizontal_angle, float vertical_angle,
610 float draw_width, float wave_height, float y_offset) {
611 horizontal_angle_ = horizontal_angle;
612 vertical_angle_ = vertical_angle;
613 draw_width_percent_ = draw_width;
614 wave_height_percent_ = wave_height;
615 y_offset_ = y_offset;
616 setDimensionValues();
617}
618
620 render_type_ = render_type;
622}
623
625 if (option == kInit) {
626 for (Listener* listener : listeners_)
627 listener->loadDefaultWavetable();
629 setDirty();
630 }
631 else if (option == kSave) {
632 for (Listener* listener : listeners_)
633 listener->saveWavetable();
634 }
635 else if (option == kTextToWavetable) {
636 for (Listener* listener : listeners_)
637 listener->textToWavetable();
638 }
639 else if (option == kResynthesizePreset) {
640 for (Listener* listener : listeners_)
641 listener->resynthesizeToWavetable();
643 setDirty();
644 }
645 else if (option == kLogIn) {
646 FullInterface* full_interface = findParentComponentOfClass<FullInterface>();
647 return full_interface->signIn();
648 }
649 else if (option == kCopy) {
650 FullInterface* parent = findParentComponentOfClass<FullInterface>();
651 if (parent == nullptr)
652 return;
653
654 SystemClipboard::copyTextToClipboard(parent->getWavetableJson(index_).dump());
655 }
656 else if (option == kPaste) {
657 String text = SystemClipboard::getTextFromClipboard();
658
659 try {
660 json parsed_json_state = json::parse(text.toStdString(), nullptr, false);
661 if (WavetableCreator::isValidJson(parsed_json_state)) {
662 loading_wavetable_ = true;
663 for (Listener* listener : listeners_)
664 listener->loadWavetable(parsed_json_state);
665 loading_wavetable_ = false;
666
668 setDirty();
669 }
670 }
671 catch (const json::exception& e) {
672 }
673 }
674}
675
677 String text = SystemClipboard::getTextFromClipboard();
678 try {
679 json parsed_json_state = json::parse(text.toStdString(), nullptr, false);
680 return WavetableCreator::isValidJson(parsed_json_state);
681 }
682 catch (const json::exception& e) {
683 return false;
684 }
685}
686
687void Wavetable3d::audioFileLoaded(const File& file) {
688 for (Listener* listener : listeners_) {
689 FileInputStream* input_stream = new FileInputStream(file);
690 if (input_stream->openedOk())
691 listener->loadAudioAsWavetable(file.getFileNameWithoutExtension(), input_stream, drag_load_style_);
692 }
693
694 drag_load_style_ = WavetableCreator::kNone;
695}
696
698 static constexpr float kDivisionPercent = 3.0f / 8.0f;
700 if (y < kDivisionPercent * getHeight())
702 else if (y > (1.0f - kDivisionPercent) * getHeight())
703 new_style = WavetableCreator::kPitched;
704
705 if (new_style != drag_load_style_)
706 drag_load_style_ = new_style;
707}
708
709void Wavetable3d::setDimensionValues() {
710 wave_range_x_ = cosf(horizontal_angle_) * draw_width_percent_;
711 frame_range_x_ = -sinf(horizontal_angle_) * draw_width_percent_;
712 wave_range_y_ = 2.0f * frame_range_x_ * cosf(vertical_angle_);
713 frame_range_y_ = -2.0f * wave_range_x_ * cosf(vertical_angle_);
714 start_x_ = 0.5f * (1.0f - wave_range_x_ - frame_range_x_);
715 start_y_ = 0.5f * (1.0f - wave_range_y_ - frame_range_y_) + y_offset_;
716 float draw_angle = atanf(wave_range_y_ / wave_range_x_);
717 offset_x_ = -sinf(draw_angle) * 1.5f * wave_height_percent_;
718 offset_y_ = cosf(draw_angle) * 1.5f * wave_height_percent_;
719}
720
721void Wavetable3d::setColors() {
722 body_color_ = findColour(Skin::kBody, true);
723 line_left_color_ = findColour(Skin::kWidgetPrimary1, true);
724 line_right_color_ = findColour(Skin::kWidgetPrimary2, true);
725 line_disabled_color_ = findColour(Skin::kWidgetPrimaryDisabled, true);
726 fill_left_color_ = findColour(Skin::kWidgetSecondary1, true);
727 fill_right_color_ = findColour(Skin::kWidgetSecondary2, true);
728 fill_disabled_color_ = findColour(Skin::kWidgetSecondaryDisabled, true);
729}
730
731vital::poly_float Wavetable3d::getDistortionValue() {
732 vital::poly_float distortion = getOutputsTotal(distortion_outputs_, distortion_slider_->getValue());
733 vital::poly_float adjusted_distortion = vital::utils::clamp(distortion, 0.0f, 1.0f);
735 vital::SynthOscillator::setDistortionValues(distortion_type, &adjusted_distortion, 1, false);
736 return adjusted_distortion;
737}
738
739vital::poly_float Wavetable3d::getSpectralMorphValue() {
740 vital::poly_float morph = getOutputsTotal(spectral_morph_outputs_, spectral_morph_slider_->getValue());
741 vital::poly_float adjusted_morph = vital::utils::clamp(morph, 0.0f, 1.0f);
743 vital::SynthOscillator::setSpectralMorphValues(morph_type, &adjusted_morph, 1, false);
744 return adjusted_morph;
745}
746
747vital::poly_int Wavetable3d::getDistortionPhaseValue() {
750 return 0;
751
752 vital::poly_float phase = getOutputsTotal(distortion_phase_outputs_, distortion_phase_slider_->getValue());
753 return vital::utils::toInt(phase * UINT_MAX - INT_MAX);
754}
755
756
757void Wavetable3d::loadIntoTimeDomain(int index) {
758 loadFrequencyData(index);
759 warpSpectrumToWave(index);
760 warpPhase(index);
761}
762
763void Wavetable3d::loadFrequencyData(int index) {
764 wavetable_index_ = std::round(getOutputsTotal(wave_frame_outputs_, frame_slider_->getValue())[index]);
765 current_wavetable_data_ = wavetable_->getAllData();
766 wavetable_index_ = std::max(0, std::min(wavetable_index_, current_wavetable_data_->num_frames - 1));
767}
768
769void Wavetable3d::warpSpectrumToWave(int index) {
770 float morph = spectral_morph_value_[index];
772
773 memset(process_wave_data_, 0, vital::SynthOscillator::kSpectralBufferSize * sizeof(vital::poly_float));
774 vital::SynthOscillator::runSpectralMorph(morph_type, morph, current_wavetable_data_, wavetable_index_,
775 process_wave_data_, &transform_);
776}
777
778void Wavetable3d::warpPhase(int index) {
779 float distortion = distortion_value_[index];
781
782 vital::poly_float spread(1.0f, 2.0f, 3.0f, 4.0f);
783 float delta = 1.0f / size_;
784 float* buffer = (float*)(process_wave_data_ + 1);
785 float* time_domain = process_frame_.time_domain;
786 for (int i = 0; i < size_ - vital::poly_float::kSize + 1; i += vital::poly_float::kSize) {
787 vital::poly_float t = (spread + i) * delta;
788 vital::poly_int original_phase = vital::utils::toInt(t * UINT_MAX - INT_MAX) + INT_MAX;
789 vital::poly_int adjusted_phase = vital::SynthOscillator::adjustPhase(distortion_type, original_phase,
790 distortion, distortion_phase_);
791
792 vital::poly_float window = vital::SynthOscillator::getPhaseWindow(distortion_type, original_phase, adjusted_phase);
793 adjusted_phase += distortion_phase_;
794
795 vital::poly_float value = window * vital::SynthOscillator::interpolate(buffer, adjusted_phase);
796 for (int v = 0; v < vital::poly_float::kSize; ++v)
797 time_domain[i + v] = value[v];
798 }
799}
The main GUI container for the entire synthesizer interface.
Definition full_interface.h:61
std::string getSignedInName()
Gets the name of the currently signed-in user, if any.
Definition full_interface.cpp:792
json getWavetableJson(int index)
Retrieves the JSON data representing the current wavetable for an oscillator.
Definition full_interface.cpp:857
void signIn()
Opens the sign-in interface, if available.
Definition full_interface.cpp:804
virtual void resized() override
Called when the component is resized.
Definition open_gl_component.cpp:121
const vital::StatusOutput * num_voices_readout_
StatusOutput for voice count lookups.
Definition open_gl_component.h:258
void setParent(const SynthSection *parent)
Sets a pointer to the parent SynthSection for skin value lookups.
Definition open_gl_component.h:178
void renderCorners(OpenGlWrapper &open_gl, bool animate, Colour color, float rounding)
Renders the corner shapes using the given color and rounding amount.
Definition open_gl_component.cpp:153
float findValue(Skin::ValueId value_id)
Finds a float value from the skin associated with this component's parent.
Definition open_gl_component.cpp:173
virtual void paintBackground(Graphics &g)
Paints a standard background for the component.
Definition open_gl_component.cpp:105
void repaintBackground()
Requests a repaint of the component's background on the OpenGL layer.
Definition open_gl_component.cpp:112
const SynthSection * parent_
Pointer to parent SynthSection for skin lookups.
Definition open_gl_component.h:256
A component for rendering lines with optional filling and boost effects using OpenGL.
Definition open_gl_line_renderer.h:16
virtual void init(OpenGlWrapper &open_gl) override
Initializes OpenGL resources for rendering the line.
Definition open_gl_line_renderer.cpp:78
virtual void destroy(OpenGlWrapper &open_gl) override
Destroys OpenGL resources allocated by this line renderer.
Definition open_gl_line_renderer.cpp:468
force_inline float xAt(int index) const
Gets the x-coordinate of a point at a given index.
Definition open_gl_line_renderer.h:81
force_inline void setFillCenter(float fill_center)
Sets the vertical center for the fill area.
Definition open_gl_line_renderer.h:138
virtual void render(OpenGlWrapper &open_gl, bool animate) override
Renders the line using OpenGL.
Definition open_gl_line_renderer.cpp:464
force_inline void setYAt(int index, float val)
Sets the y-coordinate of a point, marking data as dirty.
Definition open_gl_line_renderer.h:98
force_inline void setFill(bool fill)
Enables or disables filling below the line.
Definition open_gl_line_renderer.h:124
force_inline void setXAt(int index, float val)
Sets the x-coordinate of a point, marking data as dirty.
Definition open_gl_line_renderer.h:105
force_inline void setFillColors(Colour fill_color_from, Colour fill_color_to)
Sets a gradient fill from one color to another.
Definition open_gl_line_renderer.h:132
force_inline void setLineWidth(float width)
Sets the line width in pixels.
Definition open_gl_line_renderer.h:66
force_inline float yAt(int index) const
Gets the y-coordinate of a point at a given index.
Definition open_gl_line_renderer.h:78
force_inline void setColor(Colour color)
Sets the line color.
Definition open_gl_line_renderer.h:63
void setThickness(float thickness, bool reset=false)
Sets the thickness used by some shaders and can reset to this thickness.
Definition open_gl_multi_quad.h:338
virtual void init(OpenGlWrapper &open_gl) override
Initializes OpenGL buffers and shader attributes.
Definition open_gl_multi_quad.cpp:37
void setQuad(int i, float x, float y, float w, float h)
Sets the position and size of a quad in normalized device space.
Definition open_gl_multi_quad.h:313
void setTargetComponent(Component *target_component)
Sets a target component to help position the quads.
Definition open_gl_multi_quad.h:358
force_inline void setAltColor(Colour color)
Sets an alternate color, often used by custom shaders.
Definition open_gl_multi_quad.h:118
virtual void render(OpenGlWrapper &open_gl, bool animate) override
Renders the quads using OpenGL.
Definition open_gl_multi_quad.cpp:92
virtual void destroy(OpenGlWrapper &open_gl) override
Releases OpenGL resources when the component is destroyed.
Definition open_gl_multi_quad.cpp:69
force_inline void setColor(Colour color)
Sets the base color for the quads.
Definition open_gl_multi_quad.h:102
force_inline Colour getColor()
Gets the current base color.
Definition open_gl_multi_quad.h:110
@ kLight
Definition open_gl_image_component.h:309
Manages and provides access to vertex and fragment shaders used by the OpenGL rendering pipeline.
Definition shaders.h:19
@ kWidgetLineWidth
Definition skin.h:105
@ kWidgetFillCenter
Definition skin.h:107
@ kWidgetFillFade
Definition skin.h:108
@ kWidgetAccent1
Definition skin.h:171
@ kWidgetPrimaryDisabled
Definition skin.h:167
@ kWidgetPrimary2
Definition skin.h:166
@ kWidgetPrimary1
Definition skin.h:165
@ kWidgetBackground
Definition skin.h:173
@ kWidgetSecondary1
Definition skin.h:168
@ kWidgetSecondaryDisabled
Definition skin.h:170
@ kOverlayScreen
Definition skin.h:140
@ kTextComponentText
Definition skin.h:148
@ kWidgetSecondary2
Definition skin.h:169
@ kWidgetAccent2
Definition skin.h:172
@ kBody
Definition skin.h:129
vital::Wavetable * getWavetable(int index)
Gets a wavetable object from the engine.
Definition synth_base.cpp:266
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
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
void hidePopup(bool primary)
Definition synth_slider.cpp:640
void showPopup(bool primary)
Definition synth_slider.cpp:635
virtual void mouseWheelMove(const MouseEvent &e, const MouseWheelDetails &wheel) override
Definition synth_slider.cpp:346
Interface for components that need to respond to wavetable loading or transformations.
Definition wavetable_3d.h:89
void setViewSettings(float horizontal_angle, float vertical_angle, float draw_width, float wave_height, float y_offset)
Sets view settings for the 3D display (angles, width, height, offset).
Definition wavetable_3d.cpp:609
void resized() override
Handles component resizing, recalculating layout and scaling.
Definition wavetable_3d.cpp:205
static constexpr float kDefaultWaveHeightPercent
Definition wavetable_3d.h:41
void audioFileLoaded(const File &file) override
Definition wavetable_3d.cpp:687
void destroy(OpenGlWrapper &open_gl) override
Definition wavetable_3d.cpp:566
void init(OpenGlWrapper &open_gl) override
Definition wavetable_3d.cpp:438
bool hasMatchingSystemClipboard()
Definition wavetable_3d.cpp:676
void updateDraggingPosition(int x, int y)
Definition wavetable_3d.cpp:697
void renderWave(OpenGlWrapper &open_gl)
Definition wavetable_3d.cpp:479
void mouseDrag(const MouseEvent &e) override
Definition wavetable_3d.cpp:280
static constexpr int kBackgroundResolution
Definition wavetable_3d.h:48
static constexpr int kExtraShadows
Definition wavetable_3d.h:49
void setRenderType(RenderType render_type)
Definition wavetable_3d.cpp:619
static constexpr float kPositionLineWidthRatio
Definition wavetable_3d.h:43
void setDirty()
Marks the internal state as dirty, forcing a redraw.
Definition wavetable_3d.h:252
void mouseDown(const MouseEvent &e) override
Definition wavetable_3d.cpp:246
static constexpr float kDefaultVerticalAngle
Default angles and scaling parameters for 3D rendering.
Definition wavetable_3d.h:38
static void paint3dBackground(Graphics &g, vital::Wavetable *wavetable, bool active, Colour background_color, Colour wave_color1, Colour wave_color2, float width, float height, float wave_height_percent, float wave_range_x, float frame_range_x, float wave_range_y, float frame_range_y, float start_x, float start_y, float offset_x, float offset_y)
Static helper method for painting the 3D background of the wavetable (all frames) onto a Graphics obj...
Definition wavetable_3d.cpp:50
virtual ~Wavetable3d()
Destructor.
void mouseWheelMove(const MouseEvent &e, const MouseWheelDetails &wheel) override
Definition wavetable_3d.cpp:295
static constexpr float kDefaultDrawWidthPercent
Definition wavetable_3d.h:40
RenderType
Render types for different visualization modes.
Definition wavetable_3d.h:80
@ kFrequencyAmplitudes
Definition wavetable_3d.h:83
@ kWave2d
Definition wavetable_3d.h:82
@ kWave3d
Definition wavetable_3d.h:81
static constexpr float k2dWaveHeightPercent
Definition wavetable_3d.h:50
void respondToMenuCallback(int option)
Definition wavetable_3d.cpp:624
void render(OpenGlWrapper &open_gl, bool animate) override
Definition wavetable_3d.cpp:448
void paintBackground(Graphics &g) override
Definition wavetable_3d.cpp:182
void mouseExit(const MouseEvent &e) override
Definition wavetable_3d.cpp:299
void renderSpectrum(OpenGlWrapper &open_gl)
Definition wavetable_3d.cpp:529
static constexpr int kColorJump
Definition wavetable_3d.h:44
bool isActive()
Definition wavetable_3d.h:217
static void paint3dLine(Graphics &g, vital::Wavetable *wavetable, int index, Colour color, float width, float height, float wave_height_percent, float wave_range_x, float frame_range_x, float wave_range_y, float frame_range_y, float start_x, float start_y, float offset_x, float offset_y)
Static helper method for painting a single 3D line (waveform frame) onto a Graphics object.
Definition wavetable_3d.cpp:16
static constexpr float kDefaultHorizontalAngle
Definition wavetable_3d.h:39
@ kSave
Definition wavetable_3d.h:72
@ kPaste
Definition wavetable_3d.h:70
@ kCopy
Definition wavetable_3d.h:69
@ kLogIn
Definition wavetable_3d.h:75
@ kInit
Definition wavetable_3d.h:71
@ kResynthesizePreset
Definition wavetable_3d.h:74
@ kTextToWavetable
Definition wavetable_3d.h:73
Wavetable3d(int index, const vital::output_map &mono_modulations, const vital::output_map &poly_modulations)
Definition wavetable_3d.cpp:101
A class responsible for creating complete wavetables from groups of wavetable components.
Definition wavetable_creator.h:27
static bool isValidJson(json data)
Checks if a given JSON data represents a valid wavetable creator state.
Definition wavetable_creator.cpp:309
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
@ kNone
Definition wavetable_creator.h:34
@ kVocoded
Apply vocoder-like analysis to extract fundamental cycles.
Definition wavetable_creator.h:36
@ kPitched
Attempts to extract pitch-based cycles from the audio.
Definition wavetable_creator.h:38
force_inline poly_float value() const
Returns the current status value.
Definition synth_module.h:49
DistortionType
Types of distortion/waveshaping used by the oscillator.
Definition synth_oscillator.h:145
@ kNone
No distortion.
Definition synth_oscillator.h:146
@ kNumDistortionTypes
Definition synth_oscillator.h:159
static void setDistortionValues(DistortionType distortion_type, poly_float *values, int num_values, bool spread)
Sets distortion values for an array of poly_float, handling unison spread if necessary.
Definition synth_oscillator.cpp:1014
static bool usesDistortionPhase(DistortionType distortion_type)
Checks if a given distortion type uses a separate distortion_phase (kSync, kQuantize,...
Definition synth_oscillator.cpp:1189
static vital::poly_float getPhaseWindow(DistortionType distortion_type, poly_int phase, poly_int distorted_phase)
Retrieves a window multiplier (for example, half-sin window in formant mode).
Definition synth_oscillator.cpp:1173
SpectralMorph
Types of spectral morph effects that can be applied to the wavetable.
Definition synth_oscillator.h:126
@ kNoSpectralMorph
No spectral morph effect.
Definition synth_oscillator.h:127
@ kNumSpectralMorphTypes
Definition synth_oscillator.h:139
static void runSpectralMorph(SpectralMorph morph_type, float morph_amount, const Wavetable::WavetableData *wavetable_data, int wavetable_index, poly_float *dest, FourierTransform *transform)
Applies a spectral morph operation (e.g., vocode, smear) directly on a buffer.
Definition synth_oscillator.cpp:1112
static constexpr int kSpectralBufferSize
Size of spectral buffer for Fourier transforms.
Definition synth_oscillator.h:207
static void setSpectralMorphValues(SpectralMorph spectral_morph, poly_float *values, int num_values, bool spread)
Sets spectral morph values for an array of poly_float, handling unison spread if necessary.
Definition synth_oscillator.cpp:1070
static poly_float interpolate(const mono_float *buffer, const poly_int indices)
Performs linear interpolation on a single wave buffer.
Definition synth_oscillator.cpp:1185
static vital::poly_int adjustPhase(DistortionType distortion_type, poly_int phase, poly_float distortion_amount, poly_int distortion_phase)
Adjusts phase for sync, formant, quantize, etc.
Definition synth_oscillator.cpp:1154
std::complex< float > frequency_domain[kWaveformSize]
The frequency-domain representation (complex spectrum).
Definition wave_frame.h:125
void toFrequencyDomain()
Converts the currently loaded time-domain data into frequency-domain representation.
Definition wave_frame.cpp:64
mono_float time_domain[2 *kWaveformSize]
The time-domain data, extended buffer size for FFT alignment.
Definition wave_frame.h:124
A class representing a wavetable, holding multiple frames of waveforms and their frequency-domain rep...
Definition wavetable.h:20
static constexpr int kFrequencyBins
Number of frequency bins (equal to number of wave bits in a frame).
Definition wavetable.h:23
force_inline const WavetableData * getAllData()
Get a pointer to the current WavetableData.
Definition wavetable.h:174
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
nlohmann::json json
Definition line_generator.h:7
const poly_mask kFullMask
A mask covering all lanes of a poly_float vector.
Definition synth_constants.h:257
force_inline poly_float exp2(poly_float exponent)
Approximates 2^exponent for poly_float values using a polynomial approximation.
Definition futils.h:45
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 magnitudeToDb(poly_float value)
Converts a magnitude value to decibels (vectorized).
Definition poly_utils.h:144
force_inline poly_int toInt(poly_float floats)
Casts a poly_float to poly_int by truncation.
Definition poly_utils.h:748
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
std::map< std::string, Output * > output_map
Maps parameter names to Output pointers, representing output signals from various modules.
Definition synth_types.h:229
constexpr int kNumOscillatorWaveFrames
Number of wave frames in each oscillator’s wavetable.
Definition synth_constants.h:19
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
int num_frames
The number of frames in the wavetable.
Definition wavetable.h:51
Represents a vector of floating-point values using SIMD instructions.
Definition poly_values.h:600
static force_inline mask_simd_type vector_call equal(simd_type one, simd_type two)
Compares two SIMD float registers for equality, element-wise.
Definition poly_values.h:954
Represents a vector of integer values using SIMD instructions.
Definition poly_values.h:56
static force_inline simd_type vector_call equal(simd_type one, simd_type two)
Compares two SIMD integer registers for equality, element-wise.
Definition poly_values.h:291
Provides various utility functions, classes, and constants for audio, math, and general-purpose opera...
Declares the Wavetable3d class, which provides a 3D and 2D visualization for wavetables.