Vital
Loading...
Searching...
No Matches
chorus_section.cpp
Go to the documentation of this file.
1
3
4#include "chorus_section.h"
5
6#include "chorus_module.h"
7#include "delay_section.h"
8#include "skin.h"
9#include "fonts.h"
10#include "synth_strings.h"
11#include "synth_button.h"
12#include "synth_slider.h"
13#include "tempo_selector.h"
14#include "text_look_and_feel.h"
15
21class ChorusViewer : public BarRenderer {
22public:
24 static constexpr int kNumBars = kDelays * vital::poly_float::kSize;
25
27 ChorusViewer() : BarRenderer(kNumBars, true), delays_() {
28 active_ = true;
29 parent_ = nullptr;
30 num_voices_ = nullptr;
31
32 setBarWidth(0.3f);
33 setScale(1.0f);
35 }
36
39 void parentHierarchyChanged() override {
40 if (delays_[0])
41 return;
42
43 SynthGuiInterface* parent = findParentComponentOfClass<SynthGuiInterface>();
44 if (parent == nullptr)
45 return;
46
47 for (int i = 0; i < kDelays; ++i)
48 delays_[i] = parent->getSynth()->getStatusOutput("chorus_delays" + std::to_string(i + 1));
49 }
50
54 void drawBars(OpenGlWrapper& open_gl, bool animate) {
55 static constexpr float kMaxDelay = 0.07f;
56 static constexpr float kMinDelay = 0.000f;
57 static constexpr float kDelayRange = kMaxDelay - kMinDelay;
58
59 if (delays_[0] == nullptr)
60 return;
61
62 int num_voices = static_cast<int>(num_voices_->getValue() * vital::poly_float::kSize);
63 for (int i = 0; i < num_voices; ++i) {
64 vital::poly_float delay_frequency = delays_[i / vital::poly_float::kSize]->value();
65 float delay = 1.0f / delay_frequency[i % vital::poly_float::kSize];
66 setX(i, 2.0f * (delay - kMinDelay) / kDelayRange - 1.0f);
67 setY(i, 0.5f);
68 setBottom(i, -0.5f);
69 }
70
71 for (int i = num_voices; i < num_points_; ++i)
72 setX(i , -2.0f);
73
74 BarRenderer::render(open_gl, animate);
75 }
76
80 void render(OpenGlWrapper& open_gl, bool animate) override {
81 if (active_) {
82 Colour color = findColour(Skin::kWidgetSecondary1, true);
83 float alpha = color.getFloatAlpha();
84 setColor(color.withAlpha(alpha + (1.0f - alpha) * alpha));
85 }
86 else
88
89 drawBars(open_gl, animate);
90 renderCorners(open_gl, animate);
91 }
92
95 void setActive(bool active) { active_ = active; }
96
99 void setNumVoicesSlider(SynthSlider* num_voices) { num_voices_ = num_voices; }
100
101private:
102 bool active_;
103 const vital::StatusOutput* delays_[4];
104 SynthSlider* num_voices_;
105
106 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ChorusViewer)
107};
108
109ChorusSection::ChorusSection(const String& name, const vital::output_map& mono_modulations) : SynthSection(name) {
110 static const double kTempoDragSensitivity = 0.5;
111 static constexpr int kViewerResolution = 64;
112
113 voices_ = std::make_unique<SynthSlider>("chorus_voices");
114 addSlider(voices_.get());
115 voices_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
116 voices_->setLookAndFeel(TextLookAndFeel::instance());
117 voices_->setSensitivity(kTempoDragSensitivity);
118
119 delay_1_ = std::make_unique<SynthSlider>("chorus_delay_1");
120 addSlider(delay_1_.get());
121 delay_1_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
122
123 delay_2_ = std::make_unique<SynthSlider>("chorus_delay_2");
124 addSlider(delay_2_.get());
125 delay_2_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
126
127 mod_depth_ = std::make_unique<SynthSlider>("chorus_mod_depth");
128 addSlider(mod_depth_.get());
129 mod_depth_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
130
131 frequency_ = std::make_unique<SynthSlider>("chorus_frequency");
132 addSlider(frequency_.get());
133 frequency_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
134 frequency_->setLookAndFeel(TextLookAndFeel::instance());
135
136 tempo_ = std::make_unique<SynthSlider>("chorus_tempo");
137 addSlider(tempo_.get());
138 tempo_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
139 tempo_->setLookAndFeel(TextLookAndFeel::instance());
140 tempo_->setSensitivity(kTempoDragSensitivity);
141
142 sync_ = std::make_unique<TempoSelector>("chorus_sync");
143 addSlider(sync_.get());
144 sync_->setSliderStyle(Slider::LinearBar);
145 sync_->setTempoSlider(tempo_.get());
146 sync_->setFreeSlider(frequency_.get());
147
148 feedback_ = std::make_unique<SynthSlider>("chorus_feedback");
149 addSlider(feedback_.get());
150 feedback_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
151 feedback_->setBipolar();
152 feedback_->snapToValue(true);
153
154 dry_wet_ = std::make_unique<SynthSlider>("chorus_dry_wet");
155 addSlider(dry_wet_.get());
156 dry_wet_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
157
158 filter_cutoff_ = std::make_unique<SynthSlider>("chorus_cutoff");
159 addSlider(filter_cutoff_.get());
160 filter_cutoff_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
161
162 filter_spread_ = std::make_unique<SynthSlider>("chorus_spread");
163 addSlider(filter_spread_.get());
164 filter_spread_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
165
166 chorus_viewer_ = std::make_unique<ChorusViewer>();
167 addOpenGlComponent(chorus_viewer_.get());
168 chorus_viewer_->setNumVoicesSlider(voices_.get());
169
170 filter_viewer_ = std::make_unique<DelayFilterViewer>("chorus", kViewerResolution, mono_modulations);
171 filter_viewer_->setCutoffSlider(filter_cutoff_.get());
172 filter_viewer_->setSpreadSlider(filter_spread_.get());
173 filter_viewer_->addListener(this);
174 addOpenGlComponent(filter_viewer_.get());
175
176 on_ = std::make_unique<SynthButton>("chorus_on");
177 addButton(on_.get());
178 setActivator(on_.get());
180}
181
183
186
187 Rectangle<int> frequency_bounds(tempo_->getX(), tempo_->getY(),
188 sync_->getRight() - tempo_->getX(), tempo_->getHeight());
189 drawTextComponentBackground(g, frequency_bounds, true);
190 drawTextComponentBackground(g, voices_->getBounds(), true);
191
192 setLabelFont(g);
193 drawLabel(g, TRANS("FREQUENCY"), frequency_bounds, true);
194 drawLabelForComponent(g, TRANS("VOICES"), voices_.get(), true);
195 drawLabelForComponent(g, TRANS("FEEDBACK"), feedback_.get());
196 drawLabelForComponent(g, TRANS("MIX"), dry_wet_.get());
197 drawLabelForComponent(g, TRANS("DEPTH"), mod_depth_.get());
198 drawLabelForComponent(g, TRANS("DELAY 1"), delay_1_.get());
199 drawLabelForComponent(g, TRANS("DELAY 2"), delay_2_.get());
200 drawLabelForComponent(g, TRANS("CUTOFF"), filter_cutoff_.get());
201 drawLabelForComponent(g, TRANS("SPREAD"), filter_spread_.get());
202
203 drawTempoDivider(g, sync_.get());
204}
205
207 int widget_margin = findValue(Skin::kWidgetMargin);
208 int title_width = getTitleWidth();
209 int section_height = getKnobSectionHeight();
210
211 Rectangle<int> bounds = getLocalBounds().withLeft(title_width);
212 Rectangle<int> delay_area = getDividedAreaBuffered(bounds, 3, 0, widget_margin);
213 Rectangle<int> knobs_area = getDividedAreaBuffered(bounds, 3, 2, widget_margin);
214
215 placeKnobsInArea(Rectangle<int>(delay_area.getX(), 0, delay_area.getWidth(), section_height),
216 { voices_.get(), tempo_.get()});
217 voices_->setBounds(voices_->getBounds().withTop(widget_margin));
218 placeTempoControls(tempo_->getX(), widget_margin, tempo_->getWidth(),
219 section_height - 2 * widget_margin, frequency_.get(), sync_.get());
220 tempo_->setBounds(frequency_->getBounds());
221 tempo_->setModulationArea(frequency_->getModulationArea());
222
223 int delay_y = section_height - widget_margin;
224 placeKnobsInArea(Rectangle<int>(delay_area.getX(), delay_y, delay_area.getWidth(), section_height),
225 { mod_depth_.get(), delay_1_.get(), delay_2_.get() });
226
227 int widget_x = delay_2_->getRight() + widget_margin;
228 int viewer_width = knobs_area.getX() - widget_x;
229 int delay_height = (getHeight() - 3 * widget_margin) / 2;
230 int filter_y = delay_height + 2 * widget_margin;
231 chorus_viewer_->setBounds(widget_x, widget_margin, viewer_width, delay_height);
232 filter_viewer_->setBounds(widget_x, filter_y, viewer_width, getHeight() - filter_y - widget_margin);
233
234 placeKnobsInArea(Rectangle<int>(knobs_area.getX(), 0, knobs_area.getWidth(), section_height),
235 { feedback_.get(), dry_wet_.get() });
236
237 int knob_y2 = section_height - widget_margin;
238 placeKnobsInArea(Rectangle<int>(knobs_area.getX(), knob_y2, knobs_area.getWidth(), section_height),
239 { filter_cutoff_.get(), filter_spread_.get() });
240
242}
243
244void ChorusSection::setActive(bool active) {
246 chorus_viewer_->setActive(active);
247 filter_viewer_->setActive(active);
248}
249
250void ChorusSection::deltaMovement(float x, float y) {
251 double x_range = filter_cutoff_->getMaximum() - filter_cutoff_->getMinimum();
252 double y_range = filter_spread_->getMaximum() - filter_spread_->getMinimum();
253
254 filter_cutoff_->setValue(filter_cutoff_->getValue() + x * x_range);
255 filter_spread_->setValue(filter_spread_->getValue() + y * y_range);
256}
Declares the ChorusSection class, which provides a UI for configuring chorus effects.
A renderer for drawing a series of bars using OpenGL.
Definition bar_renderer.h:18
void setColor(const Colour &color)
Sets the color of the bars.
Definition bar_renderer.h:76
force_inline void setX(int index, float val)
Sets the x-position for all vertices of a specific bar.
Definition bar_renderer.h:141
force_inline void setBottom(int index, float val)
Sets the bottom y-position of a specific bar.
Definition bar_renderer.h:165
force_inline void setAdditiveBlending(bool additive_blending)
Enables or disables additive blending for the bar rendering.
Definition bar_renderer.h:251
void setScale(float scale)
Sets the scaling factor for the bars.
Definition bar_renderer.h:82
void setBarWidth(float bar_width)
Sets the relative width of each bar.
Definition bar_renderer.h:94
int num_points_
Number of bars to render.
Definition bar_renderer.h:280
virtual void render(OpenGlWrapper &open_gl, bool animate) override
Renders the bars using the current OpenGL context.
Definition bar_renderer.cpp:149
force_inline void setY(int index, float val)
Sets the top y-position of a specific bar.
Definition bar_renderer.h:154
void resized() override
Resizes and lays out child components and controls.
Definition chorus_section.cpp:206
ChorusSection(const String &name, const vital::output_map &mono_modulations)
Definition chorus_section.cpp:109
void deltaMovement(float x, float y) override
Definition chorus_section.cpp:250
void setActive(bool active) override
Definition chorus_section.cpp:244
void paintBackground(Graphics &g) override
Definition chorus_section.cpp:184
~ChorusSection()
Destructor.
A visual display showing chorus delay lines based on the current settings.
Definition chorus_section.cpp:21
static constexpr int kDelays
Definition chorus_section.cpp:23
ChorusViewer()
Constructor.
Definition chorus_section.cpp:27
static constexpr int kNumBars
Definition chorus_section.cpp:24
void setNumVoicesSlider(SynthSlider *num_voices)
Definition chorus_section.cpp:99
void setActive(bool active)
Definition chorus_section.cpp:95
void parentHierarchyChanged() override
Definition chorus_section.cpp:39
void drawBars(OpenGlWrapper &open_gl, bool animate)
Definition chorus_section.cpp:54
void render(OpenGlWrapper &open_gl, bool animate) override
Definition chorus_section.cpp:80
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
const SynthSection * parent_
Pointer to parent SynthSection for skin lookups.
Definition open_gl_component.h:256
@ kWidgetMargin
Definition skin.h:103
@ kWidgetSecondary1
Definition skin.h:168
@ kWidgetSecondaryDisabled
Definition skin.h:170
@ kChorus
Definition skin.h:46
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
Base class for all synthesizer sections, providing UI layout, painting, and interaction logic.
Definition synth_section.h:193
Rectangle< int > getDividedAreaBuffered(Rectangle< int > full_area, int num_sections, int section, int buffer)
Divides an area into equal sections with buffering, returns the specified section.
Definition synth_section.cpp:776
void drawTextComponentBackground(Graphics &g, Rectangle< int > bounds, bool extend_to_label)
Draws a background for a text component area.
Definition synth_section.cpp:319
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 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
virtual void setActive(bool active)
Sets the active state of this section and sub-sections.
Definition synth_section.cpp:806
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
void addButton(OpenGlToggleButton *button, bool show=true)
Definition synth_section.cpp:428
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
virtual void paintBackground(Graphics &g)
Paints the background of the section. Calls paintContainer, heading, knobs, children.
Definition synth_section.cpp:77
float getKnobSectionHeight()
Definition synth_section.cpp:633
void setActivator(SynthButton *activator)
Definition synth_section.cpp:504
void addOpenGlComponent(OpenGlComponent *open_gl_component, bool to_beginning=false)
Definition synth_section.cpp:489
float getTitleWidth()
Definition synth_section.cpp:629
void setSkinOverride(Skin::SectionOverride skin_override)
Definition synth_section.h:303
A specialized slider with extended functionality for modulation, parameter control,...
Definition synth_slider.h:314
static TextLookAndFeel * instance()
Singleton instance access.
Definition text_look_and_feel.h:106
static constexpr int kMaxDelayPairs
The maximum number of delay line pairs (voices).
Definition chorus_module.h:25
A helper class to track the "status" of a particular Output as a poly_float value.
Definition synth_module.h:35
force_inline poly_float value() const
Returns the current status value.
Definition synth_module.h:49
Declares the DelaySection class and related viewer classes for displaying and controlling a delay eff...
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
Declares classes for OpenGL-based buttons used in the Vital synth UI.
Declares the SynthSlider and related classes, providing various slider styles and functionality in th...
Declares the TempoSelector class, a specialized slider for selecting tempo-related modes.