15 String formatTime(
float time) {
18 return String(ms_value) +
"ms";
21 float sec_value = int(time * 10.0f) / 10.0f;
22 return String(sec_value) +
"s";
25 constexpr float kMinWindowSize = 0.125f;
26 constexpr float kMaxWindowSize = 64.0f;
33 drag_circle_(
Shaders::kCircleFragment),
34 hover_circle_(
Shaders::kRingFragment),
35 grid_lines_(kMaxGridLines), sub_grid_lines_(kMaxGridLines),
36 position_circle_(
Shaders::kRingFragment),
37 point_circles_(kNumSections,
Shaders::kRingFragment),
38 power_circles_(kNumSections,
Shaders::kCircleFragment) {
39 addAndMakeVisible(drag_circle_);
40 addAndMakeVisible(hover_circle_);
41 addAndMakeVisible(grid_lines_);
42 addAndMakeVisible(sub_grid_lines_);
43 addAndMakeVisible(position_circle_);
44 addAndMakeVisible(point_circles_);
45 addAndMakeVisible(power_circles_);
49 times_[i] = std::make_unique<PlainTextComponent>(
"Time",
"");
50 times_[i]->setJustification(Justification::centredLeft);
51 times_[i]->setScissor(
true);
52 addAndMakeVisible(times_[i].get());
58 attack_hover_ =
false;
60 sustain_hover_ =
false;
61 release_hover_ =
false;
62 attack_power_hover_ =
false;
63 decay_power_hover_ =
false;
64 release_power_hover_ =
false;
68 reset_positions_ =
true;
72 current_position_alpha_ = 0.0f;
75 envelope_phase_ =
nullptr;
77 attack_slider_ =
nullptr;
78 attack_power_slider_ =
nullptr;
79 decay_slider_ =
nullptr;
80 decay_power_slider_ =
nullptr;
81 sustain_slider_ =
nullptr;
82 release_slider_ =
nullptr;
83 release_power_slider_ =
nullptr;
85 delay_outputs_ = getOutputs(mono_modulations, poly_modulations, prefix +
"_delay");
86 attack_outputs_ = getOutputs(mono_modulations, poly_modulations, prefix +
"_attack");
87 hold_outputs_ = getOutputs(mono_modulations, poly_modulations, prefix +
"_hold");
88 decay_outputs_ = getOutputs(mono_modulations, poly_modulations, prefix +
"_decay");
89 sustain_outputs_ = getOutputs(mono_modulations, poly_modulations, prefix +
"_sustain");
90 release_outputs_ = getOutputs(mono_modulations, poly_modulations, prefix +
"_release");
106 parent_ = findParentComponentOfClass<SynthGuiInterface>();
108 if (envelope_phase_ ==
nullptr && parent_)
120 position.x = unpadX(position.x);
121 position.y = unpadY(position.y);
122 float delay_x = getSliderDelayX();
123 float attack_x = getSliderAttackX();
124 float hold_x = getSliderHoldX();
125 float decay_x = getSliderDecayX();
126 float sustain_y = getSliderSustainY();
127 float release_x = getSliderReleaseX();
129 Point<float> delay_point(delay_x, getHeight());
130 Point<float> attack_power_point((delay_x + attack_x) / 2.0f, getSliderAttackValue(0.5f));
131 Point<float> top_point(attack_x, 0);
132 Point<float> hold_point(hold_x, 0);
133 Point<float> decay_power_point((hold_x + decay_x) / 2.0f, getSliderDecayValue(0.5f));
134 Point<float> sustain_point(decay_x, sustain_y);
135 Point<float> release_power_point((decay_x + release_x) / 2.0f, getSliderReleaseValue(0.5f));
136 Point<float> release_point(release_x, getHeight());
138 std::vector<Point<float>> points = { top_point, sustain_point, release_point };
140 points.push_back(delay_point);
141 if (hold_x > attack_x)
142 points.push_back(hold_point);
144 points.push_back(release_power_point);
146 points.push_back(decay_power_point);
148 points.push_back(attack_power_point);
150 float closest_distance_squared = getHeight() * getHeight();
151 for (
const Point<float>& point : points) {
152 float distance = position.getDistanceSquaredFrom(point);
153 closest_distance_squared = std::min(closest_distance_squared, distance);
156 bool release_hover = position.getDistanceSquaredFrom(release_point) <= closest_distance_squared;
157 bool sustain_hover = position.getDistanceSquaredFrom(sustain_point) <= closest_distance_squared;
158 bool attack_hover = position.getDistanceSquaredFrom(top_point) <= closest_distance_squared;
159 bool delay_hover = position.getDistanceSquaredFrom(delay_point) == closest_distance_squared;
160 bool hold_hover = hold_x > attack_x && position.getDistanceSquaredFrom(hold_point) == closest_distance_squared;
161 bool release_power_hover = position.getDistanceSquaredFrom(release_power_point) == closest_distance_squared;
162 bool decay_power_hover = position.getDistanceSquaredFrom(decay_power_point) == closest_distance_squared;
163 bool attack_power_hover = position.getDistanceSquaredFrom(attack_power_point) == closest_distance_squared;
165 if (delay_hover != delay_hover_ || attack_hover != attack_hover_ || hold_hover != hold_hover_ ||
166 sustain_hover != sustain_hover_ || release_hover != release_hover_ ||
167 attack_power_hover != attack_power_hover_ || decay_power_hover != decay_power_hover_ ||
168 release_power_hover != release_power_hover_) {
169 delay_hover_ = delay_hover;
170 attack_hover_ = attack_hover;
171 hold_hover_ = hold_hover;
172 sustain_hover_ = sustain_hover;
173 release_hover_ = release_hover;
174 attack_power_hover_ = attack_power_hover;
175 decay_power_hover_ = decay_power_hover;
176 release_power_hover_ = release_power_hover;
182 Point<float> position = e.getPosition().toFloat();
187 delay_hover_ =
false;
188 attack_hover_ =
false;
190 sustain_hover_ =
false;
191 release_hover_ =
false;
192 attack_power_hover_ =
false;
193 decay_power_hover_ =
false;
194 release_power_hover_ =
false;
200 last_edit_position_ = e.position;
206 last_edit_position_ = e.position;
209 setDelayX(last_edit_position_.x);
210 else if (release_hover_)
211 setReleaseX(last_edit_position_.x);
212 else if (sustain_hover_) {
213 setDecayX(last_edit_position_.x);
214 setSustainY(last_edit_position_.y);
216 else if (attack_hover_)
217 setAttackX(last_edit_position_.x);
218 else if (hold_hover_)
219 setHoldX(last_edit_position_.x);
220 else if (attack_power_hover_)
221 setAttackPower(attack_power_slider_->getValue() + delta_power);
222 else if (decay_power_hover_)
223 setDecayPower(decay_power_slider_->getValue() + delta_power);
224 else if (release_power_hover_)
225 setReleasePower(release_power_slider_->getValue() + delta_power);
231 if (attack_power_hover_)
232 setAttackPower(0.0f);
233 else if (decay_power_hover_)
235 else if (release_power_hover_)
236 setReleasePower(0.0f);
245 static constexpr float kMouseWheelSensitivity = 1.0f;
247 zoom(std::pow(2.0f, -kMouseWheelSensitivity * wheel.deltaY));
251 static constexpr float kMouseWheelSensitivity = 0.02f;
253 zoom(std::pow(2.0f, kMouseWheelSensitivity * delta.y));
257 static constexpr float kResetBuffer = 0.25f;
259 window_time_ = (1.0f + kResetBuffer) * getSliderReleaseX() * window_time_ / getWidth();
260 window_time_ = std::max(std::min(window_time_, kMaxWindowSize), kMinWindowSize);
265void EnvelopeEditor::zoom(
float amount) {
266 window_time_ *= amount;
267 window_time_ = std::max(std::min(window_time_, kMaxWindowSize), kMinWindowSize);
276inline float EnvelopeEditor::getSliderDelayX() {
277 if (delay_slider_ ==
nullptr)
281 return getWidth() * time / window_time_;
284inline float EnvelopeEditor::getSliderAttackX() {
285 if (attack_slider_ ==
nullptr)
289 return getSliderDelayX() + getWidth() * time / window_time_;
292inline float EnvelopeEditor::getSliderHoldX() {
293 if (hold_slider_ ==
nullptr)
297 return getSliderAttackX() + getWidth() * time / window_time_;
300float EnvelopeEditor::getSliderDecayX() {
301 if (decay_slider_ ==
nullptr)
305 return getSliderHoldX() + getWidth() * time / window_time_;
308float EnvelopeEditor::getSliderSustainY() {
309 if (sustain_slider_ ==
nullptr)
312 float percent = sustain_slider_->valueToProportionOfLength(sustain_slider_->getValue());
313 return getHeight() * (1.0f - percent);
316float EnvelopeEditor::getSliderReleaseX() {
317 if (release_slider_ ==
nullptr)
320 float time = release_slider_->
getAdjustedValue(release_slider_->getValue());
321 return getSliderDecayX() + getWidth() * time / window_time_;
324inline float EnvelopeEditor::getDelayTime(
int index) {
325 vital::poly_float delays = getOutputsTotal(delay_outputs_, delay_slider_->getValue());
326 return delay_slider_->
getAdjustedValue(std::max<float>(0.0f, delays[index]));
329inline float EnvelopeEditor::getAttackTime(
int index) {
330 vital::poly_float attacks = getOutputsTotal(attack_outputs_, attack_slider_->getValue());
331 return attack_slider_->
getAdjustedValue(std::max<float>(0.0f, attacks[index]));
334inline float EnvelopeEditor::getHoldTime(
int index) {
335 vital::poly_float holds = getOutputsTotal(hold_outputs_, hold_slider_->getValue());
339inline float EnvelopeEditor::getDecayTime(
int index) {
340 vital::poly_float decays = getOutputsTotal(decay_outputs_, decay_slider_->getValue());
341 return decay_slider_->
getAdjustedValue(std::max<float>(0.0f, decays[index]));
344inline float EnvelopeEditor::getReleaseTime(
int index) {
345 vital::poly_float releases = getOutputsTotal(release_outputs_, release_slider_->getValue());
346 return release_slider_->
getAdjustedValue(std::max<float>(0.0f, releases[index]));
349inline float EnvelopeEditor::getDelayX(
int index) {
351 return getSliderDelayX();
353 return getWidth() * getDelayTime(index) / window_time_;
356inline float EnvelopeEditor::getAttackX(
int index) {
358 return getSliderAttackX();
360 return getDelayX(index) + getWidth() * getAttackTime(index) / window_time_;
363inline float EnvelopeEditor::getHoldX(
int index) {
365 return getSliderHoldX();
367 return getAttackX(index) + getWidth() * getHoldTime(index) / window_time_;
370float EnvelopeEditor::getDecayX(
int index) {
372 return getSliderDecayX();
374 return getHoldX(index) + getWidth() * getDecayTime(index) / window_time_;
377float EnvelopeEditor::getSustainY(
int index) {
379 return getSliderSustainY();
381 vital::poly_float sustains = getOutputsTotal(sustain_outputs_, sustain_slider_->getValue());
382 float percent = sustains[index] / sustain_slider_->getRange().getLength();
384 return getHeight() * (1.0f - percent);
387float EnvelopeEditor::getReleaseX(
int index) {
389 return getSliderReleaseX();
391 return getDecayX(index) + getWidth() * getReleaseTime(index) / window_time_;
394float EnvelopeEditor::getBackupPhase(
float phase,
int index) {
395 static constexpr float kBackupTime = 1.0f / 50.0f;
400 float time = kBackupTime;
401 float current_phase = phase;
403 if (current_phase == kReleasePoint)
406 if (current_phase > kReleasePoint) {
407 float release_time = getReleaseTime(index);
408 if (release_time <= 0.0f)
409 current_phase = kReleasePoint;
411 float phase_delta = time / release_time;
412 float time_released = release_time * (current_phase - kReleasePoint);
414 current_phase = current_phase - phase_delta;
415 if (current_phase >= kReleasePoint)
416 return current_phase;
418 time -= time_released;
419 current_phase = std::max(current_phase, kReleasePoint);
422 if (current_phase > kDecayPoint) {
423 float decay_time = getDecayTime(index);
424 if (decay_time <= 0.0f)
425 current_phase = kDecayPoint;
427 float phase_delta = time / decay_time;
428 float time_decayed = decay_time * (current_phase - kDecayPoint);
430 current_phase = current_phase - phase_delta;
431 if (current_phase >= kDecayPoint)
432 return current_phase;
434 time -= time_decayed;
435 current_phase = std::max(current_phase, kDecayPoint);
438 float attack_time = getAttackTime(index) + getDelayTime(index);
439 if (attack_time <= 0.0f)
442 float phase_delta = time / attack_time;
443 return std::max(0.0f, current_phase - phase_delta);
448 backup.
set(0, getBackupPhase(phase[0], 0));
449 backup.
set(1, getBackupPhase(phase[1], 1));
453float EnvelopeEditor::getEnvelopeValue(
float t,
float power,
float start,
float end) {
457inline float EnvelopeEditor::getSliderAttackValue(
float t) {
458 float power = attack_power_slider_->getValue();
459 return getHeight() - getEnvelopeValue(1.0f - t, power, getHeight(), 0.0f);
462inline float EnvelopeEditor::getSliderDecayValue(
float t) {
463 float power = decay_power_slider_->getValue();
464 return getEnvelopeValue(t, power, 0.0f, getSliderSustainY());
467inline float EnvelopeEditor::getSliderReleaseValue(
float t) {
468 float power = release_power_slider_->getValue();
469 return getEnvelopeValue(t, power, getSliderSustainY(), getHeight());
472inline float EnvelopeEditor::getAttackValue(
float t,
int index) {
474 return getSliderAttackValue(t);
476 float power = attack_power_slider_->getValue();
477 return getHeight() - getEnvelopeValue(1.0f - t, power, getHeight(), 0.0f);
480inline float EnvelopeEditor::getDecayValue(
float t,
int index) {
482 return getSliderDecayValue(t);
484 float power = decay_power_slider_->getValue();
485 return getEnvelopeValue(t, power, 0.0f, getSustainY(index));
488inline float EnvelopeEditor::getReleaseValue(
float t,
int index) {
490 return getSliderReleaseValue(t);
492 float power = release_power_slider_->getValue();
493 return getEnvelopeValue(t, power, getSustainY(index), getHeight());
496void EnvelopeEditor::setDelayX(
float x) {
497 if (delay_slider_ ==
nullptr)
500 float time = x * window_time_ / getWidth();
504void EnvelopeEditor::setAttackX(
float x) {
505 if (attack_slider_ ==
nullptr)
508 float time = (x - getSliderDelayX()) * window_time_ / getWidth();
512void EnvelopeEditor::setHoldX(
float x) {
513 if (delay_slider_ ==
nullptr)
516 float time = (x - getSliderAttackX()) * window_time_ / getWidth();
520void EnvelopeEditor::setPower(
SynthSlider* slider,
float power) {
521 power =
vital::utils::clamp(power, (
float)slider->getMinimum(), (
float)slider->getMaximum());
522 slider->setValue(power);
525void EnvelopeEditor::setAttackPower(
float power) {
526 setPower(attack_power_slider_, power);
529void EnvelopeEditor::setDecayPower(
float power) {
530 setPower(decay_power_slider_, power);
533void EnvelopeEditor::setReleasePower(
float power) {
534 setPower(release_power_slider_, power);
537void EnvelopeEditor::setDecayX(
float x) {
538 if (decay_slider_ ==
nullptr)
541 float time = (x - getSliderHoldX()) * window_time_ / getWidth();
543 window_time_ = std::max(window_time_, x * window_time_ / getWidth());
544 window_time_ = std::max(std::min(window_time_, kMaxWindowSize), kMinWindowSize);
547void EnvelopeEditor::setSustainY(
float y) {
548 if (sustain_slider_ ==
nullptr)
552 sustain_slider_->setValue(sustain_slider_->proportionOfLengthToValue(percent));
555void EnvelopeEditor::setReleaseX(
float x) {
556 if (release_slider_ ==
nullptr)
559 float time = (x - getSliderDecayX()) * window_time_ / getWidth();
561 window_time_ = std::max(window_time_, x * window_time_ / getWidth());
562 window_time_ = std::max(std::min(window_time_, kMaxWindowSize), kMinWindowSize);
566 delay_slider_ = delay_slider;
571 attack_slider_ = attack_slider;
576 hold_slider_ = hold_slider;
581 attack_power_slider_ = attack_power_slider;
586 decay_slider_ = decay_slider;
591 decay_power_slider_ = decay_power_slider;
596 sustain_slider_ = sustain_slider;
601 release_slider_ = release_slider;
606 release_power_slider_ = release_power_slider;
611 std::pair<vital::Output*, vital::Output*> outputs,
vital::poly_float default_value) {
612 if (!animate_ || !outputs.first->owner->enabled())
613 return default_value;
615 return outputs.first->trigger_value;
617 return outputs.first->trigger_value + outputs.second->trigger_value;
621 float delay_x = getDelayX(index);
622 float attack_x = getAttackX(index);
623 float hold_x = getHoldX(index);
624 float decay_x = getDecayX(index);
625 float release_x = getReleaseX(index);
630 float y = getAttackValue(t, index);
645 float y = getDecayValue(t, index);
653 float y = getReleaseValue(t, index);
659std::pair<float, float> EnvelopeEditor::getPosition(
int index) {
660 float phase = envelope_phase_->
value()[index];
663 return { -1.0f, -1.0f};
665 float delay_time = getDelayTime(index);
666 float attack_time = getAttackTime(index);
667 float hold_time = getHoldTime(index);
668 float decay_time = getDecayTime(index);
669 float release_time = getReleaseTime(index);
671 float stage_phase = phase - stage;
676 time = delay_time + stage_phase * attack_time;
677 value = getAttackValue(stage_phase, index);
680 time = delay_time + attack_time + stage_phase * hold_time;
684 time = delay_time + attack_time + hold_time + stage_phase * decay_time;
685 value = getDecayValue(stage_phase, index);
688 time = delay_time + attack_time + hold_time + decay_time + stage_phase * release_time;
689 value = getReleaseValue(stage_phase, index);
692 float x = 2.0f * time / window_time_ - 1.0f;
693 float y = 1.0 - 2.0f * value / getHeight();
694 return { padOpenGlX(x), padOpenGlY(y) };
697inline float EnvelopeEditor::padX(
float x) {
701inline float EnvelopeEditor::padY(
float y) {
705inline float EnvelopeEditor::unpadX(
float x) {
709inline float EnvelopeEditor::unpadY(
float y) {
713inline float EnvelopeEditor::padOpenGlX(
float x) {
717inline float EnvelopeEditor::padOpenGlY(
float y) {
723 drag_circle_.
init(open_gl);
724 hover_circle_.
init(open_gl);
725 grid_lines_.
init(open_gl);
726 sub_grid_lines_.
init(open_gl);
727 point_circles_.
init(open_gl);
728 power_circles_.
init(open_gl);
729 position_circle_.
init(open_gl);
732 times_[i]->
init(open_gl);
737 times_[i]->
render(open_gl, animate);
740 grid_lines_.
render(open_gl, animate);
741 sub_grid_lines_.
render(open_gl, animate);
760 bool animating = animate;
764 Colour envelope_graph_fill = fill_left_color_;
766 Colour envelope_graph_fill_fade = envelope_graph_fill.withMultipliedAlpha(1.0f - fill_fade);
767 Colour envelope_graph_fill_stereo = fill_right_color_;
768 Colour envelope_graph_fill_stereo_fade = envelope_graph_fill_stereo.withMultipliedAlpha(1.0f - fill_fade);
789 setFillColors(envelope_graph_fill_stereo_fade, envelope_graph_fill_stereo);
795 setFillColors(envelope_graph_fill_fade, envelope_graph_fill);
806 drawPosition(open_gl, 1);
807 drawPosition(open_gl, 0);
817 setFillColors(envelope_graph_fill_stereo_fade, envelope_graph_fill_stereo);
821 setFillColors(envelope_graph_fill_fade, envelope_graph_fill);
829 point_circles_.
setColor(line_center_color_);
831 point_circles_.
render(open_gl, animate);
833 power_circles_.
setColor(line_center_color_);
834 power_circles_.
render(open_gl, animate);
836 drag_circle_.
render(open_gl, animate);
837 hover_circle_.
render(open_gl, animate);
844 hover_circle_.
destroy(open_gl);
846 sub_grid_lines_.
destroy(open_gl);
847 point_circles_.
destroy(open_gl);
848 power_circles_.
destroy(open_gl);
849 position_circle_.
destroy(open_gl);
857void EnvelopeEditor::setEditingCircleBounds() {
858 float width = getWidth();
859 float height = getHeight();
860 float delay_x = padOpenGlX(getSliderDelayX() * 2.0f / width - 1.0f);
861 float attack_x = padOpenGlX(getSliderAttackX() * 2.0f / width - 1.0f);
862 float hold_x = padOpenGlX(getSliderHoldX() * 2.0f / width - 1.0f);
863 float decay_x = padOpenGlX(getSliderDecayX() * 2.0f / width - 1.0f);
864 float sustain_y = padOpenGlY(1.0f - getSliderSustainY() * 2.0f / height);
865 float release_x = padOpenGlX(getSliderReleaseX() * 2.0f / width - 1.0f);
866 float bottom = padOpenGlY(-1.0f);
867 float top = padOpenGlY(1.0f);
873 Point<float> grab_point(-10, -10);
875 grab_point = Point<float>(delay_x, bottom);
876 else if (release_hover_)
877 grab_point = Point<float>(release_x, bottom);
878 else if (sustain_hover_)
879 grab_point = Point<float>(decay_x, sustain_y);
880 else if (attack_hover_)
881 grab_point = Point<float>(attack_x, top);
882 else if (hold_hover_)
883 grab_point = Point<float>(hold_x, top);
884 else if (attack_power_hover_)
885 grab_point = Point<float>((delay_x + attack_x) / 2.0f, 1.0f - 2.0f * padY(getSliderAttackValue(0.5f)) / height);
886 else if (decay_power_hover_)
887 grab_point = Point<float>((hold_x + decay_x) / 2.0f, 1.0f - 2.0f * padY(getSliderDecayValue(0.5f)) / height);
888 else if (release_power_hover_)
889 grab_point = Point<float>((decay_x + release_x) / 2.0f, 1.0f - 2.0f * padY(getSliderReleaseValue(0.5f)) / height);
893 drag_circle_.
setQuad(0, grab_point.x - grab_width * 0.5f, grab_point.y - grab_height * 0.5f,
894 grab_width, grab_height);
897 drag_circle_.
setQuad(0, -2.0f, -2.0f, 0.0f, 0.0f);
900 hover_circle_.
setQuad(0, grab_point.x - hover_width * 0.5f, grab_point.y - hover_height * 0.5f,
901 hover_width, hover_height);
904void EnvelopeEditor::setTimePositions() {
905 static constexpr float kTimeDisplayBuffer = 0.025f;
906 static constexpr float kDrawWidth = 0.1f;
909 float current_division = floorf(powers);
910 float transition = powers - current_division;
915 float font_buffer = kTimeDisplayBuffer * getHeight();
916 float font_draw_height = font_height + font_buffer;
917 float font_y = getHeight() - font_draw_height;
918 float font_draw_width = getWidth() * kDrawWidth;
920 float width = getWidth();
922 float t = 1.0f - transition;
924 Colour big_color = background_color_.overlaidWith(lighten);
925 Colour little_color = background_color_.overlaidWith(lighten.withMultipliedAlpha(t * t));
927 for (; index * little_time_chunk < window_time_ && index <
kMaxTimesShown; ++index) {
929 times_[index]->setColor(little_color);
931 times_[index]->setColor(big_color);
933 float time = index * little_time_chunk;
934 int x = padX(width * time / window_time_);
935 String display = formatTime(time);
936 times_[index]->setText(display);
937 times_[index]->setVisible(
true);
938 times_[index]->setBounds(x + font_buffer, font_y, font_draw_width, font_draw_height);
939 times_[index]->redrawImage(
false);
942 times_[index]->setVisible(
false);
945void EnvelopeEditor::setGridPositions() {
947 float current_division = floorf(powers);
948 float transition = powers - current_division;
952 float width = getWidth();
954 float t = 1.0f - transition;
955 float line_width = 2.0f / width;
956 sub_grid_lines_.
setColor(time_color_.withMultipliedAlpha(t * t));
958 for (
int i = 1; i * little_time_chunk < window_time_; ++i) {
960 float time = i * little_time_chunk;
961 float x = padOpenGlX(2.0f * time / window_time_ - 1.0f);
962 sub_grid_lines_.
setQuad(sub_index, x, -1.0f, line_width, 2.0f);
970 for (
int i = 1; i * big_time_chunk < window_time_; ++i) {
971 float time = i * big_time_chunk;
972 float x = padOpenGlX(2.0f * time / window_time_ - 1.0f);
973 grid_lines_.
setQuad(index, x, -1.0f, line_width, 2.0f);
979void EnvelopeEditor::setPointPositions() {
980 float width = getWidth();
981 float height = getHeight();
983 float delay_x = padOpenGlX(getSliderDelayX() * 2.0f / width - 1.0f);
984 float attack_x = padOpenGlX(getSliderAttackX() * 2.0f / width - 1.0f);
985 float hold_x = padOpenGlX(getSliderHoldX() * 2.0f / width - 1.0f);
986 float decay_x = padOpenGlX(getSliderDecayX() * 2.0f / width - 1.0f);
987 float sustain_y = padOpenGlY(1.0f - getSliderSustainY() * 2.0f / height);
988 float release_x = padOpenGlX(getSliderReleaseX() * 2.0f / width - 1.0f);
989 float bottom = padOpenGlY(-1.0f);
990 float top = padOpenGlY(1.0f);
992 float marker_width = size_ratio_ * 2.0f *
kMarkerWidth / width;
993 float marker_height = size_ratio_ * 2.0f *
kMarkerWidth / height;
995 point_circles_.
setQuad(0, attack_x - marker_width * 0.5f, top - marker_height * 0.5f, marker_width, marker_height);
996 if (hold_x == attack_x)
997 point_circles_.
setQuad(1, -2.0f, -2.0f, 0.0f, 0.0f);
999 point_circles_.
setQuad(1, hold_x - marker_width * 0.5f, top - marker_height * 0.5f, marker_width, marker_height);
1001 point_circles_.
setQuad(2, decay_x - marker_width * 0.5f, sustain_y - marker_height * 0.5f,
1002 marker_width, marker_height);
1003 point_circles_.
setQuad(3, release_x - marker_width * 0.5f, bottom - marker_height * 0.5f,
1004 marker_width, marker_height);
1009 if (attack_x - delay_x > min_power_distance) {
1010 float power_attack_x = (delay_x + attack_x) * 0.5;
1011 float power_attack_y = padOpenGlY(1.0f - getSliderAttackValue(0.5f) * 2.0f / height);
1012 power_circles_.
setQuad(0, power_attack_x - power_width * 0.5f, power_attack_y - power_height * 0.5f,
1013 power_width, power_height);
1016 power_circles_.
setQuad(0, -2.0f, -2.0f, power_width, power_height);
1018 if (decay_x - hold_x > min_power_distance && sustain_y < top) {
1019 float power_decay_x = (hold_x + decay_x) * 0.5;
1020 float power_decay_y = padOpenGlY(1.0f - getSliderDecayValue(0.5f) * 2.0f / height);
1021 power_circles_.
setQuad(1, power_decay_x - power_width * 0.5f, power_decay_y - power_height * 0.5f,
1022 power_width, power_height);
1025 power_circles_.
setQuad(1, -2.0f, -2.0f, 0.0f, 0.0f);
1027 if (release_x - decay_x > min_power_distance && sustain_y > bottom) {
1028 float power_release_x = (decay_x + release_x) * 0.5;
1029 float power_release_y = padOpenGlY(1.0f - getSliderReleaseValue(0.5f) * 2.0f / height);
1030 power_circles_.
setQuad(2, power_release_x - power_width * 0.5f, power_release_y - power_height * 0.5f,
1031 power_width, power_height);
1034 power_circles_.
setQuad(2, -2.0f, -2.0f, 0.0f, 0.0f);
1037void EnvelopeEditor::setGlPositions() {
1038 if (!reset_positions_)
1041 reset_positions_ =
false;
1043 setEditingCircleBounds();
1045 setPointPositions();
1048void EnvelopeEditor::setColors() {
1061void EnvelopeEditor::drawPosition(
OpenGlWrapper& open_gl,
int index) {
1062 static constexpr float kMinPositionAlphaDecay = 0.9f;
1063 static constexpr float kCenterFade = 0.2f;
1064 if (envelope_phase_ ==
nullptr)
1067 std::pair<float, float> position = getPosition(index);
1068 float current_alpha = current_position_alpha_[index];
1069 float x = position.first;
1070 float y = position.second;
1072 current_position_alpha_.
set(index, 1.0f);
1074 float release = getOutputsTotal(release_outputs_, release_slider_->getValue())[index];
1076 current_position_alpha_.
set(index, current_position_alpha_[index] * std::min(kMinPositionAlphaDecay, release));
1079 if (current_alpha == 0.0f)
1083 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1085 float current_phase = envelope_phase_->
value()[index];
1086 if (current_phase <= vital::kVoiceKill && current_phase >=
vital::kVoiceOn) {
1087 float width = getWidth();
1088 float height = getHeight();
1089 float marker_width = size_ratio_ * 2.0f *
kMarkerWidth / width;
1090 float marker_height = size_ratio_ * 2.0f *
kMarkerWidth / height;
1092 position_circle_.
setQuad(0, x - marker_width * 0.5f, y - marker_height * 0.5f, marker_width, marker_height);
1095 float current_position_alpha = current_position_alpha_[index];
1096 float mult = std::max(current_position_alpha, 0.0f);
1100 color = line_right_color_;
1102 color = line_left_color_;
1104 Colour alt_color =
color.interpolatedWith(background_color_, kCenterFade);
1107 position_circle_.
setAltColor(alt_color.withMultipliedAlpha(mult));
1108 position_circle_.
render(open_gl,
true);
void setDecayPowerSlider(SynthSlider *decay_slider)
Definition envelope_editor.cpp:590
void parentHierarchyChanged() override
Called when the component’s parent hierarchy changes.
Definition envelope_editor.cpp:105
void mouseDrag(const MouseEvent &e) override
Definition envelope_editor.cpp:204
void mouseWheelMove(const MouseEvent &e, const MouseWheelDetails &wheel) override
Handles mouse wheel events for zooming.
Definition envelope_editor.cpp:244
void setAttackPowerSlider(SynthSlider *attack_slider)
Definition envelope_editor.cpp:580
void resetEnvelopeLine(int index)
Resets the envelope line for a given voice index.
Definition envelope_editor.cpp:620
static constexpr float kRingThickness
Thickness fraction for the marker rings.
Definition envelope_editor.h:24
void render(OpenGlWrapper &open_gl, bool animate) override
Renders the envelope using OpenGL.
Definition envelope_editor.cpp:735
static constexpr int kNumPointsPerSection
Number of points per envelope section.
Definition envelope_editor.h:51
static constexpr float kTailDecay
Decay factor for tail end animations.
Definition envelope_editor.h:32
~EnvelopeEditor()
Destructor.
Definition envelope_editor.cpp:96
void setHoldSlider(SynthSlider *hold_slider)
Definition envelope_editor.cpp:575
void setSustainSlider(SynthSlider *sustain_slider)
Definition envelope_editor.cpp:595
void init(OpenGlWrapper &open_gl) override
Initializes OpenGL resources.
Definition envelope_editor.cpp:721
void mouseMove(const MouseEvent &e) override
Mouse event callbacks for interactions.
Definition envelope_editor.cpp:181
static constexpr float kTimeDisplaySize
Display size ratio for time text.
Definition envelope_editor.h:42
void mouseDown(const MouseEvent &e) override
Definition envelope_editor.cpp:198
void setDecaySlider(SynthSlider *decay_slider)
Definition envelope_editor.cpp:585
static constexpr float kPaddingX
Horizontal padding ratio for the display.
Definition envelope_editor.h:34
EnvelopeEditor(const String &prefix, const vital::output_map &mono_modulations, const vital::output_map &poly_modulations)
Constructs an EnvelopeEditor.
Definition envelope_editor.cpp:29
static constexpr float kMarkerGrabRadius
Radius in pixels for grabbing markers.
Definition envelope_editor.h:30
static constexpr int kMaxTimesShown
Maximum number of time markers shown.
Definition envelope_editor.h:49
void mouseDoubleClick(const MouseEvent &e) override
Definition envelope_editor.cpp:230
void setReleasePowerSlider(SynthSlider *release_slider)
Definition envelope_editor.cpp:605
void guiChanged(SynthSlider *slider) override
Called when a slider value changes.
Definition envelope_editor.cpp:272
void magnifyZoom(Point< float > delta)
Zooms the envelope display via magnification (e.g., pinch gestures).
Definition envelope_editor.cpp:250
void mouseUp(const MouseEvent &e) override
Definition envelope_editor.cpp:239
void setReleaseSlider(SynthSlider *release_slider)
Definition envelope_editor.cpp:600
void pickHoverPosition(Point< float > position)
Determines hover state based on mouse position.
Definition envelope_editor.cpp:119
void setAttackSlider(SynthSlider *attack_slider)
Definition envelope_editor.cpp:570
static constexpr float kMarkerWidth
Width in pixels of the main markers (ADHSR points).
Definition envelope_editor.h:22
static constexpr float kPowerMouseMultiplier
Multiplier for mouse movements when adjusting power.
Definition envelope_editor.h:40
void magnifyReset()
Resets the magnification zoom to a default level.
Definition envelope_editor.cpp:256
static constexpr float kMinPointDistanceForPower
Minimum point distance for enabling power handle editing.
Definition envelope_editor.h:38
void setDelaySlider(SynthSlider *delay_slider)
Sets the sliders corresponding to different envelope parameters.
Definition envelope_editor.cpp:565
void resetPositions()
Flags that the positions need to be reset and recalculated.
Definition envelope_editor.h:188
void destroy(OpenGlWrapper &open_gl) override
Destroys the OpenGL resources.
Definition envelope_editor.cpp:842
void mouseExit(const MouseEvent &e) override
Definition envelope_editor.cpp:186
void paintBackground(Graphics &g) override
Paints the background of the editor.
Definition envelope_editor.cpp:98
static constexpr int kRulerDivisionSize
Division size for major time ruler lines.
Definition envelope_editor.h:45
static constexpr float kMarkerHoverRadius
Radius in pixels for hovering detection over markers.
Definition envelope_editor.h:28
static constexpr float kPaddingY
Vertical padding ratio for the display.
Definition envelope_editor.h:36
static constexpr float kPowerMarkerWidth
Width in pixels of the power markers (for adjusting curve power).
Definition envelope_editor.h:26
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
const vital::StatusOutput * num_voices_readout_
StatusOutput for voice count lookups.
Definition open_gl_component.h:258
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
void setBackgroundColor(const Colour &color)
Sets the background color of the component for painting operations.
Definition open_gl_component.h:242
virtual void paintBackground(Graphics &g)
Paints a standard background for the component.
Definition open_gl_component.cpp:105
virtual void parentHierarchyChanged() override
Called when the component's parent hierarchy changes.
Definition open_gl_component.cpp:128
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 void setFillCenter(float fill_center)
Sets the vertical center for the fill area.
Definition open_gl_line_renderer.h:138
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
void decayBoosts(vital::poly_float mult)
Decays all boosts by a multiplicative factor, allowing animated damping.
Definition open_gl_line_renderer.cpp:185
force_inline void setFillBoostAmount(float boost_amount)
Sets the boost amount that affects fill thickness.
Definition open_gl_line_renderer.h:147
force_inline void setBoostAmount(float boost_amount)
Sets the boost amount that affects line thickness.
Definition open_gl_line_renderer.h:144
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
bool anyBoostValue()
Checks if any boost value is set.
Definition open_gl_line_renderer.h:202
force_inline void setLineWidth(float width)
Sets the line width in pixels.
Definition open_gl_line_renderer.h:66
force_inline void setColor(Colour color)
Sets the line color.
Definition open_gl_line_renderer.h:63
void boostRange(float *boosts, float start, float end, int buffer_vertices, float min)
Boosts a range for the given boost array.
Definition open_gl_line_renderer.cpp:128
void drawLines(OpenGlWrapper &open_gl, bool left)
Draws the line and optional fill using OpenGL.
Definition open_gl_line_renderer.cpp:386
force_inline void setIndex(int index)
Sets an index used for custom behavior (e.g., multiple line sets).
Definition open_gl_line_renderer.h:150
force_inline Colour color() const
Gets the current line color.
Definition open_gl_line_renderer.h:189
void enableBackwardBoost(bool enable)
Enables backward boost calculation for symmetrical line deformation.
Definition open_gl_line_renderer.h:183
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 setNumQuads(int num_quads)
Sets how many quads will actually be drawn (up to max_quads).
Definition open_gl_multi_quad.h:92
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
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
@ kWidgetLineBoost
Definition skin.h:106
@ kWidgetFillBoost
Definition skin.h:109
@ kWidgetAccent1
Definition skin.h:171
@ kWidgetPrimary2
Definition skin.h:166
@ kWidgetPrimary1
Definition skin.h:165
@ kWidgetBackground
Definition skin.h:173
@ kWidgetSecondary1
Definition skin.h:168
@ kLightenScreen
Definition skin.h:141
@ kWidgetCenterLine
Definition skin.h:164
@ kWidgetSecondary2
Definition skin.h:169
@ kWidgetAccent2
Definition skin.h:172
bool isModSourceEnabled(const std::string &source)
Checks if a modulation source is currently enabled.
Definition synth_base.cpp:223
const vital::StatusOutput * getStatusOutput(const std::string &name)
Retrieves a status output by name.
Definition synth_base.cpp:262
SynthBase * getSynth()
Returns the SynthBase instance this interface is managing.
Definition synth_gui_interface.h:85
A specialized slider with extended functionality for modulation, parameter control,...
Definition synth_slider.h:314
double getAdjustedValue(double value)
Definition synth_slider.cpp:430
void addSliderListener(SliderListener *listener)
Definition synth_slider.cpp:631
void setValueFromAdjusted(double value)
Definition synth_slider.cpp:495
force_inline bool isClearValue(poly_float value) const
Checks if a given poly_float is the special "clear" value.
Definition synth_module.h:81
force_inline poly_float value() const
Returns the current status value.
Definition synth_module.h:49
force_inline mono_float powerScale(mono_float value, mono_float power)
A power-scaling function to map a linear range to a curved response.
Definition futils.h:455
force_inline poly_float clamp(poly_float value, mono_float min, mono_float max)
Clamps each lane of a vector to [min, max].
Definition poly_utils.h:306
force_inline poly_float min(poly_float left, poly_float right)
Returns the minimum of two poly_floats lane-by-lane.
Definition poly_utils.h:334
force_inline poly_float max(poly_float left, poly_float right)
Returns the maximum of two poly_floats lane-by-lane.
Definition poly_utils.h:327
force_inline poly_float maskLoad(poly_float zero_value, poly_float one_value, poly_mask reset_mask)
Selects between two values (zero_value or one_value) based on a mask in each lane.
Definition poly_utils.h:351
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
@ kVoiceOn
Definition common.h:77
@ kVoiceKill
Definition common.h:81
@ kVoiceDecay
Definition common.h:79
@ kVoiceHold
Definition common.h:78
@ kVoiceOff
Definition common.h:80
constexpr int kMsPerSec
Milliseconds per second.
Definition common.h:50
std::map< std::string, Output * > output_map
Maps parameter names to Output pointers, representing output signals from various modules.
Definition synth_types.h:229
A helper struct containing references to OpenGL context, shaders, and display scale.
Definition shaders.h:174
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
static force_inline poly_mask vector_call lessThan(poly_float one, poly_float two)
Definition poly_values.h:1105
force_inline void vector_call set(size_t index, float new_value) noexcept
Sets a specific element in the SIMD register.
Definition poly_values.h:1182
static force_inline mask_simd_type vector_call greaterThan(simd_type one, simd_type two)
Compares two SIMD float registers, element-wise, for greater than.
Definition poly_values.h:971
Represents a vector of integer values using SIMD instructions.
Definition poly_values.h:56
Provides various utility functions, classes, and constants for audio, math, and general-purpose opera...