17 if (editor ==
nullptr)
33 grid_circles_(kNumCircles,
Shaders::kCircleFragment), hover_circle_(
Shaders::kCircleFragment), editing_line_(2) {
37 hover_circle_.
setQuad(0, -2.0f, -2.0f, 0.0f, 0.0f);
38 addAndMakeVisible(&editing_line_);
39 editing_line_.setInterceptsMouseClicks(
false,
false);
46 dragging_audio_file_ =
false;
48 values_ = std::make_unique<float[]>(size);
50 current_mouse_position_ = Point<int>(INT_MAX / 2, INT_MAX / 2);
61 grid_circles_.
setColor(lighten.withMultipliedAlpha(0.5f));
67 float width = getWidth();
74 setXAt(i, i * width / (num_points - 1.0f));
79 editing_line_.setBounds(getLocalBounds());
84 current_mouse_position_ = e.getPosition();
85 if (e.mods.isPopupMenu()) {
91 SynthSection* parent = findParentComponentOfClass<SynthSection>();
93 [=](
int selection) { waveSourceCallback(selection, this); });
96 last_edit_position_ = getSnappedPoint(current_mouse_position_);
99 editing_line_.
setXAt(0, last_edit_position_.x);
100 editing_line_.
setYAt(0, last_edit_position_.y);
101 editing_line_.
setXAt(1, current_mouse_position_.x);
102 editing_line_.
setYAt(1, current_mouse_position_.y);
109 current_mouse_position_ = e.getPosition();
110 int index = getHoveredIndex(snapToGrid(current_mouse_position_));
112 for (
Listener* listener : listeners_)
113 listener->valuesChanged(index, index,
true);
117 current_mouse_position_ = e.getPosition();
122 current_mouse_position_ = e.getPosition();
124 last_edit_position_ = snapToGrid(current_mouse_position_);
126 editing_line_.
setXAt(0, last_edit_position_.x);
127 editing_line_.
setYAt(0, last_edit_position_.y);
128 editing_line_.
setXAt(1, current_mouse_position_.x);
129 editing_line_.
setYAt(1, current_mouse_position_.y);
133 current_mouse_position_ = Point<int>(-getWidth(), 0);
137int WaveSourceEditor::getHoveredIndex(Point<int> position) {
138 int index = floorf(
numPoints() * (1.0f * position.x) / getWidth());
142float WaveSourceEditor::getSnapRadius() {
143 static float kGridProximity = 0.2f;
145 if (horizontal_grid_ == 0 || vertical_grid_ == 0)
148 float grid_cell_width = getWidth() / (1.0f * horizontal_grid_);
149 float grid_cell_height = getHeight() / (1.0f * vertical_grid_);
150 return kGridProximity * std::min(grid_cell_height, grid_cell_width);
153void WaveSourceEditor::setLineValues() {
154 float adjust = getHeight() / 2.0f;
156 setYAt(i, adjust * (1.0f - values_[i]));
159void WaveSourceEditor::changeValues(
const MouseEvent& e) {
160 Point<int> mouse_position = snapToGrid(e.getPosition());
161 int from_index = getHoveredIndex(last_edit_position_);
162 int selected_index = getHoveredIndex(mouse_position);
164 float x = mouse_position.x;
165 float y = mouse_position.y;
166 float x_delta = last_edit_position_.x - x;
167 float y_delta = last_edit_position_.y - y;
168 float slope = y_delta == 0 ? 0 : y_delta / x_delta;
169 float next_x = getWidth() * (1.0f * selected_index) /
numPoints();
172 if (selected_index < from_index) {
174 next_x += getWidth() * 1.0f /
numPoints();
176 float inc_x = next_x - x;
178 for (
int index = selected_index; index != from_index + direction; index += direction) {
180 float new_value = -2.0f * y / getHeight() + 1.0f;
185 inc_x = direction * getWidth() * 1.0f /
numPoints();
190 int min_index = std::min(from_index, selected_index);
191 int max_index = std::max(from_index, selected_index);
193 for (Listener* listener : listeners_)
194 listener->valuesChanged(min_index, max_index,
false);
197Point<int> WaveSourceEditor::getSnappedPoint(Point<int> input) {
198 if (horizontal_grid_ == 0 || vertical_grid_ == 0)
201 float x = horizontal_grid_ * (1.0f * input.x) / getWidth();
202 float y = vertical_grid_ * (1.0f * input.y) / getHeight();
203 float snapped_x = getWidth() * std::roundf(x) / horizontal_grid_;
204 float snapped_y = getHeight() * std::roundf(y) / vertical_grid_;
205 return Point<int>(snapped_x, snapped_y);
208Point<int> WaveSourceEditor::snapToGrid(Point<int> input) {
209 Point<int> snapped = getSnappedPoint(input);
211 if (input.getDistanceFrom(snapped) > getSnapRadius())
212 return last_edit_position_;
219 values_[i] = waveform[i];
225 setInterceptsMouseClicks(editable, editable);
226 editable_ = editable;
230 horizontal_grid_ = horizontal;
231 vertical_grid_ = vertical;
235void WaveSourceEditor::setGridPositions() {
236 float pixel_height = 2.0f / getHeight();
237 float pixel_width = 2.0f / getWidth();
240 for (
int i = 1; i < horizontal_grid_; ++i) {
241 grid_lines_.
setQuad(grid_index, i * 2.0f / horizontal_grid_ - 1.0f, -1.0f, pixel_width, 2.0f);
245 for (
int i = 1; i < vertical_grid_; ++i) {
246 grid_lines_.
setQuad(grid_index, -1.0f, i * 2.0f / vertical_grid_ - 1.0f, 2.0f, pixel_height);
251 int circle_index = 0;
252 float circle_radius_x = getSnapRadius() * 2.0f / getWidth();
253 float circle_radius_y = getSnapRadius() * 2.0f / getHeight();
254 for (
int h = 0; h <= horizontal_grid_; ++h) {
255 for (
int v = 0; v <= vertical_grid_; ++v) {
256 float x = h * 2.0f / horizontal_grid_ - 1.0f;
257 float y = v * 2.0f / vertical_grid_ - 1.0f;
259 grid_circles_.
setQuad(circle_index, x - circle_radius_x, y - circle_radius_y,
260 circle_radius_x * 2.0f, circle_radius_y * 2.0f);
269void WaveSourceEditor::setHoverPosition() {
270 float circle_radius_x = getSnapRadius() * 2.0f / getWidth();
271 float circle_radius_y = getSnapRadius() * 2.0f / getHeight();
275 position = last_edit_position_;
277 position = getSnappedPoint(current_mouse_position_);
278 hover_circle_.
setQuad(0, position.x * 2.0f / getWidth() - 1.0f - circle_radius_x,
279 1.0f - position.y * 2.0f / getHeight() - circle_radius_y,
280 2.0f * circle_radius_x, 2.0f * circle_radius_y);
284 dragging_audio_file_ =
false;
288 dragging_audio_file_ =
true;
292 dragging_audio_file_ =
false;
296 for (
int index = 0; index <
numPoints(); ++index)
297 values_[index] = 0.0f;
301 for (
Listener* listener : listeners_)
302 listener->valuesChanged(0,
numPoints() - 1,
true);
306 for (
int index = 0; index <
numPoints(); ++index)
307 values_[index] = -values_[index];
311 for (
Listener* listener : listeners_)
312 listener->valuesChanged(0,
numPoints() - 1,
true);
316 for (
int index = 0; index <
numPoints() / 2; ++index) {
317 int other_index =
numPoints() - index - 1;
318 float other_value = values_[other_index];
319 values_[other_index] = values_[index];
320 values_[index] = other_value;
325 for (
Listener* listener : listeners_)
326 listener->valuesChanged(0,
numPoints() - 1,
true);
virtual void resized() override
Called when the component is resized.
Definition open_gl_component.cpp:121
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
A component for rendering lines with optional filling and boost effects using OpenGL.
Definition open_gl_line_renderer.h:16
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 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 setFit(bool fit)
Enables fitting the line inside the available area.
Definition open_gl_line_renderer.h:141
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
force_inline int numPoints() const
Gets the number of points in the line.
Definition open_gl_line_renderer.h:186
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
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 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
@ kWidgetBackground
Definition skin.h:173
@ kLightenScreen
Definition skin.h:141
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
Interface for receiving notifications about waveform modifications.
Definition wave_source_editor.h:26
A graphical editor for manipulating a single-cycle waveform's sample values.
Definition wave_source_editor.h:20
void mouseUp(const MouseEvent &e) override
Handles a mouse up event to finalize editing and notify listeners.
Definition wave_source_editor.cpp:107
void flipHorizontal()
Flips the waveform horizontally, reversing its sample order.
Definition wave_source_editor.cpp:315
void resized() override
Adjusts layout and internal structures on component resize.
Definition wave_source_editor.cpp:66
void setGrid(int horizontal, int vertical)
Defines a grid overlay for snapping points.
Definition wave_source_editor.cpp:229
WaveSourceEditor(int size)
Constructs a WaveSourceEditor with a given waveform size.
Definition wave_source_editor.cpp:30
void loadWaveform(float *waveform)
Loads a complete waveform into the editor.
Definition wave_source_editor.cpp:217
void mouseMove(const MouseEvent &e) override
Handles a mouse move event to update the hover position.
Definition wave_source_editor.cpp:116
void clear()
Clears the entire waveform to zero.
Definition wave_source_editor.cpp:295
void fileDragEnter(const StringArray &files, int x, int y) override
Called when dragging audio files enters the component.
Definition wave_source_editor.cpp:287
void mouseDrag(const MouseEvent &e) override
Handles a mouse drag event to continuously update waveform samples.
Definition wave_source_editor.cpp:121
void paintBackground(Graphics &g) override
Paints the background of the waveform editor.
Definition wave_source_editor.cpp:56
void setEditable(bool editable)
Enables or disables editing of the waveform.
Definition wave_source_editor.cpp:224
void fileDragExit(const StringArray &files) override
Called when dragging audio files leaves the component.
Definition wave_source_editor.cpp:291
void mouseExit(const MouseEvent &e) override
Handles a mouse exit event to clear the hover indication.
Definition wave_source_editor.cpp:132
virtual ~WaveSourceEditor()
Destructor.
Definition wave_source_editor.cpp:53
void flipVertical()
Flips the waveform vertically, inverting all sample values.
Definition wave_source_editor.cpp:305
void mouseDown(const MouseEvent &e) override
Handles a mouse down event to start editing or show the context menu.
Definition wave_source_editor.cpp:83
void audioFileLoaded(const File &file) override
Called when an audio file is dropped and loaded successfully.
Definition wave_source_editor.cpp:283
@ kClear
Definition wave_source_editor.h:53
@ kFlipHorizontal
Definition wave_source_editor.h:51
@ kFlipVertical
Definition wave_source_editor.h:52
A base overlay component for editing and interacting with a wavetable component's parameters.
Definition wavetable_component_overlay.h:22
force_inline int iclamp(int value, int min_val, int max_val)
Clamps an integer between [min_val, max_val].
Definition utils.h:250
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
Provides various utility functions, classes, and constants for audio, math, and general-purpose opera...