12 constexpr float kDefaultModulationRatio = 0.25f;
13 constexpr float kModSourceMeterWidth = 0.0018f;
14 constexpr float kModSourceMeterBuffer = 0.002f;
15 constexpr float kModSourceMinRadius = 0.005f;
16 constexpr float kModSmoothDecay = 0.25f;
18 bool showingInParents(Component* component) {
19 if (component ==
nullptr || component->getParentComponent() ==
nullptr)
22 return component->isVisible() && showingInParents(component->getParentComponent());
29 num_sliders_(0), amount_quad_(
Shaders::kRingFragment) {
31 setTriggeredOnMouseDown(
true);
32 setMouseClickGrabsKeyboardFocus(
false);
38 float height_width_ratio = getHeight() * 1.0f / getWidth();
41 while (columns * (
int)(height_width_ratio * columns) < num_sliders)
46 void setSliders(std::vector<ModulationAmountKnob*> sliders) {
48 for (
int i = 0; i < sliders.size(); ++i)
50 num_sliders_ =
static_cast<int>(sliders_.size());
53 std::vector<ModulationAmountKnob*>
getSliders() {
return sliders_; }
56 int num_sliders = num_sliders_;
58 float width = getWidth();
59 float height = getHeight();
62 float cell_width = width / columns;
63 int rows = (num_sliders + columns - 1) / columns;
64 int y_offset = (height - (rows * cell_width)) / 2;
65 float gl_width = 2.0f * cell_width / width;
66 float gl_height = 2.0f * cell_width / height;
70 for (
int i = 0; i < num_sliders; ++i) {
71 float x = column * cell_width;
72 float y = height - y_offset - (row + 1) * cell_width;
75 amount_quad_.
setAltColor(colors_[i].withMultipliedAlpha(0.5f));
76 amount_quad_.
setQuad(0, 2.0f * x / width - 1.0f, 1.0f - 2.0f * y / height - gl_height, gl_width, gl_height);
77 amount_quad_.
render(open_gl, animate);
80 if (column >= columns) {
88 std::vector<ModulationAmountKnob*> sliders_;
100 size_multiple_(1.0f),
101 active_(false), rectangle_(false), rotary_(true) {
102 setName(source->getName());
112 size_multiple_ = multiple;
117 static constexpr float kBufferPercent = 0.4f;
119 float width = getWidth();
120 float height = getHeight();
122 if (!rectangle_ && rotary_) {
125 float x = (width - rotary_width) / 2.0f;
126 float y = offset + (height - rotary_width) / 2.0f;
127 return Rectangle<float>(x, y, rotary_width, rotary_width);
131 return getLocalBounds().toFloat();
133 if (destination_slider_->getSliderStyle() == Slider::LinearBar) {
136 y -= 2.0f * glow_height * kBufferPercent;
137 glow_height += 4.0f * kBufferPercent * glow_height;
139 return Rectangle<float>(margin_, y, width - 2 * margin_, glow_height);
144 x -= 2.0f * glow_width * kBufferPercent;
145 glow_width += 4.0f * kBufferPercent * glow_width;
146 return Rectangle<float>(x, margin_, glow_width, height - 2 * margin_);
160 Component* viewport_container_;
164 float size_multiple_;
173 color_component_(nullptr), index_(index) {
178 draw_background_ =
false;
184 setDoubleClickReturnValue(
false, 0.0f);
185 setWantsKeyboardFocus(
false);
188 current_modulator_ =
false;
192 if (e.mods.isMiddleButtonDown())
195 if (e.mods.isPopupMenu()) {
217 auto cancel = [=]() {
219 listener->menuFinished(
this);
224 listener->mouseDown(
this);
228 MouseInputSource source = e.source;
230 if (source.isMouse() && source.canDoUnboundedMovement()) {
233 source.enableUnboundedMouseMovement(
true);
234 mouse_down_position_ = e.getScreenPosition();
236 listener->beginModulationEdit(
this);
242 if (!e.mods.isPopupMenu()) {
245 MouseInputSource source = e.source;
246 if (source.isMouse() && source.canDoUnboundedMovement()) {
247 source.showMouseCursor(MouseCursor::NormalCursor);
248 source.enableUnboundedMouseMovement(
false);
249 if (getScreenBounds().contains(e.getScreenPosition()))
251 source.setScreenPosition(mouse_down_position_.toFloat());
259 listener->endModulationEdit(
this);
265void ModulationAmountKnob::toggleBypass() {
267 for (Listener* listener : listeners_)
268 listener->setModulationBypass(
this, bypass_);
274 for (
Listener* listener : listeners_)
275 listener->disconnectModulation(
this);
280 bipolar_ = !bipolar_;
281 for (
Listener* listener : listeners_)
282 listener->setModulationBipolar(
this, bipolar_);
286 for (
Listener* listener : listeners_)
287 listener->setModulationStereo(
this, stereo_);
294 listener->menuFinished(
this);
299 if (visible == showing_)
304 setAlpha((showing_ || hovering_) ? 1.0f : 0.0f);
315 if (current_modulator_ == current)
319 current_modulator_ = current;
323 color_component_ = component;
326 if (color_component_)
331 if (color_component_)
342 std::map<std::string, ModulationButton*> modulation_buttons,
343 std::map<std::string, SynthSlider*> sliders,
346 drag_quad_(
Shaders::kRingFragment),
347 current_modulator_quad_(
Shaders::kRoundedRectangleBorderFragment),
348 editing_rotary_amount_quad_(
Shaders::kRotaryModulationFragment),
349 editing_linear_amount_quad_(
Shaders::kLinearModulationFragment),
350 modifying_(false), dragging_(false), changing_hover_modulation_(false),
351 current_modulator_(nullptr) {
352 current_modulator_quad_.
setQuad(0, -1.0f, -1.0f, 2.0f, 2.0f);
355 editing_rotary_amount_quad_.
setActive(
false);
356 editing_rotary_amount_quad_.
setQuad(0, -1.0f, -1.0f, 2.0f, 2.0f);
358 editing_linear_amount_quad_.
setActive(
false);
359 editing_linear_amount_quad_.
setQuad(0, -1.0f, -1.0f, 2.0f, 2.0f);
361 modulation_expansion_box_.setVisible(
false);
362 modulation_expansion_box_.setWantsKeyboardFocus(
true);
364 modulation_expansion_box_.setAlwaysOnTop(
true);
368 last_milliseconds_ = Time::currentTimeMillis();
369 current_source_ =
nullptr;
370 current_expanded_modulation_ =
nullptr;
371 temporarily_set_destination_ =
nullptr;
372 temporarily_set_synth_slider_ =
nullptr;
373 temporarily_set_hover_slider_ =
nullptr;
374 temporarily_set_bipolar_ =
false;
375 num_voices_readout_ =
nullptr;
377 modulation_buttons_ = modulation_buttons;
378 for (
auto& modulation_button : modulation_buttons_) {
379 modulation_button.second->addListener(
this);
381 modulation_callout_buttons_[modulation_button.first] = std::make_unique<ExpandModulationButton>();
382 addChildComponent(modulation_callout_buttons_[modulation_button.first].get());
383 addOpenGlComponent(modulation_callout_buttons_[modulation_button.first]->getGlComponent());
384 modulation_callout_buttons_[modulation_button.first]->addListener(
this);
387 modulation_source_meters_ = std::make_unique<BarRenderer>(modulation_buttons.size());
388 modulation_source_meters_->setBarWidth(0.0f);
389 addAndMakeVisible(modulation_source_meters_.get());
390 modulation_source_meters_->setInterceptsMouseClicks(
false,
false);
392 setInterceptsMouseClicks(
false,
true);
394 modulation_destinations_ = std::make_unique<Component>();
395 modulation_destinations_->setInterceptsMouseClicks(
false,
true);
397 slider_model_lookup_ = sliders;
398 std::map<Viewport*, int> num_rotary_meters;
399 std::map<Viewport*, int> num_linear_meters;
400 for (
auto& slider : slider_model_lookup_) {
401 if (mono_modulations[slider.first]) {
402 bool rotary = slider.second->isRotary() && !slider.second->isTextOrCurve();
403 Viewport* viewport = slider.second->findParentComponentOfClass<Viewport>();
405 num_rotary_meters[viewport] = num_rotary_meters[viewport] + 1;
407 num_linear_meters[viewport] = num_linear_meters[viewport] + 1;
411 for (
auto& rotary_meters : num_rotary_meters) {
412 rotary_destinations_[rotary_meters.first] = std::make_unique<OpenGlMultiQuad>(rotary_meters.second,
414 rotary_destinations_[rotary_meters.first]->setTargetComponent(
this);
415 rotary_destinations_[rotary_meters.first]->setScissorComponent(rotary_meters.first);
416 rotary_destinations_[rotary_meters.first]->setAlpha(0.0f,
true);
418 rotary_meters_[rotary_meters.first] = std::make_unique<OpenGlMultiQuad>(rotary_meters.second,
420 rotary_meters_[rotary_meters.first]->setTargetComponent(
this);
421 rotary_meters_[rotary_meters.first]->setScissorComponent(rotary_meters.first);
423 for (
auto& linear_meters : num_linear_meters) {
424 linear_destinations_[linear_meters.first] = std::make_unique<OpenGlMultiQuad>(linear_meters.second,
426 linear_destinations_[linear_meters.first]->setTargetComponent(
this);
427 linear_destinations_[linear_meters.first]->setScissorComponent(linear_meters.first);
428 linear_destinations_[linear_meters.first]->setAlpha(0.0f,
true);
430 linear_meters_[linear_meters.first] = std::make_unique<OpenGlMultiQuad>(linear_meters.second,
432 linear_meters_[linear_meters.first]->setTargetComponent(
this);
433 linear_meters_[linear_meters.first]->setScissorComponent(linear_meters.first);
436 for (
auto& slider : slider_model_lookup_) {
437 std::string name = slider.first;
440 if (mono_total ==
nullptr)
443 bool rotary = slider.second->isRotary() && !slider.second->isTextOrCurve();
444 Viewport* viewport = slider.second->findParentComponentOfClass<Viewport>();
448 int index = num_rotary_meters[viewport] - 1;
449 num_rotary_meters[viewport] = index;
453 int index = num_linear_meters[viewport] - 1;
454 num_linear_meters[viewport] = index;
458 slider.second->addSliderListener(
this);
462 addChildComponent(modulation_destinations_.get());
465 std::string name =
"modulation_" + std::to_string(i + 1) +
"_amount";
466 modulation_amount_sliders_[i] = std::make_unique<ModulationAmountKnob>(name, i);
467 modulation_amount_sliders_[i]->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
468 addSlider(modulation_amount_sliders_[i].get());
469 modulation_amount_sliders_[i]->addSliderListener(
this);
470 modulation_amount_sliders_[i]->addModulationAmountListener(
this);
471 modulation_amount_lookup_[name] = modulation_amount_sliders_[i].get();
473 modulation_hover_sliders_[i] = std::make_unique<ModulationAmountKnob>(name, i);
474 modulation_hover_sliders_[i]->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
475 addSlider(modulation_hover_sliders_[i].get());
476 modulation_hover_sliders_[i]->setAlpha(0.0f,
true);
477 modulation_hover_sliders_[i]->addSliderListener(
this);
478 modulation_hover_sliders_[i]->addModulationAmountListener(
this);
479 modulation_hover_sliders_[i]->setDrawWhenNotVisible(
true);
481 selected_modulation_sliders_[i] = std::make_unique<ModulationAmountKnob>(name, i);
482 selected_modulation_sliders_[i]->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
483 addSlider(selected_modulation_sliders_[i].get());
484 selected_modulation_sliders_[i]->setAlpha(0.0f,
true);
485 selected_modulation_sliders_[i]->addSliderListener(
this);
486 selected_modulation_sliders_[i]->addModulationAmountListener(
this);
487 selected_modulation_sliders_[i]->setDrawWhenNotVisible(
true);
494 std::string name = slider->getName().toStdString();
495 std::unique_ptr<ModulationMeter> meter = std::make_unique<ModulationMeter>(mono_total, poly_total,
496 slider, quads, index);
497 addChildComponent(meter.get());
498 meter->setName(name);
499 meter->setBounds(getLocalArea(slider, slider->getLocalBounds()));
500 meter_lookup_[name] = std::move(meter);
504 std::unique_ptr<ModulationDestination> destination = std::make_unique<ModulationDestination>(slider);
505 modulation_destinations_->addAndMakeVisible(destination.get());
507 destination->setRotary(slider->isRotary());
510 destination_lookup_[name] = destination.get();
511 all_destinations_.push_back(std::move(destination));
522 editing_rotary_amount_quad_.
setColor(meter_center_color);
523 editing_rotary_amount_quad_.
setAltColor(meter_center_color);
524 editing_rotary_amount_quad_.
setModColor(meter_center_color);
525 editing_linear_amount_quad_.
setColor(meter_center_color);
526 editing_linear_amount_quad_.
setAltColor(meter_center_color);
527 editing_linear_amount_quad_.
setModColor(meter_center_color);
529 for (
auto& rotary_meter_group : rotary_meters_) {
530 rotary_meter_group.second->setThickness(meter_thickness);
531 rotary_meter_group.second->setModColor(meter_center_color);
532 rotary_meter_group.second->setColor(meter_left_color);
533 rotary_meter_group.second->setAltColor(meter_right_color);
536 for (
auto& linear_meter_group : linear_meters_) {
537 linear_meter_group.second->setModColor(meter_center_color);
538 linear_meter_group.second->setColor(meter_left_color);
539 linear_meter_group.second->setAltColor(meter_right_color);
542 modulation_destinations_->setBounds(getLocalBounds());
543 modulation_source_meters_->setBounds(getLocalBounds());
548 current_modulator_quad_.
setColor(meter_control);
557 for (
auto& rotary_destination_group : rotary_destinations_)
558 rotary_destination_group.second->setColor(lighten_screen);
560 for (
auto& linear_destination_group : linear_destinations_) {
561 linear_destination_group.second->setColor(lighten_screen);
562 linear_destination_group.second->setRounding(rounding);
567 positionModulationAmountSliders();
571 SynthSection::parentHierarchyChanged();
572 if (!modulation_source_readouts_.empty())
576 if (parent ==
nullptr)
579 for (
auto& mod_button : modulation_buttons_) {
581 smooth_mod_values_[mod_button.first] = 0.0f;
582 active_mod_values_[mod_button.first] =
false;
591 for (
auto& meter : meter_lookup_) {
592 SynthSlider* model = slider_model_lookup_[meter.first];
598 meter.second->setModulated(num_modulations);
599 meter.second->setVisible(num_modulations);
605 std::string slider_name = slider->getName().toStdString();
606 std::string source_name = current_modulator_->getName().toStdString();
610 modulation_buttons_[source_name]->repaint();
614 std::string slider_name = slider->getName().toStdString();
615 std::string source_name = current_modulator_->getName().toStdString();
618 modulation_buttons_[source_name]->repaint();
622 if (current_modulator_ ==
nullptr)
632 for (
auto& button : modulation_buttons_)
633 button.second->setActiveModulation(button.second == source);
635 current_modulator_ = source;
636 for (
auto& hover_slider : modulation_hover_sliders_)
637 hover_slider->makeVisible(
false);
638 makeCurrentModulatorAmountsVisible();
640 positionModulationAmountSliders();
645 positionModulationAmountSliders();
649 makeCurrentModulatorAmountsVisible();
667 mouse_drag_position_ = getLocalPoint(source, e.getPosition());
668 current_source_ = source;
670 Rectangle<int> global_bounds = getLocalArea(current_source_, current_source_->getLocalBounds());
671 Point<int> global_start = global_bounds.getCentre();
672 mouse_drag_start_ = global_start;
673 modulation_destinations_->setVisible(
true);
676 std::map<Viewport*, int> rotary_indices;
677 std::map<Viewport*, int> linear_indices;
678 for (
auto& rotary_destination_group : rotary_destinations_)
679 rotary_indices[rotary_destination_group.first] = 0;
681 for (
auto& linear_destination_group : linear_destinations_)
682 linear_indices[linear_destination_group.first] = 0;
685 std::string source_name = source->getName().toStdString();
686 std::set<std::string> active_destinations;
689 active_destinations.insert(connection->destination_name);
691 for (
auto& destination : destination_lookup_) {
692 SynthSlider* model = slider_model_lookup_[destination.first];
694 current_source_->getName() != String(destination.first);
695 Viewport* viewport = model->findParentComponentOfClass<Viewport>();
696 destination.second->setVisible(should_show);
697 destination.second->
setActive(active_destinations.count(destination.first));
698 destination.second->setMargin(widget_margin);
700 Point<int> position = getLocalPoint(model, Point<int>(0, 0));
701 Rectangle<int> slider_bounds = model->getLocalBounds() + position;
702 destination.second->setBounds(slider_bounds);
706 Rectangle<int> bounds = destination.second->getFillBounds().toNearestInt() + position;
708 Point<int> top_left = getLocalPoint(extra_target, Point<int>(0, 0));
709 Rectangle<int> extra_bounds(top_left.x, top_left.y, extra_target->getWidth(), extra_target->getHeight());
710 bounds = bounds.getUnion(extra_bounds);
711 destination.second->setBounds(bounds);
715 if (destination.second->isRotary()) {
716 destination.second->setIndex(rotary_indices[viewport]);
717 rotary_indices[viewport] = rotary_indices[viewport] + 1;
720 destination.second->setIndex(linear_indices[viewport]);
721 linear_indices[viewport] = linear_indices[viewport] + 1;
723 setDestinationQuadBounds(destination.second);
727 for (
auto& index_count : rotary_indices) {
728 rotary_destinations_[index_count.first]->setNumQuads(index_count.second);
729 rotary_destinations_[index_count.first]->setAlpha(index_count.second > 0 ? 1.0f : 0.0f);
732 for (
auto& index_count : linear_indices) {
733 linear_destinations_[index_count.first]->setNumQuads(index_count.second);
734 linear_destinations_[index_count.first]->setAlpha(index_count.second > 0 ? 1.0f : 0.0f);
739 Point<float> top_left = destination->getBounds().getTopLeft().toFloat();
740 Rectangle<float> draw_bounds = destination->getLocalBounds().toFloat() + top_left;
743 float global_width = getWidth();
744 float global_height = getHeight();
745 float x = 2.0f * draw_bounds.getX() / global_width - 1.0f;
746 float y = 1.0f - 2.0f * draw_bounds.getBottom() / global_height;
747 float width = 2.0f * draw_bounds.getWidth() / global_width;
748 float height = 2.0f * draw_bounds.getHeight() / global_height;
750 float offset = destination->
isActive() ? -2.0f : 0.0f;
752 Viewport* viewport = destination->
getDestinationSlider()->findParentComponentOfClass<Viewport>();
754 rotary_destinations_[viewport]->setQuad(destination->
getIndex(), x + offset, y, width, height);
756 linear_destinations_[viewport]->setQuad(destination->
getIndex(), x + offset, y, width, height);
764 std::string source_name = current_modulator_->getName().toStdString();
766 if (connection ==
nullptr) {
767 float value = hover_slider->getValue() * 0.5f;
768 hover_slider->setValue(0.0f, sendNotificationSync);
769 temporarily_set_hover_slider_ = hover_slider;
782 if (component && current_modulator_ && destination_lookup_.count(component->getName().toStdString())) {
783 std::string name = component->getName().toStdString();
785 if (
getConnection(current_modulator_->getName().toStdString(), name) ==
nullptr) {
789 float percent = slider->valueToProportionOfLength(slider->getValue());
790 float modulation_amount = 1.0f - percent;
792 modulation_amount = std::min(modulation_amount, percent) * 2.0f;
793 modulation_amount = std::max(modulation_amount, kDefaultModulationRatio);
795 temporarily_set_destination_ = destination;
796 temporarily_set_synth_slider_ = slider_model_lookup_[name];
798 std::string source_name = current_modulator_->getName().toStdString();
802 setDestinationQuadBounds(destination);
808 if (connection->source_name == source_name && connection->destination_name == name) {
809 int index = connection->modulation_processor->index();
810 showModulationAmountOverlay(selected_modulation_sliders_[index].get());
815 makeModulationsVisible(slider,
true);
823 if (current_modulator_ ==
nullptr || component != temporarily_set_destination_ || component ==
nullptr)
826 std::string source_name = current_modulator_->getName().toStdString();
827 std::string name = component->getName().toStdString();
831 float percent = slider->valueToProportionOfLength(slider->getValue());
832 float modulation_amount = 1.0f - percent;
834 modulation_amount = std::min(modulation_amount, percent) * 2.0f;
835 modulation_amount = std::max(modulation_amount, kDefaultModulationRatio);
839 temporarily_set_bipolar_ = bipolar;
840 showModulationAmountOverlay(selected_modulation_sliders_[index].get());
844 if (temporarily_set_destination_ && current_modulator_) {
845 temporarily_set_destination_->
setActive(
false);
846 setDestinationQuadBounds(temporarily_set_destination_);
847 temporarily_set_destination_ =
nullptr;
848 std::string source_name = current_modulator_->getName().toStdString();
849 removeModulation(source_name, temporarily_set_synth_slider_->getName().toStdString());
850 temporarily_set_synth_slider_ =
nullptr;
852 hideModulationAmountOverlay();
857 if (temporarily_set_hover_slider_ && current_modulator_) {
858 std::string name = temporarily_set_hover_slider_->
getOriginalName().toStdString();
860 std::string source_name = current_modulator_->getName().toStdString();
862 temporarily_set_hover_slider_ =
nullptr;
870 mouse_drag_position_ = getLocalPoint(current_source_, e.getPosition());
871 Component* component = getComponentAt(mouse_drag_position_.x, mouse_drag_position_.y);
874 if (modulation_amount_sliders_[i].get() == component)
875 hover_knob = modulation_amount_sliders_[i].get();
876 else if (modulation_hover_sliders_[i].get() == component)
877 hover_knob = modulation_hover_sliders_[i].get();
878 else if (selected_modulation_sliders_[i].get() == component)
879 hover_knob = selected_modulation_sliders_[i].get();
885 bool bipolar = e.mods.isAnyModifierKeyDown();
886 if (temporarily_set_destination_ && temporarily_set_destination_ != component)
888 if (temporarily_set_hover_slider_ && temporarily_set_hover_slider_ != component)
891 else if (temporarily_set_synth_slider_ && temporarily_set_bipolar_ != bipolar)
901 if (!dragging_ || current_modulator_ ==
nullptr || temporarily_set_destination_ ==
nullptr)
904 MouseEvent new_event(e.source, e.position, ModifierKeys(), e.pressure, e.orientation, e.rotation,
905 e.tiltX, e.tiltY, e.eventComponent, e.originalComponent, e.eventTime, e.mouseDownPosition,
906 e.mouseDownTime, e.getNumberOfClicks(), e.mouseWasDraggedSinceMouseDown());
907 std::string source_name = current_modulator_->getName().toStdString();
908 std::string destination_name = temporarily_set_destination_->getName().toStdString();
911 selected_modulation_sliders_[index]->mouseWheelMove(new_event, wheel);
915 temporarily_set_destination_ =
nullptr;
916 temporarily_set_synth_slider_ =
nullptr;
917 temporarily_set_hover_slider_ =
nullptr;
921 positionModulationAmountSliders();
922 current_source_ =
nullptr;
923 for (
auto& rotary_destination_group : rotary_destinations_)
924 rotary_destination_group.second->setAlpha(0.0f);
926 for (
auto& linear_destination_group : linear_destinations_)
927 linear_destination_group.second->setAlpha(0.0f);
929 modulation_destinations_->setVisible(
false);
931 hideModulationAmountOverlay();
940 if (current_modulator_) {
941 for (
auto& selected_slider : selected_modulation_sliders_)
942 selected_slider->makeVisible(
false);
944 current_modulator_ =
nullptr;
960 float value = modulation_knob->getValue();
961 bool bipolar = modulation_knob->
isBipolar();
962 bool stereo = modulation_knob->
isStereo();
963 bool bypass = modulation_knob->
isBypass();
965 int index = modulation_knob->
index();
966 modulation_amount_sliders_[index]->setBipolar(bipolar);
967 modulation_amount_sliders_[index]->setStereo(stereo);
968 modulation_amount_sliders_[index]->setBypass(bypass);
969 modulation_hover_sliders_[index]->setBipolar(bipolar);
970 modulation_hover_sliders_[index]->setStereo(stereo);
971 modulation_hover_sliders_[index]->setBypass(bypass);
972 selected_modulation_sliders_[index]->setBipolar(bipolar);
973 selected_modulation_sliders_[index]->setStereo(stereo);
974 selected_modulation_sliders_[index]->setBypass(bypass);
992 drag_quad_.
init(open_gl);
993 modulation_expansion_box_.
init(open_gl);
994 modulation_source_meters_->init(open_gl);
995 for (
auto& rotary_destination_group : rotary_destinations_)
996 rotary_destination_group.second->init(open_gl);
998 for (
auto& linear_destination_group : linear_destinations_)
999 linear_destination_group.second->init(open_gl);
1001 for (
auto& rotary_meter_group : rotary_meters_)
1002 rotary_meter_group.second->init(open_gl);
1004 for (
auto& linear_meter_group : linear_meters_)
1005 linear_meter_group.second->init(open_gl);
1011 for (
auto& rotary_destination_group : rotary_destinations_)
1012 rotary_destination_group.second->render(open_gl,
true);
1014 for (
auto& linear_destination_group : linear_destinations_)
1015 linear_destination_group.second->render(open_gl,
true);
1019 Component* component = current_modulator_;
1022 current_modulator_quad_.
setAlpha(1.0f);
1025 current_modulator_quad_.
setAlpha(0.0f);
1027 current_modulator_quad_.
setThickness(dragging_ ? 2.6f : 1.0f);
1028 current_modulator_quad_.
render(open_gl,
true);
1032 static constexpr float kRadiusWidthRatio = 0.022f;
1033 static constexpr float kThicknessWidthRatio = 0.003f;
1034 if (current_source_ ==
nullptr || temporarily_set_destination_ || temporarily_set_hover_slider_)
1037 vital::poly_float mod_percent = modulation_source_readouts_[current_source_->getName().toStdString()]->value();
1038 float draw_radius = kRadiusWidthRatio * getWidth();
1039 float radius_x = draw_radius / getWidth();
1040 float radius_y = draw_radius / getHeight();
1041 float x = mouse_drag_position_.x * 2.0f / getWidth() - 1.0f;
1042 float y = -mouse_drag_position_.y * 2.0f / getHeight() + 1.0f;
1046 drag_quad_.
setAltColor(widget_background.interpolatedWith(control, mod_percent[0]));
1047 drag_quad_.
setQuad(0, x - radius_x, y - radius_y, 2.0f * radius_x, 2.0f * radius_y);
1048 drag_quad_.
setThickness(getWidth() * kThicknessWidthRatio);
1049 drag_quad_.
render(open_gl,
true);
1057 for (
auto& callout_button : modulation_callout_buttons_) {
1058 if (callout_button.second->isVisible())
1059 callout_button.second->renderSliderQuads(open_gl,
animate);
1068 modulation_source_meters_->setAdditiveBlending(second_color.getBrightness() > 0.5f);
1069 modulation_source_meters_->setColor(second_color);
1071 modulation_source_meters_->setAdditiveBlending(first_color.getBrightness() > 0.5f);
1072 modulation_source_meters_->setColor(first_color);
1089 if (num_voices_readout_)
1090 num_voices = std::max<float>(0.0f, num_voices_readout_->
value()[0]);
1091 for (
auto& meter : meter_lookup_) {
1092 SynthSlider* slider = slider_model_lookup_[meter.first];
1093 bool show = meter.second->isModulated() && showingInParents(slider) && slider->
isActive();
1094 meter.second->setActive(show);
1096 meter.second->updateDrawing(num_voices);
1100 for (
auto& rotary_meter_group : rotary_meters_)
1101 rotary_meter_group.second->render(open_gl,
animate);
1103 for (
auto& linear_meter_group : linear_meters_)
1104 linear_meter_group.second->render(open_gl,
animate);
1109 float width = getWidth();
1110 float height = getHeight();
1111 for (
auto& mod_readout : modulation_source_readouts_) {
1113 float readout_value = mod_readout.second->value()[index];
1116 if (!active_mod_values_[mod_readout.first] && !mod_readout.second->isClearValue(readout_value))
1117 smooth_mod_values_[mod_readout.first].set(index, clamped_value);
1118 float smooth_value = smooth_mod_values_[mod_readout.first][index];
1120 Rectangle<int> bounds = getLocalArea(button, button->
getMeterBounds());
1121 float left = 2.0f * ((bounds.getX() - 1.0f) / width) - 1.0f + kModSourceMeterBuffer;
1122 float w = 2.0f * bounds.getWidth() / width - 2.0f * kModSourceMeterBuffer;
1123 float h = 2.0f * bounds.getHeight() / height - 2.0f * kModSourceMeterBuffer;
1124 float y = 1.0f - 2.0f * bounds.getY() / height - kModSourceMeterBuffer;
1125 float y_center = y - h * (1.0f - clamped_value);
1126 float smooth_y_center = y - h * (1.0f - smooth_value);
1128 float top = std::min(y_center, smooth_y_center) - kModSourceMinRadius;
1129 float bottom = std::max(y_center, smooth_y_center) + kModSourceMinRadius;
1132 if (w <= 0.0f || mod_readout.second->isClearValue(readout_value) || !showingInParents(button) || !active) {
1138 modulation_source_meters_->positionBar(i, left, top, w, bottom - top);
1143 modulation_source_meters_->render(open_gl,
true);
1147 static constexpr float kTimeDecayScale = 60.0f;
1148 long long current_milliseconds = Time::currentTimeMillis();
1149 long long delta_milliseconds = current_milliseconds - last_milliseconds_;
1150 last_milliseconds_ = current_milliseconds;
1152 float seconds = delta_milliseconds / 1000.0f;
1153 float decay = std::max(std::min(kModSmoothDecay * seconds * kTimeDecayScale, 1.0f), 0.0f);
1155 for (
auto& mod_readout : modulation_source_readouts_) {
1159 bool active = !mod_readout.second->isClearValue(readout_value);
1160 active_mod_values_[mod_readout.first] = active;
1170 modulation_expansion_box_.
destroy(open_gl);
1171 modulation_source_meters_->destroy(open_gl);
1172 for (
auto& rotary_destination_group : rotary_destinations_)
1173 rotary_destination_group.second->destroy(open_gl);
1175 for (
auto& linear_destination_group : linear_destinations_)
1176 linear_destination_group.second->destroy(open_gl);
1178 for (
auto& rotary_meter_group : rotary_meters_)
1179 rotary_meter_group.second->destroy(open_gl);
1181 for (
auto& linear_meter_group : linear_meters_)
1182 linear_meter_group.second->destroy(open_gl);
1187 if (connection ==
nullptr || meter_lookup_.count(connection->
destination_name) == 0)
1201 editing_rotary_amount_quad_.
setAlpha(1.0f);
1202 editing_rotary_amount_quad_.
setActive(
true);
1210 editing_linear_amount_quad_.
setAlpha(1.0f);
1211 editing_linear_amount_quad_.
setActive(
true);
1215void ModulationManager::hideModulationAmountOverlay() {
1216 if (changing_hover_modulation_)
1219 editing_rotary_amount_quad_.
setAlpha(0.0f);
1220 editing_linear_amount_quad_.
setAlpha(0.0f);
1224 if (changing_hover_modulation_)
1227 if (!enteringHoverValue())
1228 makeModulationsVisible(slider,
true);
1232 showModulationAmountOverlay(amount_knob);
1234 hideModulationAmountOverlay();
1238 hideModulationAmountOverlay();
1242 if (current_modulator_ && current_modulator_->isVisible())
1243 current_modulator_->grabKeyboardFocus();
1249 SynthSlider* slider = slider_model_lookup_[destination];
1250 if (current_modulator_)
1251 makeCurrentModulatorAmountsVisible();
1253 makeModulationsVisible(slider, slider->isShowing());
1255 if (parent ==
nullptr)
1258 if (meter_lookup_.count(destination) == 0)
1262 meter_lookup_[destination]->setModulated(num_modulations);
1263 meter_lookup_[destination]->setVisible(num_modulations);
1281 return amount_knob->
index();
1290 while (aux_connections_to_from_.count(index))
1291 index = aux_connections_to_from_[index];
1298 if (parent ==
nullptr)
1306 if (parent ==
nullptr)
1319 for (
auto& amount_knob : modulation_hover_sliders_) {
1320 if (slider == amount_knob.get())
1324 if (modulation_expansion_box_.isVisible())
1332 hideModulationAmountOverlay();
1333 makeModulationsVisible(slider,
true);
1338 if (current_modulator_ && current_modulator_->isVisible())
1339 current_modulator_->grabKeyboardFocus();
1343 changing_hover_modulation_ =
false;
1349 if (current_modulator_ && current_modulator_->isVisible())
1350 current_modulator_->grabKeyboardFocus();
1354 changing_hover_modulation_ =
true;
1358 changing_hover_modulation_ =
false;
1363 if (amount_knob ==
nullptr)
1366 float value = slider->getValue();
1369 float scaled_value = value * scale;
1370 while (aux_connections_to_from_.count(index))
1371 index = aux_connections_to_from_[index];
1379 showModulationAmountOverlay(amount_knob);
1385 for (
auto& callout_button : modulation_callout_buttons_) {
1386 if (button == callout_button.second.get()) {
1387 bool new_button = button != current_expanded_modulation_;
1388 hideModulationAmountCallout();
1390 showModulationAmountCallout(callout_button.first);
1400 if (parent ==
nullptr || source.empty() || destination.empty())
1410 if (parent ==
nullptr || source.empty() || destination.empty())
1414 if (connection ==
nullptr) {
1415 positionModulationAmountSliders();
1420 if (aux_connections_from_to_.count(index)) {
1422 int dest_index = aux_connections_from_to_[index];
1425 float reset_value = current_value == 0.0f ? 1.0f : -current_value;
1426 modulation_amount->setValue(reset_value, dontSendNotification);
1427 modulation_amount->setValue(current_value * 2.0f, sendNotificationSync);
1436 positionModulationAmountSliders();
1440 modulation_amount_sliders_[index]->setValue(value, dontSendNotification);
1441 modulation_hover_sliders_[index]->setValue(value, dontSendNotification);
1442 selected_modulation_sliders_[index]->setValue(value, dontSendNotification);
1443 modulation_amount_sliders_[index]->redoImage();
1444 modulation_hover_sliders_[index]->redoImage();
1445 selected_modulation_sliders_[index]->redoImage();
1449 modulation_amount_sliders_[index]->setBipolar(bipolar);
1450 modulation_hover_sliders_[index]->setBipolar(bipolar);
1451 selected_modulation_sliders_[index]->setBipolar(bipolar);
1456 float from_value = value;
1457 int from_index = index;
1458 while (aux_connections_from_to_.count(from_index)) {
1459 from_index = aux_connections_from_to_[from_index];
1464 float to_value = value;
1465 int to_index = index;
1466 while (aux_connections_to_from_.count(to_index)) {
1467 to_index = aux_connections_to_from_[to_index];
1476 int end_index = index;
1478 while (aux_connections_from_to_.count(end_index)) {
1479 end_index = aux_connections_from_to_[end_index];
1484 if (parent ==
nullptr)
1492 float display_multiply = scale * (details.
max - details.
min);
1493 modulation_amount_sliders_[index]->setDisplayMultiply(display_multiply);
1494 modulation_hover_sliders_[index]->setDisplayMultiply(display_multiply);
1495 selected_modulation_sliders_[index]->setDisplayMultiply(display_multiply);
1499 modulation_amount_sliders_[index]->setDisplayMultiply(1.0f);
1500 modulation_hover_sliders_[index]->setDisplayMultiply(1.0f);
1501 selected_modulation_sliders_[index]->setDisplayMultiply(1.0f);
1507 if (parent ==
nullptr || source.empty() || destination.empty())
1522 if (parent ==
nullptr)
1526 modulation_amount_sliders_[i]->removeAux();
1527 modulation_hover_sliders_[i]->removeAux();
1528 selected_modulation_sliders_[i]->removeAux();
1531 aux_connections_from_to_.clear();
1532 aux_connections_to_from_.clear();
1540 int modulation_index = modulation_amount_lookup_[connection->
destination_name]->index();
1548 if (parent ==
nullptr || modifying_)
1551 for (
auto& meter : meter_lookup_) {
1554 meter.second->setVisible(num_modulations);
1557 for (
auto& button : modulation_buttons_)
1558 button.second->setActiveModulation(button.second->isActiveModulation());
1562 positionModulationAmountSliders();
1568 if (parent ==
nullptr || changing_hover_modulation_)
1576 modulation_hover_sliders_[index]->hideImmediately();
1579 if (slider ==
nullptr || !slider->isShowing())
1580 modulation_hover_sliders_[index]->hideImmediately();
1587 while (aux_connections_to_from_.count(index)) {
1588 index = aux_connections_to_from_[index];
1596 if (from_index == to_index)
1599 aux_connections_to_from_[to_index] = from_index;
1600 aux_connections_from_to_[from_index] = to_index;
1601 std::string aux_name =
"modulation_" + std::to_string(from_index + 1) +
"_amount";
1602 modulation_hover_sliders_[to_index]->setAux(aux_name);
1603 modulation_amount_sliders_[to_index]->setAux(aux_name);
1607 if (aux_connections_from_to_.count(from_index) == 0)
1610 int to_index = aux_connections_from_to_[from_index];
1611 modulation_hover_sliders_[to_index]->removeAux();
1612 modulation_amount_sliders_[to_index]->removeAux();
1613 aux_connections_from_to_.erase(from_index);
1614 aux_connections_to_from_.erase(to_index);
1618 if (aux_connections_to_from_.count(to_index) == 0)
1621 modulation_hover_sliders_[to_index]->removeAux();
1622 modulation_amount_sliders_[to_index]->removeAux();
1623 aux_connections_from_to_.erase(aux_connections_to_from_[to_index]);
1624 aux_connections_to_from_.erase(to_index);
1627void ModulationManager::makeCurrentModulatorAmountsVisible() {
1629 if (current_modulator_ ==
nullptr || parent ==
nullptr)
1632 std::string source_name = current_modulator_->getName().toStdString();
1634 std::set<ModulationAmountKnob*> selected_modulation_sliders;
1641 selected_modulation_sliders.insert(selected_slider);
1642 if (!selected_slider->
hasAux()) {
1643 selected_slider->setValue(connection->
modulation_processor->currentBaseValue(), dontSendNotification);
1658 Rectangle<int> destination_bounds = getLocalArea(destination_slider, destination_slider->getLocalBounds());
1660 int center_x = destination_bounds.getCentreX();
1661 int left = destination_bounds.getX();
1662 int right = destination_bounds.getRight();
1664 int bottom = destination_bounds.getBottom();
1665 int top = destination_bounds.getY();
1666 int center_y = destination_bounds.getCentreY();
1670 if (placement == BubbleComponent::below)
1671 selected_slider->setBounds(center_x - width / 2, bottom, width, width);
1672 else if (placement == BubbleComponent::above)
1673 selected_slider->setBounds(center_x - width / 2, top - width, width, width);
1674 else if (placement == BubbleComponent::left)
1675 selected_slider->setBounds(left - width, center_y - width / 2, width, width);
1677 selected_slider->setBounds(right, center_y - width / 2, width, width);
1679 selected_slider->
makeVisible(destination_slider->isShowing());
1682 for (
auto& selected_slider : selected_modulation_sliders_) {
1683 if (selected_modulation_sliders.count(selected_slider.get()) == 0)
1688void ModulationManager::makeModulationsVisible(
SynthSlider* destination,
bool visible) {
1690 if (destination ==
nullptr || parent ==
nullptr || changing_hover_modulation_)
1693 std::string name = destination->getName().toStdString();
1694 if (slider_model_lookup_[name] != destination)
1698 std::vector<ModulationAmountKnob*> modulation_hover_sliders;
1700 bool current_modulation_showing =
false;
1704 if (current_modulator_ && current_modulator_->getName() == String(connection->
source_name))
1705 current_modulation_showing =
true;
1707 modulation_hover_sliders.push_back(hover_slider);
1708 if (!hover_slider->
hasAux()) {
1709 hover_slider->setValue(connection->
modulation_processor->currentBaseValue(), dontSendNotification);
1719 if (current_modulation_showing) {
1720 auto position = modulation_hover_sliders.begin() + (modulation_hover_sliders.size() + 1) / 2;
1721 modulation_hover_sliders.insert(position,
nullptr);
1722 if (modulation_hover_sliders.size() % 2 == 0)
1723 modulation_hover_sliders.insert(modulation_hover_sliders.end(),
nullptr);
1725 int num_sliders = (int)modulation_hover_sliders.size();
1727 Rectangle<int> destination_bounds = getLocalArea(destination, destination->getLocalBounds());
1728 int x = destination_bounds.getRight();
1729 int y = destination_bounds.getBottom();
1730 int beginning_offset = hover_slider_width * num_sliders / 2;
1735 if (placement == BubbleComponent::below) {
1736 x = destination_bounds.getCentreX() - beginning_offset;
1737 delta_x = hover_slider_width;
1739 else if (placement == BubbleComponent::above) {
1740 x = destination_bounds.getCentreX() - beginning_offset;
1741 y = destination_bounds.getY() - hover_slider_width;
1742 delta_x = hover_slider_width;
1744 else if (placement == BubbleComponent::left) {
1745 x = destination_bounds.getX() - hover_slider_width;
1746 y = destination_bounds.getCentreY() - beginning_offset;
1747 delta_y = hover_slider_width;
1750 y = destination_bounds.getCentreY() - beginning_offset;
1751 delta_y = hover_slider_width;
1754 std::unordered_set<ModulationAmountKnob*> lookup(modulation_hover_sliders.begin(), modulation_hover_sliders.end());
1755 for (
auto& hover_slider : modulation_hover_sliders_) {
1756 if (lookup.count(hover_slider.get()) == 0)
1763 hover_slider->setBounds(x, y, hover_slider_width, hover_slider_width);
1772void ModulationManager::positionModulationAmountSlidersInside(
const std::string& source,
1773 std::vector<vital::ModulationConnection*> connections) {
1774 static constexpr float kRightPopupPositionX = 150;
1775 int total_connections =
static_cast<int>(connections.size());
1778 expand_button->setVisible(
false);
1780 if (expand_button == current_expanded_modulation_)
1781 hideModulationAmountCallout();
1783 for (
int i = 0; i < total_connections; ++i) {
1787 slider->setVisible(showingInParents(modulation_button));
1788 Point<int> point = getLocalPoint(modulation_button, Point<int>(0, 0));
1791 BubbleComponent::BubblePlacement popup_position = BubbleComponent::below;
1792 if (slider->getX() < kRightPopupPositionX)
1793 popup_position = BubbleComponent::right;
1794 if (getWidth() - slider->getRight() < kRightPopupPositionX)
1795 popup_position = BubbleComponent::left;
1799 if (slider_model_lookup_.count(name))
1804 slider->setMouseClickGrabsKeyboardFocus(
true);
1809void ModulationManager::positionModulationAmountSlidersCallout(
const std::string& source,
1810 std::vector<vital::ModulationConnection*> connections) {
1814 expand_button->setVisible(showingInParents(modulation_button));
1816 std::vector<ModulationAmountKnob*> amount_controls;
1819 amount_controls.push_back(modulation_amount_sliders_[index].get());
1823 if (slider_model_lookup_.count(name))
1828 slider->setVisible(
false);
1832 if (expand_button == current_expanded_modulation_)
1833 showModulationAmountCallout(source);
1836void ModulationManager::showModulationAmountCallout(
const std::string& source) {
1837 static constexpr int kSliderWidth = 30;
1838 static constexpr int kPadding = 5;
1841 current_expanded_modulation_ = modulation_callout_buttons_[source].get();
1842 std::vector<ModulationAmountKnob*> amount_controls = current_expanded_modulation_->
getSliders();
1844 int num_sliders =
static_cast<int>(amount_controls.size());
1845 int columns = current_expanded_modulation_->
getNumColumns(num_sliders);
1846 int rows = (num_sliders + columns - 1) / columns;
1847 int width = kSliderWidth * columns + 2 * kPadding;
1848 int height = kSliderWidth * rows + 2 * kPadding;
1849 Rectangle<int> top_level_modulation_bounds = getLocalArea(modulation_button, modulation_button->getLocalBounds());
1850 int start_x = top_level_modulation_bounds.getX() + (modulation_button->getWidth() - width) / 2;
1851 start_x = std::min(getWidth() - width, std::max(0, start_x));
1852 int start_y = top_level_modulation_bounds.getBottom();
1853 start_y = std::min(getHeight() - height, start_y);
1855 modulation_expansion_box_.setVisible(
true);
1857 modulation_expansion_box_.setBounds(start_x, start_y, width, height);
1859 modulation_expansion_box_.grabKeyboardFocus();
1864 int x = column * kSliderWidth + kPadding;
1865 int y = height - (row + 1) * kSliderWidth - kPadding;
1866 slider->setBounds(start_x + x, start_y + y, kSliderWidth, kSliderWidth);
1867 slider->setVisible(
true);
1868 slider->setMouseClickGrabsKeyboardFocus(
false);
1873 if (column >= columns) {
1880void ModulationManager::hideModulationAmountCallout() {
1881 if (current_expanded_modulation_ ==
nullptr)
1884 std::vector<ModulationAmountKnob*> amount_controls = current_expanded_modulation_->
getSliders();
1886 slider->setVisible(
false);
1890 modulation_expansion_box_.setVisible(
false);
1891 current_expanded_modulation_ =
nullptr;
1894void ModulationManager::positionModulationAmountSliders(
const std::string& source) {
1895 static constexpr int kMaxModulationsAcross = 3;
1897 if (parent ==
nullptr)
1902 int area_width = std::max(1, modulation_area.getWidth());
1903 int max_modulation_height = (kMaxModulationsAcross * modulation_area.getHeight()) / area_width;
1904 int max_modulations_inside = kMaxModulationsAcross * max_modulation_height;
1907 int total_connections =
static_cast<int>(connections.size());
1908 if (total_connections) {
1909 if (total_connections && total_connections > max_modulations_inside)
1910 positionModulationAmountSlidersCallout(source, connections);
1912 positionModulationAmountSlidersInside(source, connections);
1915 modulation_callout_buttons_[source]->setVisible(
false);
1918void ModulationManager::positionModulationAmountSliders() {
1920 if (parent ==
nullptr)
1923 for (
auto& modulation_slider : modulation_amount_sliders_)
1924 modulation_slider->setVisible(
false);
1926 for (
auto& modulation_button : modulation_buttons_) {
1927 std::string name = modulation_button.second->getName().toStdString();
1928 positionModulationAmountSliders(name);
1932bool ModulationManager::enteringHoverValue() {
1934 if (modulation_amount_sliders_[i] && modulation_amount_sliders_[i]->enteringValue())
1936 if (modulation_hover_sliders_[i] && modulation_hover_sliders_[i]->enteringValue())
1938 if (selected_modulation_sliders_[i] && selected_modulation_sliders_[i]->enteringValue())
1946 if (parent ==
nullptr || modifying_)
1952 if (aux_connections_to_from_.count(i) == 0)
1958 modulation_amount_sliders_[i]->setBipolar(bipolar);
1959 modulation_amount_sliders_[i]->setStereo(stereo);
1960 modulation_amount_sliders_[i]->setBypass(bypass);
1962 modulation_hover_sliders_[i]->setBipolar(bipolar);
1963 modulation_hover_sliders_[i]->setStereo(stereo);
1964 modulation_hover_sliders_[i]->setBypass(bypass);
1969 for (
auto& meter : meter_lookup_) {
1970 SynthSlider* slider = slider_model_lookup_[meter.first];
1971 if (slider && slider->isShowing()) {
1973 meter.second->setBounds(local_bounds);
Interface for objects interested in ModulationAmountKnob events.
Definition modulation_manager.h:44
A specialized SynthSlider that represents a single modulation amount control.
Definition modulation_manager.h:27
void setStereo(bool stereo)
Definition modulation_manager.h:147
bool isBypass()
Definition modulation_manager.h:149
bool isCurrentModulator()
Definition modulation_manager.h:153
String getOriginalName()
Gets the knob's original name before auxiliary assignment.
Definition modulation_manager.h:185
void handleModulationMenuCallback(int result)
Handles a selection from the modulation context menu.
Definition modulation_manager.cpp:272
void makeVisible(bool visible)
Toggles the knob's visibility smoothly or immediately.
Definition modulation_manager.cpp:298
bool isStereo()
Definition modulation_manager.h:150
void setBipolar(bool bipolar)
Definition modulation_manager.h:148
int index()
Definition modulation_manager.h:154
void setDestinationComponent(Component *component, const std::string &name)
Associates the knob with a destination component (slider or UI element).
Definition modulation_manager.cpp:322
void setSource(const std::string &name)
Sets the source parameter name for this modulation.
Definition modulation_manager.cpp:336
bool hasAux()
Checks if this knob currently has an auxiliary modulation.
Definition modulation_manager.h:170
ModulationAmountKnob(String name, int index)
Constructs a ModulationAmountKnob.
Definition modulation_manager.cpp:172
void setCurrentModulator(bool current)
Marks this knob as representing the currently selected modulator.
Definition modulation_manager.cpp:314
void hideImmediately()
Hides the knob immediately without animations.
Definition modulation_manager.cpp:307
void mouseExit(const MouseEvent &e) override
Definition modulation_manager.cpp:256
void mouseDown(const MouseEvent &e) override
Mouse event overrides for custom behavior.
Definition modulation_manager.cpp:191
Colour getInternalColor()
Returns the internal color for drawing this knob.
Definition modulation_manager.cpp:330
@ kDisconnect
Removes the modulation connection.
Definition modulation_manager.h:34
@ kToggleBypass
Toggles bypassing the modulation.
Definition modulation_manager.h:35
@ kToggleBipolar
Toggles bipolar (positive and negative) modulation.
Definition modulation_manager.h:36
@ kToggleStereo
Toggles stereo modulation mode.
Definition modulation_manager.h:37
void setBypass(bool bypass)
Definition modulation_manager.h:146
void mouseUp(const MouseEvent &e) override
Definition modulation_manager.cpp:241
bool isBipolar()
Definition modulation_manager.h:151
Definition modulation_manager.cpp:97
bool isActive()
Definition modulation_manager.cpp:156
void setIndex(int index)
Definition modulation_manager.cpp:152
void setRectangle(bool rectangle)
Definition modulation_manager.cpp:149
void setActive(bool active)
Definition modulation_manager.cpp:109
ModulationDestination()=delete
virtual ~ModulationDestination()
Definition modulation_manager.cpp:106
void setRotary(bool rotary)
Definition modulation_manager.cpp:150
void setMargin(int margin)
Definition modulation_manager.cpp:151
bool hasExtraModulationTarget()
Definition modulation_manager.cpp:154
int getIndex()
Definition modulation_manager.cpp:157
bool isRotary()
Definition modulation_manager.cpp:155
void setSizeMultiple(float multiple)
Definition modulation_manager.cpp:111
Rectangle< float > getFillBounds()
Definition modulation_manager.cpp:116
ModulationDestination(SynthSlider *source)
Definition modulation_manager.cpp:99
SynthSlider * getDestinationSlider()
Definition modulation_manager.cpp:108
void setAmountControls(std::vector< ModulationAmountKnob * > amount_controls)
Sets the amount controls displayed inside this expansion box.
Definition modulation_manager.h:260
void addListener(Listener *listener)
Adds a Listener for expansion box focus events.
Definition modulation_manager.h:266
void modulationDragged(const MouseEvent &e) override
Called while modulation is being dragged out (during mouse drag).
Definition modulation_manager.cpp:866
void disconnectModulation(ModulationAmountKnob *modulation_knob) override
Called when the modulation is disconnected.
Definition modulation_manager.cpp:948
void renderMeters(OpenGlWrapper &open_gl, bool animate)
Definition modulation_manager.cpp:1084
void renderOpenGlComponents(OpenGlWrapper &open_gl, bool animate) override
Renders all OpenGL components in this section and sub-sections.
Definition modulation_manager.cpp:1052
void setModulationBipolar(ModulationAmountKnob *modulation_knob, bool bipolar) override
Called when modulation bipolar state changes.
Definition modulation_manager.cpp:983
void drawDraggingModulation(OpenGlWrapper &open_gl)
Definition modulation_manager.cpp:1031
void setModulationSliderValue(int index, float value)
Sets the modulation value for a given modulation index.
Definition modulation_manager.cpp:1439
void removeModulation(std::string source, std::string destination)
Removes a modulation connection between a source and a destination.
Definition modulation_manager.cpp:1408
void drawModulationDestinations(OpenGlWrapper &open_gl)
Definition modulation_manager.cpp:1010
void modulationWheelMoved(const MouseEvent &e, const MouseWheelDetails &wheel) override
Called when the mouse wheel moves while interacting with the modulation button.
Definition modulation_manager.cpp:900
int getModulationIndex(std::string source, std::string destination)
Definition modulation_manager.cpp:1266
void modulationAmountChanged(SynthSlider *slider) override
Definition modulation_manager.cpp:604
void resized() override
Called when the component is resized. Arranges layout of child components.
Definition modulation_manager.cpp:516
void modulationsChanged(const std::string &name) override
Definition modulation_manager.cpp:1246
void initOpenGlComponents(OpenGlWrapper &open_gl) override
Initializes all OpenGL components in this section and sub-sections.
Definition modulation_manager.cpp:991
ModulationManager(std::map< std::string, ModulationButton * > modulation_buttons, std::map< std::string, SynthSlider * > sliders, vital::output_map mono_modulations, vital::output_map poly_modulations)
Constructs a ModulationManager.
Definition modulation_manager.cpp:341
void mouseDown(SynthSlider *slider) override
Definition modulation_manager.cpp:1318
void createModulationMeter(const vital::Output *mono_total, const vital::Output *poly_total, SynthSlider *slider, OpenGlMultiQuad *quads, int index)
Creates a modulation meter for a given slider and places it into an OpenGlMultiQuad for visualization...
Definition modulation_manager.cpp:491
void setModulationSliderValues(int index, float value)
Sets the modulation values and updates all connected auxiliary nodes.
Definition modulation_manager.cpp:1454
void mouseUp(SynthSlider *slider) override
Definition modulation_manager.cpp:1337
int getIndexForModulationSlider(Slider *slider)
Definition modulation_manager.cpp:1278
void startModulationMap(ModulationButton *source, const MouseEvent &e) override
Called when the user begins dragging out to map the modulation (dragging out of the button).
Definition modulation_manager.cpp:663
void clearTemporaryHoverModulation()
Definition modulation_manager.cpp:856
float getAuxMultiplier(int index)
Definition modulation_manager.cpp:1585
void modulationSelected(ModulationButton *source) override
Called when this modulation button is selected.
Definition modulation_manager.cpp:631
void setModulationSettings(ModulationAmountKnob *modulation_knob)
Definition modulation_manager.cpp:958
void setModulationSliderBipolar(int index, bool bipolar)
Sets the bipolar state for a given modulation index.
Definition modulation_manager.cpp:1448
void clearModulationSource()
Definition modulation_manager.cpp:939
void destroyOpenGlComponents(OpenGlWrapper &open_gl) override
Destroys all OpenGL components in this section and sub-sections.
Definition modulation_manager.cpp:1166
void reset() override
Resets the section and all sub-sections.
Definition modulation_manager.cpp:1546
void hoverEnded(SynthSlider *slider) override
Definition modulation_manager.cpp:1237
void doubleClick(SynthSlider *slider) override
Definition modulation_manager.cpp:1342
void modulationCleared() override
Called when all modulations associated with this button have been cleared.
Definition modulation_manager.cpp:648
void renderSourceMeters(OpenGlWrapper &open_gl, int index)
Definition modulation_manager.cpp:1107
void endModulationMap() override
Called when the user finishes dragging out modulation connections.
Definition modulation_manager.cpp:914
void modulationDraggedToHoverSlider(ModulationAmountKnob *hover_slider)
Definition modulation_manager.cpp:759
void modulationLostFocus(ModulationButton *source) override
Called when the modulation button loses keyboard focus.
Definition modulation_manager.cpp:934
void drawCurrentModulator(OpenGlWrapper &open_gl)
Definition modulation_manager.cpp:1018
void connectModulation(std::string source, std::string destination)
Connects a modulation source to a destination parameter.
Definition modulation_manager.cpp:1398
void hoverStarted(SynthSlider *slider) override
Definition modulation_manager.cpp:1223
void createModulationSlider(std::string name, SynthSlider *slider, bool poly)
Creates internal structures for handling modulation of a given parameter (slider).
Definition modulation_manager.cpp:503
void updateSmoothModValues()
Definition modulation_manager.cpp:1146
void setModulationBypass(ModulationAmountKnob *modulation_knob, bool bypass) override
Called when modulation bypass state changes.
Definition modulation_manager.cpp:979
void hideUnusedHoverModulations()
Definition modulation_manager.cpp:1566
void setVisibleMeterBounds()
Definition modulation_manager.cpp:1968
~ModulationManager()
Destructor.
Definition modulation_manager.cpp:514
void setModulationSliderScale(int index)
Adjusts the displayed range of a modulation slider based on parameter scaling.
Definition modulation_manager.cpp:1475
void setModulationAmounts()
Definition modulation_manager.cpp:1944
void modulationClicked(ModulationButton *source) override
Called when the modulation button is clicked (mouse up) without dragging out.
Definition modulation_manager.cpp:643
void initAuxConnections()
Definition modulation_manager.cpp:1520
void addAuxConnection(int from_index, int to_index)
Definition modulation_manager.cpp:1595
void buttonClicked(Button *button) override
Called when a button is clicked. Updates the synth parameter accordingly.
Definition modulation_manager.cpp:1384
void setTemporaryModulationBipolar(Component *component, bool bipolar)
Definition modulation_manager.cpp:822
void clearTemporaryModulation()
Definition modulation_manager.cpp:843
void modulationDisconnected(vital::ModulationConnection *connection, bool last) override
Called when a modulation connection is disconnected.
Definition modulation_manager.cpp:621
void menuFinished(SynthSlider *slider) override
Definition modulation_manager.cpp:1241
void removeAuxDestinationConnection(int to_index)
Definition modulation_manager.cpp:1617
void modulationRemoved(SynthSlider *slider) override
Definition modulation_manager.cpp:613
void modulationDraggedToComponent(Component *component, bool bipolar)
Definition modulation_manager.cpp:781
void parentHierarchyChanged() override
Definition modulation_manager.cpp:570
vital::ModulationConnection * getConnection(int index)
Definition modulation_manager.cpp:1296
void updateModulationMeterLocations()
Definition modulation_manager.cpp:588
bool hasFreeConnection()
Definition modulation_manager.cpp:652
void removeAuxSourceConnection(int from_index)
Definition modulation_manager.cpp:1606
void endModulationEdit(SynthSlider *slider) override
Definition modulation_manager.cpp:1357
void sliderValueChanged(Slider *slider) override
Called when a slider value changes. Updates the synth parameter accordingly.
Definition modulation_manager.cpp:1361
void setModulationValues(std::string source, std::string destination, vital::mono_float amount, bool bipolar, bool stereo, bool bypass)
Sets multiple modulation properties at once.
Definition modulation_manager.cpp:1504
vital::ModulationConnection * getConnectionForModulationSlider(Slider *slider)
Definition modulation_manager.cpp:1285
void setModulationStereo(ModulationAmountKnob *modulation_knob, bool stereo) override
Called when modulation stereo state changes.
Definition modulation_manager.cpp:987
void beginModulationEdit(SynthSlider *slider) override
Definition modulation_manager.cpp:1353
static String getMenuSourceDisplayName(const String &original)
Returns a user-friendly display name for a given source string in menu context.
Definition modulation_matrix.cpp:513
A visual component that displays the current modulation amount applied to a slider parameter.
Definition modulation_meter.h:21
void setModulationAmountQuad(OpenGlQuad &quad, float amount, bool bipolar)
Sets the given quad to represent a modulation amount line or arc.
Definition modulation_meter.cpp:180
const SynthSlider * destination()
Gets the destination slider that the meter is visualizing.
Definition modulation_meter.h:100
bool isRotary() const
Checks if the associated parameter control is a rotary knob.
Definition modulation_meter.h:82
void setModulated(bool modulated)
Sets the modulated state of the meter.
Definition modulation_meter.h:88
void setAmountQuadVertices(OpenGlQuad &quad)
Sets up the quad coordinates for the modulation amount indicator.
Definition modulation_meter.cpp:115
static bool setViewPort(Component *component, Rectangle< int > bounds, OpenGlWrapper &open_gl)
Sets the OpenGL viewport to match a specified rectangle within a component.
Definition open_gl_component.cpp:42
A component for rendering multiple quads using OpenGL, with customizable colors, rounding,...
Definition open_gl_multi_quad.h:16
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
void setActive(bool active)
Activates or deactivates rendering of this component.
Definition open_gl_multi_quad.h:331
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
void setRounding(float rounding)
Sets the rounding radius of the quads.
Definition open_gl_multi_quad.h:347
force_inline void setModColor(Colour color)
Sets a modulation color for custom effects in the shader.
Definition open_gl_multi_quad.h:126
void setAlpha(float alpha, bool reset=false)
Sets the alpha blending multiplier, can reset to this alpha.
Definition open_gl_multi_quad.h:382
void setAdditive(bool additive)
Enables or disables additive blending for rendering.
Definition open_gl_multi_quad.h:377
A convenience class for a single quad rendered via OpenGL.
Definition open_gl_multi_quad.h:447
float getModulationAmount() const
Definition synth_slider.h:160
bool isTextOrCurve() const
Definition synth_slider.h:105
void setActive(bool active=true)
Definition synth_slider.h:186
void setColors()
Updates internal colors based on the current skin and state.
Definition synth_slider.cpp:144
void redoImage(bool skip_image=false)
Definition synth_slider.cpp:64
SynthSection * getSectionParent()
Definition synth_slider.h:286
void setAlpha(float alpha, bool reset=false)
Definition synth_slider.h:278
void setModulationKnob()
Marks this slider as a modulation knob.
Definition synth_slider.h:152
OpenGlComponent * getQuadComponent()
Definition synth_slider.h:141
SynthSection * parent_
The parent SynthSection.
Definition synth_slider.h:289
bool isActive() const
Definition synth_slider.h:172
Manages and provides access to vertex and fragment shaders used by the OpenGL rendering pipeline.
Definition shaders.h:19
@ kLinearModulationFragment
Definition shaders.h:75
@ kRotaryModulationFragment
Definition shaders.h:72
@ kRoundedRectangleFragment
Definition shaders.h:69
@ kCircleFragment
Definition shaders.h:65
@ kKnobModMeterArcThickness
Definition skin.h:96
@ kWidgetMargin
Definition skin.h:103
@ kBodyRounding
Definition skin.h:71
@ kKnobOffset
Definition skin.h:97
@ kLabelBackgroundRounding
Definition skin.h:74
@ kKnobModMeterArcSize
Definition skin.h:95
@ kModulationMeterRight
Definition skin.h:177
@ kModulationMeter
Definition skin.h:175
@ kModulationMeterLeft
Definition skin.h:176
@ kWidgetPrimary2
Definition skin.h:166
@ kWidgetPrimary1
Definition skin.h:165
@ kWidgetBackground
Definition skin.h:173
@ kLightenScreen
Definition skin.h:141
@ kRotaryArc
Definition skin.h:150
@ kModulationMeterControl
Definition skin.h:178
@ kBody
Definition skin.h:129
@ kModulationDragDrop
Definition skin.h:55
std::vector< vital::ModulationConnection * > getSourceConnections(const std::string &source)
Returns all modulation connections from a particular source.
Definition synth_base.cpp:236
bool isMidiMapped(const std::string &name)
Checks if a given parameter name is MIDI mapped.
Definition synth_base.cpp:677
vital::ModulationConnectionBank & getModulationBank()
Retrieves the ModulationConnectionBank managing all modulation connections.
Definition synth_base.cpp:730
int getNumModulations(const std::string &destination)
Counts how many modulations target a given parameter.
Definition synth_base.cpp:227
std::vector< vital::ModulationConnection * > getDestinationConnections(const std::string &destination)
Returns all modulation connections targeting a given destination parameter.
Definition synth_base.cpp:253
const vital::StatusOutput * getStatusOutput(const std::string &name)
Retrieves a status output by name.
Definition synth_base.cpp:262
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
void setModulationValues(const std::string &source, const std::string &destination, vital::mono_float amount, bool bipolar, bool stereo, bool bypass)
Sets various modulation parameters (amount, bipolar, stereo, bypass) for a given connection.
Definition synth_gui_interface.cpp:119
void disconnectModulation(std::string source, std::string destination)
Disconnects a modulation from the GUI layer.
Definition synth_gui_interface.cpp:146
void connectModulation(std::string source, std::string destination)
Connects a modulation source to a destination parameter through the GUI.
Definition synth_gui_interface.cpp:91
void notifyModulationValueChanged(int index)
Notifies the GUI that a specific modulation's value changed.
Definition synth_gui_interface.cpp:87
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
void addSlider(SynthSlider *slider, bool show=true, bool listen=true)
Definition synth_section.cpp:445
virtual void animate(bool animate)
Triggers animation state change in sub-sections if needed.
Definition synth_section.cpp:822
virtual void resized() override
Called when the component is resized. Arranges layout of child components.
Definition synth_section.cpp:35
virtual void destroyOpenGlComponents(OpenGlWrapper &open_gl)
Destroys all OpenGL components in this section and sub-sections.
Definition synth_section.cpp:383
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
bool isActive() const
Checks if the section is currently active.
Definition synth_section.h:683
void addOpenGlComponent(OpenGlComponent *open_gl_component, bool to_beginning=false)
Definition synth_section.cpp:489
virtual void sliderValueChanged(Slider *moved_slider) override
Called when a slider value changes. Updates the synth parameter accordingly.
Definition synth_section.cpp:391
const SynthSection * parent_
Definition synth_section.h:814
void setSkinOverride(Skin::SectionOverride skin_override)
Definition synth_section.h:303
virtual void initOpenGlComponents(OpenGlWrapper &open_gl)
Initializes all OpenGL components in this section and sub-sections.
Definition synth_section.cpp:349
Listener interface for receiving slider events such as mouse interactions, modulation changes,...
Definition synth_slider.h:347
A specialized slider with extended functionality for modulation, parameter control,...
Definition synth_slider.h:314
void setShowPopupOnHover(bool show)
Definition synth_slider.h:629
bool has_parameter_assignment_
Definition synth_slider.h:736
bool isModulationBypassed() const
Definition synth_slider.h:580
virtual void mouseDown(const MouseEvent &e) override
Mouse event overrides for custom behavior.
Definition synth_slider.cpp:234
float findValue(Skin::ValueId value_id) const override
Definition synth_slider.h:681
Rectangle< int > getModulationMeterBounds() const
Definition synth_slider.cpp:673
static constexpr float kLinearWidthPercent
Definition synth_slider.h:341
void setPopupPrefix(String prefix)
Definition synth_slider.h:633
void setTextEntrySizePercent(float width_percent, float height_percent)
Definition synth_slider.h:613
virtual void mouseExit(const MouseEvent &e) override
Definition synth_slider.cpp:327
void handlePopupResult(int result)
Definition synth_slider.cpp:703
Component * getExtraModulationTarget()
Definition synth_slider.h:653
virtual void mouseUp(const MouseEvent &e) override
Definition synth_slider.cpp:302
bool isModulationStereo() const
Definition synth_slider.h:576
void setPopupPlacement(BubbleComponent::BubblePlacement placement)
Definition synth_slider.h:515
SynthGuiInterface * synth_interface_
Definition synth_slider.h:766
BubbleComponent::BubblePlacement getModulationPlacement()
Definition synth_slider.h:531
std::vector< SliderListener * > slider_listeners_
Definition synth_slider.h:769
float getKnobSizeScale() const override
Definition synth_slider.h:641
@ kClearMidiLearn
Definition synth_slider.h:320
@ kManualEntry
Definition synth_slider.h:322
@ kArmMidiLearn
Definition synth_slider.h:319
bool isModulationBipolar() const
Definition synth_slider.h:572
A container managing a fixed number of ModulationConnections.
Definition synth_types.h:87
ModulationConnection * atIndex(int index)
Retrieves a ModulationConnection by index.
Definition synth_types.h:114
static const ValueDetails & getDetails(const std::string &name)
Definition synth_parameters.h:200
static std::string getDisplayName(const std::string &name)
Definition synth_parameters.h:212
force_inline poly_float value() const
Returns the current status value.
Definition synth_module.h:49
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 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 kMaxModulationConnections
Maximum number of modulation connections allowed.
Definition synth_constants.h:49
float mono_float
Definition common.h:33
A helper struct containing references to OpenGL context, shaders, and display scale.
Definition shaders.h:174
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 and manages a buffer of samples (poly_float) for a Processor's output.
Definition processor.h:35
Holds metadata about a single parameter (control) in the Vital synthesizer.
Definition synth_parameters.h:23
mono_float max
Maximum parameter value.
Definition synth_parameters.h:41
@ kLinear
Parameter scales linearly between min and max.
Definition synth_parameters.h:30
@ kIndexed
Parameter steps through discrete indexed values.
Definition synth_parameters.h:29
mono_float min
Minimum parameter value.
Definition synth_parameters.h:40
ValueScale value_scale
The scaling mode of the parameter value.
Definition synth_parameters.h:45
Represents a vector of floating-point values using SIMD instructions.
Definition poly_values.h:600
simd_type value
The underlying SIMD register for float.
Definition poly_values.h:1112