24 static constexpr double kTempoDragSensitivity = 0.5;
25 static constexpr int kDefaultGridSizeX = 8;
26 static constexpr int kDefaultGridSizeY = 1;
28 smooth_mode_control_name_ = value_prepend +
"_smooth_mode";
30 frequency_ = std::make_unique<SynthSlider>(value_prepend +
"_frequency");
32 frequency_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
35 tempo_ = std::make_unique<SynthSlider>(value_prepend +
"_tempo");
37 tempo_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
39 tempo_->setSensitivity(kTempoDragSensitivity);
40 tempo_->setTextEntrySizePercent(1.0f, 0.7f);
42 keytrack_transpose_ = std::make_unique<SynthSlider>(value_prepend +
"_keytrack_transpose");
44 keytrack_transpose_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
47 keytrack_transpose_->setBipolar();
50 keytrack_tune_ = std::make_unique<SynthSlider>(value_prepend +
"_keytrack_tune");
52 keytrack_tune_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
54 keytrack_tune_->setBipolar();
55 keytrack_tune_->setMaxDisplayCharacters(3);
56 keytrack_tune_->setMaxDecimalPlaces(0);
58 sync_ = std::make_unique<TempoSelector>(value_prepend +
"_sync");
60 sync_->setSliderStyle(Slider::LinearBar);
61 sync_->setTempoSlider(tempo_.get());
62 sync_->setKeytrackTransposeSlider(keytrack_transpose_.get());
63 sync_->setKeytrackTuneSlider(keytrack_tune_.get());
64 sync_->setFreeSlider(frequency_.get());
66 sync_type_ = std::make_unique<TextSelector>(value_prepend +
"_sync_type");
68 sync_type_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
72 paint_pattern_ = std::make_unique<PaintPatternSelector>(
"paint_pattern");
75 paint_pattern_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
79 paint_pattern_->setTextHeightPercentage(0.45f);
80 paint_pattern_->setActive(
false);
85 transpose_tune_divider_->setInterceptsMouseClicks(
false,
false);
87 phase_ = std::make_unique<SynthSlider>(value_prepend +
"_phase");
89 phase_->setSliderStyle(Slider::LinearBar);
90 phase_->setModulationPlacement(BubbleComponent::above);
92 fade_ = std::make_unique<SynthSlider>(value_prepend +
"_fade_time");
94 fade_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
95 fade_->setPopupPlacement(BubbleComponent::below);
96 fade_->setVisible(
false);
98 smooth_ = std::make_unique<SynthSlider>(value_prepend +
"_smooth_time");
100 smooth_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
101 smooth_->setPopupPlacement(BubbleComponent::below);
103 smooth_mode_text_ = std::make_unique<PlainTextComponent>(
"Smooth Mode Text",
"---");
107 smooth_mode_type_selector_ = std::make_unique<ShapeButton>(
"Smooth Mode", Colours::black,
108 Colours::black, Colours::black);
109 addAndMakeVisible(smooth_mode_type_selector_.get());
110 smooth_mode_type_selector_->addListener(
this);
111 smooth_mode_type_selector_->setTriggeredOnMouseDown(
true);
113 delay_ = std::make_unique<SynthSlider>(value_prepend +
"_delay_time");
115 delay_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
116 delay_->setPopupPlacement(BubbleComponent::below);
118 stereo_ = std::make_unique<SynthSlider>(value_prepend +
"_stereo");
120 stereo_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
121 stereo_->setPopupPlacement(BubbleComponent::below);
122 stereo_->setBipolar(
true);
123 stereo_->snapToValue(
true, 0.0);
125 grid_size_x_ = std::make_unique<SynthSlider>(
"grid_size_x");
127 grid_size_x_->setValue(kDefaultGridSizeX);
129 grid_size_x_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
131 grid_size_x_->setDoubleClickReturnValue(
true, kDefaultGridSizeX);
132 grid_size_x_->setMaxDecimalPlaces(0);
133 grid_size_x_->setSensitivity(0.2f);
135 grid_size_x_->setTextHeightPercentage(0.6f);
136 grid_size_x_->setPopupPrefix(
"X Grid");
138 grid_size_y_ = std::make_unique<SynthSlider>(
"grid_size_y");
140 grid_size_y_->setValue(kDefaultGridSizeY);
142 grid_size_y_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
144 grid_size_y_->setDoubleClickReturnValue(
true, kDefaultGridSizeY);
145 grid_size_y_->setMaxDecimalPlaces(0);
146 grid_size_y_->setSensitivity(0.2f);
148 grid_size_y_->setTextHeightPercentage(0.6f);
149 grid_size_y_->setPopupPrefix(
"Y Grid");
151 paint_ = std::make_unique<OpenGlShapeButton>(
"paint");
152 paint_->useOnColors(
true);
153 paint_->setClickingTogglesState(
true);
154 addAndMakeVisible(paint_.get());
156 paint_->addListener(
this);
159 lfo_smooth_ = std::make_unique<OpenGlShapeButton>(
"smooth");
160 lfo_smooth_->useOnColors(
true);
161 lfo_smooth_->setClickingTogglesState(
true);
162 addAndMakeVisible(lfo_smooth_.get());
164 lfo_smooth_->addListener(
this);
167 editor_ = std::make_unique<LfoEditor>(lfo_source, value_prepend, mono_modulations, poly_modulations);
168 editor_->addListener(
this);
169 editor_->setGridSizeX(kDefaultGridSizeX);
170 editor_->setGridSizeY(kDefaultGridSizeY);
173 lfo_smooth_->setToggleState(editor_->getModel()->smooth(), dontSendNotification);
175 paint_pattern_->setValue(
kDown);
177 preset_selector_ = std::make_unique<PresetSelector>();
179 preset_selector_->addListener(
this);
181 preset_selector_->setText(editor_->getModel()->getName());
203 float tempo_width = sync_->getRight() - tempo_->getX();
206 Rectangle<int> frequency_bounds(tempo_->getX(), tempo_->getY(), tempo_width, tempo_->getHeight());
211 drawLabel(g, TRANS(
"MODE"), sync_type_->getBounds(),
true);
212 drawLabel(g, TRANS(
"FREQUENCY"), frequency_bounds,
true);
221 int grid_label_x = grid_size_x_->getX();
222 int grid_size_width = grid_size_y_->getRight() - grid_label_x;
224 int background_height = title_width - 2 * widget_margin;
225 g.fillRoundedRectangle(grid_label_x, widget_margin, grid_size_width, background_height, rounding);
226 g.fillRoundedRectangle(widget_margin, widget_margin, grid_label_x - 2 * widget_margin, background_height, rounding);
229 g.setColour(body_text);
230 g.drawText(
"-", grid_label_x, widget_margin, grid_size_width, title_width - 2 * widget_margin,
231 Justification::centred,
false);
234 smooth_mode_text_->setColor(body_text);
253 int wave_height = getHeight() - slider_width - widget_margin -
254 title_width - knob_section_height + 2 * slider_overlap;
255 int wave_width = getWidth() - 2 * widget_margin;
256 editor_->setBounds(widget_margin, title_width, wave_width, wave_height);
257 phase_->setBounds(0, editor_->getBottom() - slider_overlap + widget_margin, getWidth(), slider_width);
260 int style_width = getWidth() - knobs_width;
262 int knob_y = getHeight() - knob_section_height;
263 int text_component_width = style_width / 2 - widget_margin;
264 sync_type_->setBounds(widget_margin, knob_y + widget_margin,
265 text_component_width, knob_section_height - 2 * widget_margin);
266 int tempo_x = sync_type_->getRight() + widget_margin;
267 placeTempoControls(tempo_x, knob_y + widget_margin, style_width - tempo_x, knob_section_height - 2 * widget_margin,
268 frequency_.get(), sync_.get());
269 tempo_->setBounds(frequency_->getBounds());
270 Rectangle<int> divider_bounds = frequency_->getModulationArea() + frequency_->getBounds().getTopLeft();
271 divider_bounds = divider_bounds.reduced(divider_bounds.getHeight() / 4);
272 divider_bounds.setX(divider_bounds.getCentreX());
273 divider_bounds.setWidth(1);
274 transpose_tune_divider_->setBounds(divider_bounds);
275 tempo_->setModulationArea(frequency_->getModulationArea());
277 Rectangle<int> frequency_bounds = frequency_->getBounds();
278 keytrack_transpose_->setBounds(frequency_bounds.withWidth(frequency_bounds.getWidth() / 2));
279 keytrack_tune_->setBounds(frequency_bounds.withLeft(keytrack_transpose_->getRight()));
280 keytrack_transpose_->setModulationArea(frequency_->getModulationArea().withWidth(keytrack_transpose_->getWidth()));
281 keytrack_tune_->setModulationArea(frequency_->getModulationArea().withWidth(keytrack_tune_->getWidth()));
283 placeKnobsInArea(Rectangle<int>(style_width, knob_y, knobs_width, knob_section_height),
284 { fade_.get(), delay_.get(), stereo_.get() });
285 smooth_->setBounds(fade_->getBounds());
288 smooth_mode_text_->setBounds(smooth_label_bounds);
290 smooth_mode_type_selector_->setBounds(smooth_label_bounds);
293 int top_height = title_width - 2 * widget_margin;
295 lfo_smooth_->setBounds(browser_bounds.getX() - title_width - widget_margin, widget_margin, title_width, top_height);
296 grid_size_y_->setBounds(lfo_smooth_->getX() - title_width - widget_margin, widget_margin, title_width, top_height);
297 grid_size_x_->setBounds(grid_size_y_->getX() - title_width - widget_margin, widget_margin, title_width, top_height);
299 paint_->setBounds(widget_margin, widget_margin, top_height, top_height);
300 int pattern_width = grid_size_x_->getX() - paint_->getRight() - widget_margin;
302 paint_pattern_->setBounds(paint_->getRight(), widget_margin, pattern_width, top_height);
313 preset_selector_->setText(editor_->getModel()->getName());
314 editor_->resetPositions();
324 lfo_smooth_->setToggleState(editor_->getSmooth(), dontSendNotification);
325 transpose_tune_divider_->setVisible(sync_->isKeytrack());
327 int smooth_mode = controls[smooth_mode_control_name_]->value();
329 smooth_->setVisible(smooth_mode);
330 fade_->setVisible(smooth_mode == 0);
342 if (changed_slider == grid_size_x_.get())
343 editor_->setGridSizeX(grid_size_x_->getValue());
344 else if (changed_slider == grid_size_y_.get())
345 editor_->setGridSizeY(grid_size_y_->getValue());
346 else if (changed_slider == paint_pattern_.get())
351 transpose_tune_divider_->setVisible(sync_->isKeytrack());
363 if (clicked_button == paint_.get()) {
364 editor_->setPaint(paint_->getToggleState());
365 paint_pattern_->setActive(paint_->getToggleState());
367 else if (clicked_button == lfo_smooth_.get())
368 editor_->setSmooth(lfo_smooth_->getToggleState());
369 else if (clicked_button == smooth_mode_type_selector_.get()) {
372 for (
int i = 0; i < 2; ++i)
375 showPopupSelector(
this, Point<int>(clicked_button->getX(), clicked_button->getBottom()), options,
376 [=](
int selection) { setSmoothModeSelected(selection); });
391 if (paint_->getToggleState())
392 paint_pattern_->mouseWheelMove(e, wheel);
394 grid_size_x_->mouseWheelMove(e, wheel);
404 paint_->setToggleState(enabled != temporary_switch, dontSendNotification);
405 paint_pattern_->setActive(enabled != temporary_switch);
413 if (!import_box.browseForFileToOpen())
416 File choice = import_box.getResult();
425 if (!export_box.browseForFileToSave(
true))
428 File choice = export_box.getResult();
430 if (!choice.exists())
432 choice.replaceWithText(editor_->getModel()->stateToJson().dump());
434 String name = choice.getFileNameWithoutExtension();
435 editor_->getModel()->setName(name.toStdString());
436 preset_selector_->setText(name);
445 lfo_smooth_->setToggleState(editor_->getModel()->smooth(), dontSendNotification);
454 if (lfo_file.exists())
466 if (lfo_file.exists())
480 static constexpr int kBrowserWidth = 500;
481 static constexpr int kBrowserHeight = 250;
485 Rectangle<int> bounds(preset_selector_->getRight() - browser_width, -browser_height,
486 browser_width, browser_height);
487 bounds = getLocalArea(
this, bounds);
501 smooth_->setVisible(result);
502 fade_->setVisible(result == 0);
520 current_file_ = file;
522 json parsed_file = json::parse(file.loadFileAsString().toStdString(),
nullptr,
false);
523 editor_->getModel()->jsonToState(parsed_file);
525 catch (
const json::exception& e) {
529 String name = file.getFileNameWithoutExtension();
530 editor_->getModel()->setName(name.toStdString());
531 editor_->getModel()->setLastBrowsedFile(file.getFullPathName().toStdString());
532 preset_selector_->setText(name);
534 editor_->resetPositions();
535 lfo_smooth_->setToggleState(editor_->getModel()->smooth(), dontSendNotification);
static std::vector< std::pair< float, float > > getPaintPattern(int pattern)
Retrieves a paint pattern as a vector of (x, y) pairs.
Definition lfo_section.h:54
void textMouseDown(const MouseEvent &e) override
Handles mouse-down events on the text component, usually to open a file browser.
Definition lfo_section.cpp:479
void prevClicked() override
Loads the previous LFO preset.
Definition lfo_section.cpp:451
void nextClicked() override
Loads the next LFO preset.
Definition lfo_section.cpp:463
void loadFile(const File &file) override
Loads the LFO configuration from the specified file.
Definition lfo_section.cpp:516
File getCurrentFile() override
Retrieves the current LFO file.
Definition lfo_section.h:199
void lineEditorScrolled(const MouseEvent &e, const MouseWheelDetails &wheel) override
Responds to scrolling events in the line editor component.
Definition lfo_section.cpp:390
void reset() override
Resets all LFO settings to their default states.
Definition lfo_section.cpp:311
void importLfo() override
Imports an LFO from a user-selected file.
Definition lfo_section.cpp:411
void resized() override
Called when the component is resized.
Definition lfo_section.cpp:245
void setAllValues(vital::control_map &controls) override
Updates all control values in this section from the given map of controls.
Definition lfo_section.cpp:322
void exportLfo() override
Exports the current LFO configuration to a user-selected file.
Definition lfo_section.cpp:423
LfoSection(String name, std::string value_prepend, LineGenerator *lfo_source, const vital::output_map &mono_modulations, const vital::output_map &poly_modulations)
Constructs a new LfoSection.
Definition lfo_section.cpp:21
@ kDown
A downward linear ramp.
Definition lfo_section.h:42
@ kNumPaintPatterns
The number of available paint patterns.
Definition lfo_section.h:45
void buttonClicked(Button *clicked_button) override
Responds to a button click event.
Definition lfo_section.cpp:362
void setSmoothModeSelected(int result)
Sets the selected smooth mode.
Definition lfo_section.cpp:499
void fileLoaded() override
Called when an LFO file has been successfully loaded.
Definition lfo_section.cpp:444
void togglePaintMode(bool enabled, bool temporary_switch) override
Toggles paint mode for the LFO editor.
Definition lfo_section.cpp:403
void sliderValueChanged(Slider *changed_slider) override
Responds to a slider value change event.
Definition lfo_section.cpp:341
void paintBackground(Graphics &g) override
Paints the background of the LFO section.
Definition lfo_section.cpp:199
static constexpr int kMaxGridSizeY
Definition line_editor.h:51
static constexpr int kMaxGridSizeX
Maximum grid sizes for horizontal and vertical lines.
Definition line_editor.h:50
A class for generating and storing a line shape, defined by a series of points and associated powers.
Definition line_generator.h:20
static std::vector< File > getLfoDirectories()
Gets directories that should contain LFO shapes.
Definition load_save.cpp:1780
static File getShiftedFile(const String directory_name, const String &extensions, const std::string &additional_folders_name, const File ¤t_file, int shift)
Given a directory name and extensions, returns a file shifted by some offset from the current file.
Definition load_save.cpp:1921
static const std::string kLfoFolderName
Definition load_save.h:78
static File getUserLfoDirectory()
Retrieves the user's LFO directory.
Definition load_save.cpp:1819
static Path halfSinCurve()
Definition paths.h:751
static Path paintBrush()
Definition paths.h:804
@ kColorFragment
Definition shaders.h:63
@ kWidgetMargin
Definition skin.h:103
@ kLabelHeight
Definition skin.h:72
@ kTextComponentOffset
Definition skin.h:85
@ kModulationButtonWidth
Definition skin.h:101
@ kPadding
Definition skin.h:81
@ kBodyText
Definition skin.h:133
@ kLightenScreen
Definition skin.h:141
@ kPopupSelectorBackground
Definition skin.h:143
@ kLfo
Definition skin.h:40
void valueChangedInternal(const std::string &name, vital::mono_float value)
Handles internal value changes, updating the parameter and optionally notifying the host.
Definition synth_base.cpp:54
An interface class linking the Vital synthesizer backend (SynthBase) with a GUI.
Definition synth_gui_interface.h:56
SynthBase * getSynth()
Returns the SynthBase instance this interface is managing.
Definition synth_gui_interface.h:85
Base class for all synthesizer sections, providing UI layout, painting, and interaction logic.
Definition synth_section.h:193
void drawTextComponentBackground(Graphics &g, Rectangle< int > bounds, bool extend_to_label)
Draws a background for a text component area.
Definition synth_section.cpp:319
virtual void buttonClicked(Button *clicked_button) override
Called when a button is clicked. Updates the synth parameter accordingly.
Definition synth_section.cpp:398
float getSliderWidth()
Definition synth_section.cpp:637
void placeKnobsInArea(Rectangle< int > area, std::vector< Component * > knobs)
Definition synth_section.cpp:601
void addSlider(SynthSlider *slider, bool show=true, bool listen=true)
Definition synth_section.cpp:445
void addSubSection(SynthSection *section, bool show=true)
Adds a subsection (another SynthSection) as a child.
Definition synth_section.cpp:457
void drawLabel(Graphics &g, String text, Rectangle< int > component_bounds, bool text_component=false)
Draws a label text below a component.
Definition synth_section.cpp:789
void drawTempoDivider(Graphics &g, Component *sync)
Draws a divider line for tempo-related controls.
Definition synth_section.cpp:339
virtual void resized() override
Called when the component is resized. Arranges layout of child components.
Definition synth_section.cpp:35
void placeTempoControls(int x, int y, int width, int height, SynthSlider *tempo, SynthSlider *sync)
Definition synth_section.cpp:584
float getWidgetRounding()
Definition synth_section.cpp:680
static constexpr double kTransposeMouseSensitivity
Definition synth_section.h:204
void paintChildrenBackgrounds(Graphics &g)
Paints the backgrounds for all child sections.
Definition synth_section.cpp:274
void updatePopupBrowser(SynthSection *owner)
Updates the currently visible popup browser if any.
Definition synth_section.cpp:113
void paintKnobShadows(Graphics &g)
Paints knob shadows for all sliders.
Definition synth_section.cpp:253
void drawLabelForComponent(Graphics &g, String text, Component *component, bool text_component=false)
Draws a label for a given component.
Definition synth_section.h:548
void setLabelFont(Graphics &g)
Sets the Graphics context font and color for labels.
Definition synth_section.cpp:740
float getSliderOverlap()
Definition synth_section.cpp:641
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
Rectangle< int > getLabelBackgroundBounds(Rectangle< int > bounds, bool text_component=false)
Gets the background bounds for a label.
Definition synth_section.cpp:782
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
float getKnobSectionHeight()
Definition synth_section.cpp:633
void addOpenGlComponent(OpenGlComponent *open_gl_component, bool to_beginning=false)
Definition synth_section.cpp:489
float getSizeRatio() const
Definition synth_section.h:765
virtual void sliderValueChanged(Slider *moved_slider) override
Called when a slider value changes. Updates the synth parameter accordingly.
Definition synth_section.cpp:391
virtual void setAllValues(vital::control_map &controls)
Sets values for all known parameters from a control map.
Definition synth_section.cpp:827
virtual void reset()
Resets the section and all sub-sections.
Definition synth_section.cpp:30
void setPresetSelector(PresetSelector *preset_selector, bool half=false)
Definition synth_section.h:779
float getTitleWidth()
Definition synth_section.cpp:629
void setSkinOverride(Skin::SectionOverride skin_override)
Definition synth_section.h:303
Rectangle< int > getPresetBrowserBounds()
Definition synth_section.cpp:684
void showPopupBrowser(SynthSection *owner, Rectangle< int > bounds, std::vector< File > directories, String extensions, std::string passthrough_name, std::string additional_folders_name)
Shows a file browser popup (e.g., for loading samples or wavetables).
Definition synth_section.cpp:105
float getWidgetMargin()
Definition synth_section.cpp:676
static TextLookAndFeel * instance()
Singleton instance access.
Definition text_look_and_feel.h:106
nlohmann::json json
Definition line_generator.h:7
const std::string kPaintPatternNames[]
Names for painting patterns in wavetable or LFO editing.
Definition synth_strings.h:327
const std::string kSyncNames[]
Full names for different sync/re-triggering modes of modulators.
Definition synth_strings.h:292
const std::string kSmoothModeNames[]
Names for smoothing modes in parameters or LFO shapes.
Definition synth_strings.h:270
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 kNotesPerOctave
Number of semitones per octave.
Definition common.h:51
std::map< std::string, Value * > control_map
Maps parameter names to Value pointers representing synth control parameters.
Definition synth_types.h:214
const std::string kLfoExtension
File extension for Vital LFO shape files.
Definition synth_constants.h:100
Declares the TempoSelector class, a specialized slider for selecting tempo-related modes.
Declares the TextSelector class and PaintPatternSelector class for selecting text-based options and d...