Vital
Loading...
Searching...
No Matches
lfo_editor.cpp
Go to the documentation of this file.
1#include "lfo_editor.h"
2
4#include "skin.h"
5#include "shaders.h"
7#include "synth_section.h"
8#include "utils.h"
9
10LfoEditor::LfoEditor(LineGenerator* lfo_source, String prefix,
11 const vital::output_map& mono_modulations,
12 const vital::output_map& poly_modulations) : LineEditor(lfo_source) {
13 parent_ = nullptr;
14 wave_phase_ = nullptr;
15 frequency_ = nullptr;
16 last_phase_ = 0.0f;
17
18 setFill(true);
19 setFillCenter(-1.0f);
20 setName(prefix);
21
22 last_voice_ = -1.0f;
23}
24
26
28 parent_ = findParentComponentOfClass<SynthGuiInterface>();
29
30 if (wave_phase_ == nullptr && parent_)
31 wave_phase_ = parent_->getSynth()->getStatusOutput(getName().toStdString() + "_phase");
32
33 if (frequency_ == nullptr && parent_)
34 frequency_ = parent_->getSynth()->getStatusOutput(getName().toStdString() + "_frequency");
35
37}
38
39void LfoEditor::mouseDown(const MouseEvent& e) {
40 if (e.mods.isPopupMenu()) {
41 PopupItems options;
42
43 int active_point = getActivePoint();
44 if (active_point >= 0) {
45 options.addItem(kSetPhaseToPoint, "Set Start Point");
46 if (active_point >= 1 && active_point < getModel()->getNumPoints() - 1) {
47 options.addItem(kRemovePoint, "Remove Point");
48 options.addItem(kEnterPhase, "Enter Point Phase");
49 }
50
51 options.addItem(kEnterValue, "Enter Point Value");
52 options.addItem(-1, "");
53 }
54 else if (getActivePower() >= 0) {
55 options.addItem(kSetPhaseToPower, "Set Start Point");
56 options.addItem(kResetPower, "Reset Power");
57 options.addItem(-1, "");
58 }
59 else if (getActiveGridSection() >= 0)
60 options.addItem(kSetPhaseToGrid, "Set Start Point");
61
62 options.addItem(kCopy, "Copy");
64 options.addItem(kPaste, "Paste");
65
66 options.addItem(kSave, "Save to LFOs");
67
68 options.addItem(kFlipHorizontal, "Flip Horizontal");
69 options.addItem(kFlipVertical, "Flip Vertical");
70
71 options.addItem(kImportLfo, "Import LFO");
72 options.addItem(kExportLfo, "Export LFO");
73
74 SynthSection* parent = findParentComponentOfClass<SynthSection>();
75 int point = active_point;
76 int power = getActivePower();
77 parent->showPopupSelector(this, e.getPosition(), options,
78 [=](int selection) { respondToCallback(point, power, selection); });
79 }
80 else
82}
83
84void LfoEditor::mouseDoubleClick(const MouseEvent& e) {
85 if (!e.mods.isPopupMenu())
87}
88
89void LfoEditor::mouseUp(const MouseEvent& e) {
90 if (!e.mods.isPopupMenu())
92}
93
94void LfoEditor::respondToCallback(int point, int power, int result) {
95 if (result == kSetPhaseToPoint) {
96 if (point >= 0 && point < numPoints())
97 setPhase(getModel()->getPoint(point).first);
98 }
99 else if (result == kSetPhaseToPower) {
100 if (power >= 0 && power < numPoints() - 1) {
101 float from = getModel()->getPoint(power).first;
102 float to = getModel()->getPoint(power + 1).first;
103 setPhase((from + to) / 2.0f);
104 }
105 }
106 else if (result == kSetPhaseToGrid) {
107 int section = getActiveGridSection();
108 int grid_size = getGridSizeX();
109 if (section >= 0 && grid_size > 0)
110 setPhase(section * 1.0f / grid_size);
111 }
112 else if (result == kImportLfo) {
113 for (Listener* listener : listeners_)
114 listener->importLfo();
115 }
116 else if (result == kExportLfo) {
117 for (Listener* listener : listeners_)
118 listener->exportLfo();
119 }
120 else
121 LineEditor::respondToCallback(point, power, result);
122
124}
125
126void LfoEditor::setPhase(float phase) {
127 for (Listener* listener : listeners_)
128 listener->setPhase(phase);
129}
130
131void LfoEditor::render(OpenGlWrapper& open_gl, bool animate) {
132 // The rendering code sets up the LFO curve and the animated position indicator.
133 // It applies smoothing (boost and decay) to changes in phase and amplitude.
134 // The LFO curve is drawn along with optional stereo variations.
135
136 static constexpr float kBackupTime = 1.0f / 50.0f;
137
139 renderGrid(open_gl, animate);
140
141 vital::poly_float encoded_phase = wave_phase_->value();
142 vital::poly_mask inactive_mask = 0;
143 if (wave_phase_->isClearValue(encoded_phase)) {
144 encoded_phase = 0.0f;
145 inactive_mask = vital::constants::kFullMask;
146 }
147
148 vital::poly_float frequency = frequency_->value();
149 if (frequency_->isClearValue(frequency))
150 frequency = 0.0f;
151
152 std::pair<vital::poly_float, vital::poly_float> decoded = vital::utils::decodePhaseAndVoice(encoded_phase);
153 vital::poly_float phase = decoded.first;
154 vital::poly_float voice = decoded.second;
155
156 vital::poly_float phase_delta = vital::poly_float::abs(phase - last_phase_);
157 vital::poly_float decay = vital::poly_float(1.0f) - phase_delta * kSpeedDecayMult;
158 decay = vital::utils::clamp(decay, kBoostDecay, 1.0f);
159 decay = vital::utils::maskLoad(decay, kBoostDecay, inactive_mask);
160 decayBoosts(decay);
161
162 vital::poly_mask switch_mask = vital::poly_float::notEqual(voice, last_voice_) | inactive_mask;
163 vital::poly_float phase_reset = vital::utils::max(0.0f, phase - frequency * kBackupTime);
164 last_phase_ = vital::utils::maskLoad(last_phase_, phase_reset, switch_mask);
165
166 bool animating = animate;
167 if (parent_)
168 animating = animating && parent_->getSynth()->isModSourceEnabled(getName().toStdString());
169
170 if (animating)
171 boostRange(adjustBoostPhase(last_phase_), adjustBoostPhase(phase), kNumWrapPoints, decay);
172 else
173 decayBoosts(0.0f);
174
175 last_phase_ = phase;
176 last_voice_ = voice;
177
180
181 Colour fill_color = findColour(Skin::kWidgetSecondary1, true);
182 float fill_fade = findValue(Skin::kWidgetFillFade);
183 Colour fill_color_fade = fill_color.withMultipliedAlpha(1.0f - fill_fade);
184 Colour position_color = findColour(Skin::kWidgetPrimary1, true);
185
186 Colour fill_color_stereo = findColour(Skin::kWidgetSecondary2, true);
187 Colour fill_color_stereo_fade = fill_color_stereo.withMultipliedAlpha(1.0f - fill_fade);
188 Colour position_color_stereo = findColour(Skin::kWidgetPrimary2, true);
189
190 if (animating) {
191 // Drawing the animated LFO lines and positions.
192 setFill(true);
195
196 setIndex(1);
197 setColor(findColour(Skin::kWidgetPrimary2, true));
198 setFillColors(fill_color_stereo_fade, fill_color_stereo);
199 drawLines(open_gl, false);
200
201 setIndex(0);
202 setColor(findColour(Skin::kWidgetPrimary1, true));
203 setFillColors(fill_color_fade, fill_color);
204 drawLines(open_gl, anyBoostValue());
205
206 setBoostAmount(0.0f);
207 setFill(false);
208 setColor(findColour(Skin::kWidgetCenterLine, true));
209 drawLines(open_gl, anyBoostValue());
210
211 setViewPort(open_gl);
212 if (switch_mask.sum() == 0) {
213 drawPosition(open_gl, position_color_stereo, phase[1]);
214 drawPosition(open_gl, position_color, phase[0]);
215 }
216 }
217 else {
218 // Drawing the static LFO lines without animation.
219 setBoostAmount(0.0f);
220 setFillBoostAmount(0.0f);
221 setFill(true);
222
223 setColor(findColour(Skin::kWidgetPrimary2, true));
224 setFillColors(fill_color_stereo_fade, fill_color_stereo);
225 drawLines(open_gl, false);
226
227 setColor(findColour(Skin::kWidgetPrimary1, true));
228 setFillColors(fill_color_fade, fill_color);
229 drawLines(open_gl, false);
230
231 setFill(false);
232 setColor(findColour(Skin::kWidgetCenterLine, true));
233 drawLines(open_gl, false);
234 }
235
236 renderPoints(open_gl, animate);
237 renderCorners(open_gl, animate);
238}
virtual void mouseDown(const MouseEvent &e) override
Handles mouse down events.
Definition lfo_editor.cpp:39
void render(OpenGlWrapper &open_gl, bool animate) override
Renders the LFO editor using OpenGL.
Definition lfo_editor.cpp:131
static constexpr float kSpeedDecayMult
Multiplier for adjusting boost decay speed depending on phase changes.
Definition lfo_editor.h:28
void parentHierarchyChanged() override
Called when the component’s parent hierarchy changes.
Definition lfo_editor.cpp:27
virtual ~LfoEditor()
Destructor.
Definition lfo_editor.cpp:25
LfoEditor(LineGenerator *lfo_source, String prefix, const vital::output_map &mono_modulations, const vital::output_map &poly_modulations)
Constructs the LfoEditor.
Definition lfo_editor.cpp:10
@ kExportLfo
Menu option to export the current LFO shape to file.
Definition lfo_editor.h:35
@ kSetPhaseToPoint
Menu option to set the LFO start phase to a point’s phase.
Definition lfo_editor.h:31
@ kSetPhaseToPower
Menu option to set the LFO start phase to a segment midpoint.
Definition lfo_editor.h:32
@ kImportLfo
Menu option to import an LFO shape from file.
Definition lfo_editor.h:34
@ kSetPhaseToGrid
Menu option to set the LFO start phase to a grid division.
Definition lfo_editor.h:33
void setPhase(float phase)
Sets the LFO’s start phase.
Definition lfo_editor.cpp:126
virtual void mouseDoubleClick(const MouseEvent &e) override
Handles mouse double-click events.
Definition lfo_editor.cpp:84
static constexpr float kBoostDecay
Decay factor used when reducing boost intensity over time.
Definition lfo_editor.h:25
void respondToCallback(int point, int power, int result) override
Responds to selection callbacks from the popup menu.
Definition lfo_editor.cpp:94
virtual void mouseUp(const MouseEvent &e) override
Handles mouse up events.
Definition lfo_editor.cpp:89
Interface for classes that want to receive notifications about line editor changes.
Definition line_editor.h:86
A GUI component for editing and visualizing a user-defined line shape (curve or envelope).
Definition line_editor.h:27
void clearActiveMouseActions()
Definition line_editor.cpp:634
vital::poly_float adjustBoostPhase(vital::poly_float phase)
Adjusts a given phase value for boost calculations.
Definition line_editor.cpp:1061
void renderGrid(OpenGlWrapper &open_gl, bool animate)
Renders the grid lines that show snapping lines or painting sections.
Definition line_editor.cpp:763
virtual void mouseUp(const MouseEvent &e) override
Definition line_editor.cpp:603
virtual void mouseDoubleClick(const MouseEvent &e) override
Definition line_editor.cpp:517
LineGenerator * getModel()
Gets the current LineGenerator model.
Definition line_editor.h:357
bool hasMatchingSystemClipboard()
Checks if the system clipboard contains a compatible line data JSON.
Definition line_editor.cpp:353
int getActivePower()
Gets the currently active power handle index.
Definition line_editor.h:450
@ kFlipHorizontal
Definition line_editor.h:77
@ kRemovePoint
Definition line_editor.h:75
@ kSave
Definition line_editor.h:71
@ kEnterValue
Definition line_editor.h:73
@ kResetPower
Definition line_editor.h:74
@ kEnterPhase
Definition line_editor.h:72
@ kCopy
Definition line_editor.h:69
@ kPaste
Definition line_editor.h:70
@ kFlipVertical
Definition line_editor.h:78
static constexpr int kNumWrapPoints
Number of wrap points for looping lines.
Definition line_editor.h:43
void setGlPositions()
Updates OpenGL buffers with the latest positions if needed.
Definition line_editor.cpp:963
virtual void respondToCallback(int point, int power, int option)
Responds to a callback triggered by a menu option or action.
Definition line_editor.cpp:287
void drawPosition(OpenGlWrapper &open_gl, Colour color, float fraction_x)
Draws a position marker at a specific fraction of the X-axis.
Definition line_editor.cpp:838
int getActivePoint()
Gets the currently active point index.
Definition line_editor.h:444
int getGridSizeX()
Gets the current horizontal grid size.
Definition line_editor.h:341
int getActiveGridSection()
Gets the currently active grid section index for painting.
Definition line_editor.h:456
void renderPoints(OpenGlWrapper &open_gl, bool animate)
Renders the points and power handles on the curve.
Definition line_editor.cpp:768
virtual void mouseDown(const MouseEvent &e) override
Definition line_editor.cpp:455
std::vector< Listener * > listeners_
Definition line_editor.h:482
A class for generating and storing a line shape, defined by a series of points and associated powers.
Definition line_generator.h:20
force_inline std::pair< float, float > getPoint(int index) const
Returns a point at the given index.
Definition line_generator.h:306
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
void renderCorners(OpenGlWrapper &open_gl, bool animate, Colour color, float rounding)
Renders the corner shapes using the given color and rounding amount.
Definition open_gl_component.cpp:153
float findValue(Skin::ValueId value_id)
Finds a float value from the skin associated with this component's parent.
Definition open_gl_component.cpp:173
virtual void parentHierarchyChanged() override
Called when the component's parent hierarchy changes.
Definition open_gl_component.cpp:128
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 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 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
force_inline int numPoints() const
Gets the number of points in the line.
Definition open_gl_line_renderer.h:186
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
@ 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
@ kWidgetPrimary2
Definition skin.h:166
@ kWidgetPrimary1
Definition skin.h:165
@ kWidgetSecondary1
Definition skin.h:168
@ kWidgetCenterLine
Definition skin.h:164
@ kWidgetSecondary2
Definition skin.h:169
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
Base class for all synthesizer sections, providing UI layout, painting, and interaction logic.
Definition synth_section.h:193
void showPopupSelector(Component *source, Point< int > position, const PopupItems &options, std::function< void(int)> callback, std::function< void()> cancel={ })
Shows a popup selector with options.
Definition synth_section.cpp:119
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
const poly_mask kFullMask
A mask covering all lanes of a poly_float vector.
Definition synth_constants.h:257
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 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 std::pair< poly_float, poly_float > decodePhaseAndVoice(poly_float encoded)
Decodes a phase and voice from an encoded float, returning (phase, voice).
Definition poly_utils.h:987
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
A hierarchical structure of popup menu items for a selector component.
Definition synth_section.h:29
void addItem(int sub_id, const std::string &sub_name, bool sub_selected=false)
Adds a new item as a submenu entry.
Definition synth_section.h:51
Represents a vector of floating-point values using SIMD instructions.
Definition poly_values.h:600
static force_inline simd_type vector_call abs(simd_type value)
Computes the absolute value of each element in the SIMD float register.
Definition poly_values.h:935
static force_inline mask_simd_type vector_call notEqual(simd_type one, simd_type two)
Compares two SIMD float registers for non-equality, element-wise.
Definition poly_values.h:1003
Represents a vector of integer values using SIMD instructions.
Definition poly_values.h:56
static force_inline uint32_t vector_call sum(simd_type value)
Computes the sum of all elements in a SIMD integer register.
Definition poly_values.h:326
Provides various utility functions, classes, and constants for audio, math, and general-purpose opera...