Vital
Loading...
Searching...
No Matches
equalizer_section.cpp
Go to the documentation of this file.
1
3
4#include "equalizer_section.h"
5
6#include "skin.h"
8#include "fonts.h"
9#include "oscilloscope.h"
10#include "sound_engine.h"
11#include "synth_button.h"
12#include "synth_slider.h"
13#include "tab_selector.h"
14
15namespace {
16 Path bufferPath(const Path& path) {
17 static constexpr float kBuffer = 0.3f;
18 Rectangle<float> bounds = path.getBounds();
19 Path result = path;
20
21 float top = bounds.getY() - kBuffer;
22 float bottom = bounds.getBottom() + kBuffer;
23 result.addLineSegment(Line<float>(bounds.getX(), top, bounds.getX(), top), 0.1f);
24 result.addLineSegment(Line<float>(bounds.getX(), bottom, bounds.getX(), bottom), 0.1f);
25 return result;
26 }
27}
28
29EqualizerSection::EqualizerSection(String name, const vital::output_map& mono_modulations) : SynthSection(name) {
30 parent_ = nullptr;
31
32 low_mode_ = std::make_unique<OpenGlShapeButton>("eq_low_mode");
33 low_mode_->useOnColors(true);
34 low_mode_->setClickingTogglesState(true);
35 addButton(low_mode_.get());
36 low_mode_->addListener(this);
37 low_mode_->setShape(bufferPath(Paths::highPass()));
38
39 band_mode_ = std::make_unique<OpenGlShapeButton>("eq_band_mode");
40 band_mode_->useOnColors(true);
41 band_mode_->setClickingTogglesState(true);
42 addButton(band_mode_.get());
43 band_mode_->addListener(this);
44 band_mode_->setShape(bufferPath(Paths::notch()));
45
46 high_mode_ = std::make_unique<OpenGlShapeButton>("eq_high_mode");
47 high_mode_->useOnColors(true);
48 high_mode_->setClickingTogglesState(true);
49 addButton(high_mode_.get());
50 high_mode_->addListener(this);
51 high_mode_->setShape(bufferPath(Paths::lowPass()));
52
53 low_cutoff_ = std::make_unique<SynthSlider>("eq_low_cutoff");
54 addSlider(low_cutoff_.get());
55 low_cutoff_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
56 setSliderHasHzAlternateDisplay(low_cutoff_.get());
57
58 low_resonance_ = std::make_unique<SynthSlider>("eq_low_resonance");
59 addSlider(low_resonance_.get());
60 low_resonance_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
61
62 low_gain_ = std::make_unique<SynthSlider>("eq_low_gain");
63 addSlider(low_gain_.get());
64 low_gain_->setBipolar();
65 low_gain_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
66
67 band_cutoff_ = std::make_unique<SynthSlider>("eq_band_cutoff");
68 addSlider(band_cutoff_.get());
69 band_cutoff_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
70 setSliderHasHzAlternateDisplay(band_cutoff_.get());
71
72 band_resonance_ = std::make_unique<SynthSlider>("eq_band_resonance");
73 addSlider(band_resonance_.get());
74 band_resonance_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
75
76 band_gain_ = std::make_unique<SynthSlider>("eq_band_gain");
77 addSlider(band_gain_.get());
78 band_gain_->setBipolar();
79 band_gain_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
80
81 high_cutoff_ = std::make_unique<SynthSlider>("eq_high_cutoff");
82 addSlider(high_cutoff_.get());
83 high_cutoff_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
84 setSliderHasHzAlternateDisplay(high_cutoff_.get());
85
86 high_resonance_ = std::make_unique<SynthSlider>("eq_high_resonance");
87 addSlider(high_resonance_.get());
88 high_resonance_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
89
90 high_gain_ = std::make_unique<SynthSlider>("eq_high_gain");
91 addSlider(high_gain_.get());
92 high_gain_->setBipolar();
93 high_gain_->setSliderStyle(Slider::RotaryHorizontalVerticalDrag);
94
95 spectrogram_ = std::make_unique<Spectrogram>();
96 addOpenGlComponent(spectrogram_.get());
97 float min_frequency = vital::utils::midiNoteToFrequency(low_cutoff_->getMinimum());
98 spectrogram_->setMinFrequency(min_frequency);
99 float max_frequency = vital::utils::midiNoteToFrequency(low_cutoff_->getMaximum());
100 spectrogram_->setMaxFrequency(max_frequency);
101 spectrogram_->setInterceptsMouseClicks(false, false);
102 spectrogram_->setFill(true);
103
104 eq_response_ = std::make_unique<EqualizerResponse>();
105 eq_response_->initEq(mono_modulations);
106 addOpenGlComponent(eq_response_.get());
107 eq_response_->setLowSliders(low_cutoff_.get(), low_resonance_.get(), low_gain_.get());
108 eq_response_->setBandSliders(band_cutoff_.get(), band_resonance_.get(), band_gain_.get());
109 eq_response_->setHighSliders(high_cutoff_.get(), high_resonance_.get(), high_gain_.get());
110 eq_response_->addListener(this);
111
112 on_ = std::make_unique<SynthButton>("eq_on");
113 addButton(on_.get());
114
115 selected_band_ = std::make_unique<TabSelector>("selected_band");
116 addAndMakeVisible(selected_band_.get());
117 addOpenGlComponent(selected_band_->getImageComponent());
118 selected_band_->setSliderStyle(Slider::LinearBar);
119 selected_band_->setRange(0, 2);
120 selected_band_->addListener(this);
121 selected_band_->setNames({"LOW", "BAND", "HIGH"});
122 selected_band_->setFontHeightPercent(0.4f);
123 selected_band_->setScrollWheelEnabled(false);
124
125 setActivator(on_.get());
128}
129
131
134
135 Colour lighten = findColour(Skin::kLightenScreen, true);
136 Colour background = findColour(Skin::kWidgetBackground, true);
137 Colour color = background.overlaidWith(lighten);
138 color = color.withAlpha(1.0f);
139 spectrogram_->setColour(Skin::kWidgetPrimary1, color);
140 spectrogram_->setColour(Skin::kWidgetPrimary2, color);
141 spectrogram_->setColour(Skin::kWidgetSecondary1, color);
142 spectrogram_->setColour(Skin::kWidgetSecondary2, color);
143 spectrogram_->setLineWidth(2.5f);
144
145 setLabelFont(g);
146 drawLabelForComponent(g, "GAIN", low_gain_.get());
147 drawLabelForComponent(g, "RESONANCE", low_resonance_.get());
148 drawLabelForComponent(g, "CUTOFF", low_cutoff_.get());
149
150 g.setColour(findColour(Skin::kTextComponentBackground, true));
151 float button_rounding = findValue(Skin::kLabelBackgroundRounding);
152 g.fillRoundedRectangle(low_mode_->getBounds().toFloat(), button_rounding);
153 g.fillRoundedRectangle(band_mode_->getBounds().toFloat(), button_rounding);
154 g.fillRoundedRectangle(high_mode_->getBounds().toFloat(), button_rounding);
155}
156
158 int title_width = getTitleWidth();
159 Rectangle<int> bounds = getLocalBounds().withLeft(title_width);
160 int widget_margin = findValue(Skin::kWidgetMargin);
161 Rectangle<int> widget_bounds = getDividedAreaUnbuffered(bounds, 2, 1, widget_margin);
162 spectrogram_->setBounds(widget_bounds.reduced(0, widget_margin));
163 eq_response_->setBounds(spectrogram_->getBounds());
164
165 Rectangle<int> knobs_area = getDividedAreaBuffered(bounds, 2, 0, widget_margin);
166
167 int button_height = getTextComponentHeight();
168 int section_height = getKnobSectionHeight();
169 int knob_y = getHeight() - section_height;
170 int button_y = widget_margin;
171
172 placeKnobsInArea(Rectangle<int>(knobs_area.getX(), knob_y, knobs_area.getWidth(), section_height),
173 { low_gain_.get(), low_cutoff_.get(), low_resonance_.get() });
174
175 band_cutoff_->setBounds(low_cutoff_->getBounds());
176 band_resonance_->setBounds(low_resonance_->getBounds());
177 band_gain_->setBounds(low_gain_->getBounds());
178
179 high_cutoff_->setBounds(low_cutoff_->getBounds());
180 high_resonance_->setBounds(low_resonance_->getBounds());
181 high_gain_->setBounds(low_gain_->getBounds());
182
183 low_mode_->setBounds(low_gain_->getX(), button_y, low_gain_->getWidth(), button_height);
184 band_mode_->setBounds(low_cutoff_->getX(), button_y, low_cutoff_->getWidth(), button_height);
185 high_mode_->setBounds(low_resonance_->getX(), button_y, low_resonance_->getWidth(), button_height);
186
187 int selected_y = low_mode_->getBottom() + widget_margin;
188 int selected_height = knob_y - selected_y + widget_margin;
189 selected_band_->setBounds(title_width + widget_margin, selected_y,
190 knobs_area.getWidth() - 2 * widget_margin, selected_height);
191
193}
194
196 eq_response_->setActive(active);
197 selected_band_->setActive(active);
200}
201
203 selected_band_->setValue(0.0, dontSendNotification);
204 selected_band_->redoImage();
205 low_cutoff_->setVisible(true);
206 low_resonance_->setVisible(true);
207 low_gain_->setVisible(true);
208
209 band_cutoff_->setVisible(false);
210 band_resonance_->setVisible(false);
211 band_gain_->setVisible(false);
212
213 high_cutoff_->setVisible(false);
214 high_resonance_->setVisible(false);
215 high_gain_->setVisible(false);
216}
217
219 selected_band_->setValue(1.0, dontSendNotification);
220 selected_band_->redoImage();
221 low_cutoff_->setVisible(false);
222 low_resonance_->setVisible(false);
223 low_gain_->setVisible(false);
224
225 band_cutoff_->setVisible(true);
226 band_resonance_->setVisible(true);
227 band_gain_->setVisible(true);
228
229 high_cutoff_->setVisible(false);
230 high_resonance_->setVisible(false);
231 high_gain_->setVisible(false);
232}
233
235 selected_band_->setValue(2.0, dontSendNotification);
236 selected_band_->redoImage();
237 low_cutoff_->setVisible(false);
238 low_resonance_->setVisible(false);
239 low_gain_->setVisible(false);
240
241 band_cutoff_->setVisible(false);
242 band_resonance_->setVisible(false);
243 band_gain_->setVisible(false);
244
245 high_cutoff_->setVisible(true);
246 high_resonance_->setVisible(true);
247 high_gain_->setVisible(true);
248}
249
251 if (slider == selected_band_.get()) {
252 if (selected_band_->getValue() == 0)
254 else if (selected_band_->getValue() == 1)
256 else if (selected_band_->getValue() == 2)
258
259 eq_response_->setSelectedBand(selected_band_->getValue());
260 }
261 else
263}
264
267 if (button == low_mode_.get()) {
268 eq_response_->setHighPass(low_mode_->getToggleState());
269 selected_band_->setValue(0);
270 }
271 else if (button == band_mode_.get()) {
272 eq_response_->setNotch(band_mode_->getToggleState());
273 selected_band_->setValue(1);
274 }
275 else if (button == high_mode_.get()) {
276 eq_response_->setLowPass(high_mode_->getToggleState());
277 selected_band_->setValue(2);
278 }
280}
281
283 selected_band_->setScrollWheelEnabled(enabled);
285}
286
288 low_gain_->setActive(isActive() && !low_mode_->getToggleState());
289 band_gain_->setActive(isActive() && !band_mode_->getToggleState());
290 high_gain_->setActive(isActive() && !high_mode_->getToggleState());
291}
292
294 if (parent_)
295 return;
296
297 parent_ = findParentComponentOfClass<SynthGuiInterface>();
298
299 if (parent_)
300 spectrogram_->setAudioMemory(parent_->getSynth()->getEqualizerMemory());
301}
302
304 if (parent_) {
305 int oversampling_amount = parent_->getSynth()->getEngine()->getOversamplingAmount();
306 if (oversampling_amount >= 1)
307 spectrogram_->setOversampleAmount(oversampling_amount);
308 }
309 spectrogram_->setColour(Skin::kWidgetPrimary1, findColour(Skin::kLightenScreen, true));
311}
void midBandSelected() override
Called when the mid band is selected in the EQ response.
Definition equalizer_section.cpp:218
EqualizerSection(String name, const vital::output_map &mono_modulations)
Definition equalizer_section.cpp:29
void parentHierarchyChanged() override
Called when the parent hierarchy changes, used to set up spectrogram memory.
Definition equalizer_section.cpp:293
void renderOpenGlComponents(OpenGlWrapper &open_gl, bool animate) override
Definition equalizer_section.cpp:303
void resized() override
Resizes and lays out child components (filter sliders, spectrogram, etc.).
Definition equalizer_section.cpp:157
void sliderValueChanged(Slider *slider) override
Definition equalizer_section.cpp:250
void paintBackground(Graphics &g) override
Definition equalizer_section.cpp:132
void setGainActive()
Sets the gain sliders active or inactive based on the current mode and active state.
Definition equalizer_section.cpp:287
void setActive(bool active) override
Definition equalizer_section.cpp:195
virtual ~EqualizerSection()
Destructor.
Definition equalizer_section.cpp:130
void highBandSelected() override
Called when the high band is selected in the EQ response.
Definition equalizer_section.cpp:234
void buttonClicked(Button *button) override
Definition equalizer_section.cpp:265
void lowBandSelected() override
Called when the low band is selected in the EQ response.
Definition equalizer_section.cpp:202
void setScrollWheelEnabled(bool enabled) override
Definition equalizer_section.cpp:282
static Path highPass()
Definition paths.h:853
static Path notch()
Definition paths.h:949
static Path lowPass(float line_thickness=0.1f)
Definition paths.h:842
@ kWidgetMargin
Definition skin.h:103
@ kLabelBackgroundRounding
Definition skin.h:74
@ 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
@ kTextComponentBackground
Definition skin.h:147
@ kWidgetSecondary2
Definition skin.h:169
@ kEqualizer
Definition skin.h:50
const vital::StereoMemory * getEqualizerMemory()
Retrieves memory used for equalizer visualization, if available.
Definition synth_base.cpp:724
vital::SoundEngine * getEngine()
Returns a pointer to the SoundEngine used for audio and modulation processing.
Definition synth_base.h:484
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
virtual void buttonClicked(Button *clicked_button) override
Called when a button is clicked. Updates the synth parameter accordingly.
Definition synth_section.cpp:398
virtual void renderOpenGlComponents(OpenGlWrapper &open_gl, bool animate)
Renders all OpenGL components in this section and sub-sections.
Definition synth_section.cpp:357
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
virtual void animate(bool animate)
Triggers animation state change in sub-sections if needed.
Definition synth_section.cpp:822
virtual void resized() override
Called when the component is resized. Arranges layout of child components.
Definition synth_section.cpp:35
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
bool isActive() const
Checks if the section is currently active.
Definition synth_section.h:683
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
virtual void sliderValueChanged(Slider *moved_slider) override
Called when a slider value changes. Updates the synth parameter accordingly.
Definition synth_section.cpp:391
float getTextComponentHeight()
Definition synth_section.cpp:652
Rectangle< int > getDividedAreaUnbuffered(Rectangle< int > full_area, int num_sections, int section, int buffer)
Divides an area into equal sections without extra buffering, returns the specified section.
Definition synth_section.cpp:768
void setSliderHasHzAlternateDisplay(SynthSlider *slider)
Definition synth_section.cpp:410
float getTitleWidth()
Definition synth_section.cpp:629
virtual void setScrollWheelEnabled(bool enabled)
Enables or disables scroll wheel support for this section and sub-sections.
Definition synth_section.cpp:481
void setSkinOverride(Skin::SectionOverride skin_override)
Definition synth_section.h:303
force_inline int getOversamplingAmount() const
Retrieves the current oversampling factor (e.g., 1, 2, 4).
Definition sound_engine.h:395
Declares the EqualizerSection class, providing a UI for a 3-band equalizer with adjustable modes and ...
force_inline poly_float midiNoteToFrequency(poly_float value)
Converts a MIDI note to a frequency (vectorized).
Definition poly_utils.h:123
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
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 TabSelector class, a slider-based UI component for selecting tabs.