Vital
Loading...
Searching...
No Matches
compressor_editor.cpp
Go to the documentation of this file.
1/*
2Note: For brevity, the cpp file code is unchanged apart from added Doxygen comments in the anonymous namespace. The bulk of the logic does not need repeated documentation at every function definition since it's mostly done in the header file. However, if desired, you can add /// comments above each function definition in the .cpp file as well, mirroring the header documentation.
3 */
4
5#include "compressor_editor.h"
6
7#include "skin.h"
8#include "shaders.h"
10#include "utils.h"
11
12namespace {
18 float getOpenGlYForDb(float db) {
20 return 2.0f * t - 1.0f;
21 }
22
28 vital::poly_float getOpenGlYForDb(vital::poly_float db) {
30 return vital::utils::clamp(t * 2.0f - 1.0f, -1.0f, 1.0f);
31 }
32
38 vital::poly_float getOpenGlYForMagnitude(vital::poly_float magnitude) {
40 return getOpenGlYForDb(db);
41 }
42
54 void setQuadIfRatioMatch(OpenGlMultiQuad& quads, float ratio, float ratio_match,
55 int index, float x, float y, float w, float h) {
56 if (ratio == ratio_match || (ratio > 0.0f && ratio_match > 0.0f) || (ratio < 0.0f && ratio_match < 0.0f))
57 quads.setQuad(index, x, y, w, h);
58 else
59 quads.setQuad(index, -2.0f, -2.0f, 0.0f, 0.0f);
60 }
61
68 std::string formatString(float value, std::string suffix) {
69 static constexpr int kMaxDecimalPlaces = 4;
70 String format = String(value, kMaxDecimalPlaces);
71
72 int display_characters = kMaxDecimalPlaces;
73 if (format[0] == '-')
74 display_characters += 1;
75
76 format = format.substring(0, display_characters);
77 if (format.getLastCharacter() == '.')
78 format = format.removeCharacters(".");
79
80 return format.toStdString() + suffix;
81 }
82} // namespace
83
84CompressorEditor::CompressorEditor() : hover_quad_(Shaders::kColorFragment),
85 input_dbs_(kNumChannels, Shaders::kColorFragment),
86 output_dbs_(kNumChannels, Shaders::kRoundedRectangleFragment),
87 thresholds_(kNumChannels, Shaders::kColorFragment),
88 ratio_lines_(kTotalRatioLines, Shaders::kFadeSquareFragment) {
90 addAndMakeVisible(hover_quad_);
91 addAndMakeVisible(input_dbs_);
92 addAndMakeVisible(output_dbs_);
93 addAndMakeVisible(thresholds_);
94 addAndMakeVisible(ratio_lines_);
95
96 parent_ = nullptr;
97 section_parent_ = nullptr;
98 hover_ = kNone;
99 animate_ = false;
100 high_band_active_ = true;
101 low_band_active_ = true;
102 size_ratio_ = 1.0f;
103 active_ = true;
104
105 // Initialize thresholds and ratios
106 low_upper_threshold_ = kMaxDb;
107 band_upper_threshold_ = kMaxDb;
108 high_upper_threshold_ = kMaxDb;
109 low_lower_threshold_ = kMinDb;
110 band_lower_threshold_ = kMinDb;
111 high_lower_threshold_ = kMinDb;
112 low_upper_ratio_ = 0.0f;
113 band_upper_ratio_ = 0.0f;
114 high_upper_ratio_ = 0.0f;
115 low_lower_ratio_ = 0.0f;
116 band_lower_ratio_ = 0.0f;
117 high_lower_ratio_ = 0.0f;
118
119 low_input_ms_ = nullptr;
120 band_input_ms_ = nullptr;
121 high_input_ms_ = nullptr;
122
123 low_output_ms_ = nullptr;
124 band_output_ms_ = nullptr;
125 high_output_ms_ = nullptr;
126}
127
129
130CompressorEditor::DragPoint CompressorEditor::getHoverPoint(const MouseEvent& e) {
131 float low_band_high_position = 3.0f * e.position.x / ((1.0f - kCompressorAreaBuffer) * getWidth());
132 int index = low_band_high_position;
133 float local_position = low_band_high_position - index;
134 if (index >= 3 || index < 0 || local_position < 3.0f * kCompressorAreaBuffer)
135 return kNone;
136
137 if (index == 0 && !low_band_active_)
138 index = 1;
139 if (index == 2 && !high_band_active_)
140 index = 1;
141
142 float upper_threshold_values[] = { low_upper_threshold_, band_upper_threshold_, high_upper_threshold_ };
143 float lower_threshold_values[] = { low_lower_threshold_, band_lower_threshold_, high_lower_threshold_ };
144 DragPoint upper_threshold_points[] = { kLowUpperThreshold, kBandUpperThreshold, kHighUpperThreshold };
145 DragPoint lower_threshold_points[] = { kLowLowerThreshold, kBandLowerThreshold, kHighLowerThreshold };
146 DragPoint upper_ratio_points[] = { kLowUpperRatio, kBandUpperRatio, kHighUpperRatio };
147 DragPoint lower_ratio_points[] = { kLowLowerRatio, kBandLowerRatio, kHighLowerRatio };
148
149 float grab_radius = kGrabRadius * size_ratio_;
150 int upper_handle_y = std::max(grab_radius, getYForDb(upper_threshold_values[index]));
151 int lower_handle_y = std::min(getHeight() - grab_radius, getYForDb(lower_threshold_values[index]));
152
153 float delta_upper = e.position.y - upper_handle_y;
154 float delta_lower = e.position.y - lower_handle_y;
155 if (fabsf(delta_upper) <= grab_radius && fabsf(delta_upper) < fabsf(delta_lower))
156 return upper_threshold_points[index];
157 if (fabsf(delta_lower) <= grab_radius)
158 return lower_threshold_points[index];
159 if (delta_upper < 0.0f)
160 return upper_ratio_points[index];
161 if (delta_lower > 0.0f)
162 return lower_ratio_points[index];
163 return kNone;
164}
165
166void CompressorEditor::mouseDown(const MouseEvent& e) {
167 last_mouse_position_ = e.getPosition();
168 mouseDrag(e);
169}
170
171void CompressorEditor::mouseDoubleClick(const MouseEvent& e) {
172 if (isRatio(hover_)) {
173 switch (hover_) {
174 case kLowUpperRatio:
175 setLowUpperRatio(0.0f);
176 break;
177 case kBandUpperRatio:
178 setBandUpperRatio(0.0f);
179 break;
180 case kHighUpperRatio:
181 setHighUpperRatio(0.0f);
182 break;
183 case kLowLowerRatio:
184 setLowLowerRatio(0.0f);
185 break;
186 case kBandLowerRatio:
187 setBandLowerRatio(0.0f);
188 break;
189 case kHighLowerRatio:
190 setHighLowerRatio(0.0f);
191 break;
192 default:
193 break;
194 }
195 }
196}
197
198void CompressorEditor::mouseMove(const MouseEvent& e) {
199 hover_ = getHoverPoint(e);
200
201 if (hover_ != kNone)
202 setMouseCursor(MouseCursor::BottomEdgeResizeCursor);
203 else
204 setMouseCursor(MouseCursor::NormalCursor);
205}
206
207void CompressorEditor::mouseDrag(const MouseEvent& e) {
208 if (hover_ == kNone || parent_ == nullptr)
209 return;
210
211 float delta = (e.getPosition().y - last_mouse_position_.y) * kMouseMultiplier / getHeight();
212 float delta_db_value = (kMinDb - kMaxDb) * delta;
213
214 last_mouse_position_ = e.getPosition();
215 float delta_ratio = delta * kRatioEditMultiplier;
216
217 if (e.mods.isShiftDown()) {
218 setLowUpperThreshold(low_upper_threshold_ + delta_db_value, false);
219 setBandUpperThreshold(band_upper_threshold_ + delta_db_value, false);
220 setHighUpperThreshold(high_upper_threshold_ + delta_db_value, false);
221 setLowLowerThreshold(low_lower_threshold_ + delta_db_value, false);
222 setBandLowerThreshold(band_lower_threshold_ + delta_db_value, false);
223 setHighLowerThreshold(high_lower_threshold_ + delta_db_value, false);
224 }
225 else {
226 switch (hover_) {
227 case kLowUpperThreshold:
228 setLowUpperThreshold(low_upper_threshold_ + delta_db_value, true);
229 break;
230 case kLowUpperRatio:
231 setLowUpperRatio(low_upper_ratio_ + delta_ratio);
232 break;
233 case kBandUpperThreshold:
234 setBandUpperThreshold(band_upper_threshold_ + delta_db_value, true);
235 break;
236 case kBandUpperRatio:
237 setBandUpperRatio(band_upper_ratio_ + delta_ratio);
238 break;
239 case kHighUpperThreshold:
240 setHighUpperThreshold(high_upper_threshold_ + delta_db_value, true);
241 break;
242 case kHighUpperRatio:
243 setHighUpperRatio(high_upper_ratio_ + delta_ratio);
244 break;
245 case kLowLowerThreshold:
246 setLowLowerThreshold(low_lower_threshold_ + delta_db_value, true);
247 break;
248 case kLowLowerRatio:
249 setLowLowerRatio(low_lower_ratio_ - delta_ratio);
250 break;
251 case kBandLowerThreshold:
252 setBandLowerThreshold(band_lower_threshold_ + delta_db_value, true);
253 break;
254 case kBandLowerRatio:
255 setBandLowerRatio(band_lower_ratio_ - delta_ratio);
256 break;
257 case kHighLowerThreshold:
258 setHighLowerThreshold(high_lower_threshold_ + delta_db_value, true);
259 break;
260 case kHighLowerRatio:
261 setHighLowerRatio(high_lower_ratio_ - delta_ratio);
262 break;
263 default:
264 break;
265 }
266 }
267}
268
269void CompressorEditor::mouseUp(const MouseEvent& e) {
270 if (isRatio(hover_))
271 setMouseCursor(MouseCursor::BottomEdgeResizeCursor);
272
273 section_parent_->hidePopupDisplay(true);
274}
275
276void CompressorEditor::mouseExit(const MouseEvent& e) {
277 setMouseCursor(MouseCursor::NormalCursor);
278 hover_ = kNone;
279}
280
283
284 g.setColour(findColour(Skin::kLightenScreen, true));
285 for (int i = 1; i < kDbLineSections; ++i) {
286 float t = (i * 1.0f) / kDbLineSections;
287 int y = getHeight() * t;
288 g.fillRect(0, y, getWidth(), 1);
289 }
290}
291
294 hover_quad_.setBounds(getLocalBounds());
295 input_dbs_.setBounds(getLocalBounds());
296 output_dbs_.setBounds(getLocalBounds());
297 thresholds_.setBounds(getLocalBounds());
298 ratio_lines_.setBounds(getLocalBounds());
299}
300
302 OpenGlComponent::init(open_gl);
303 hover_quad_.init(open_gl);
304 input_dbs_.init(open_gl);
305 output_dbs_.init(open_gl);
306 thresholds_.init(open_gl);
307 ratio_lines_.init(open_gl);
308}
309
310void CompressorEditor::render(OpenGlWrapper& open_gl, bool animate) {
311 renderCompressor(open_gl, animate);
312 renderCorners(open_gl, animate);
313}
314
315void CompressorEditor::setThresholdPositions(int low_start, int low_end, int band_start, int band_end,
316 int high_start, int high_end, float ratio_match) {
317 thresholds_.setColor(getColorForRatio(ratio_match));
318 float width = getWidth();
319
320 float low_start_x = low_start * 2.0f / width - 1.0f;
321 float low_width = (low_end - low_start) * 2.0f / width;
322 float band_start_x = band_start * 2.0f / width - 1.0f;
323 float band_width = (band_end - band_start) * 2.0f / width;
324 float high_start_x = high_start * 2.0f / width - 1.0f;
325 float high_width = (high_end - high_start) * 2.0f / width;
326
327 setQuadIfRatioMatch(thresholds_, -low_lower_ratio_, ratio_match, 0,
328 low_start_x, -1.0f, low_width, getOpenGlYForDb(low_lower_threshold_) + 1.0f);
329 setQuadIfRatioMatch(thresholds_, low_upper_ratio_, ratio_match, 1,
330 low_start_x, 1.0f, low_width, getOpenGlYForDb(low_upper_threshold_) - 1.0f);
331 setQuadIfRatioMatch(thresholds_, -band_lower_ratio_, ratio_match, 2,
332 band_start_x, -1.0f, band_width, getOpenGlYForDb(band_lower_threshold_) + 1.0f);
333 setQuadIfRatioMatch(thresholds_, band_upper_ratio_, ratio_match, 3,
334 band_start_x, 1.0f, band_width, getOpenGlYForDb(band_upper_threshold_) - 1.0f);
335 setQuadIfRatioMatch(thresholds_, -high_lower_ratio_, ratio_match, 4,
336 high_start_x, -1.0f, high_width, getOpenGlYForDb(high_lower_threshold_) + 1.0f);
337 setQuadIfRatioMatch(thresholds_, high_upper_ratio_, ratio_match, 5,
338 high_start_x, 1.0f, high_width, getOpenGlYForDb(high_upper_threshold_) - 1.0f);
339}
340
341void CompressorEditor::setRatioLines(int start_index, int start_x, int end_x,
342 float threshold, float ratio, bool upper, bool hover) {
343
344 float db_position = kDbLineSections * (threshold - kMinDb) / (kMaxDb - kMinDb);
345 int db_index = db_position;
346 float db_change = -(kMaxDb - kMinDb) / kDbLineSections;
347 if (upper) {
348 db_change = (kMaxDb - kMinDb) / kDbLineSections;
349 db_index = ceil(db_position);
350 }
351
352 float width = getWidth();
353 float x = start_x * 2.0f / width - 1.0f;
354 float ratio_width = (end_x - start_x) * 2.0f / width;
355 float ratio_height = 4.0f / getHeight();
356
357 float mult = hover ? 5.0f : 2.5f;
358
359 float db = db_index * (kMaxDb - kMinDb) / kDbLineSections + kMinDb;
360 for (int i = 0; i < kRatioDbLines; ++i) {
361 float adjusted_db = getCompressedDb(db, threshold, ratio, threshold, ratio);
362 ratio_lines_.setQuad(start_index + i, x, getOpenGlYForDb(adjusted_db) - ratio_height * 0.5f,
363 ratio_width, ratio_height);
364 ratio_lines_.setShaderValue(start_index + i, (kRatioDbLines - i) * mult / kRatioDbLines);
365 db += db_change;
366 }
367}
368
369void CompressorEditor::setRatioLinePositions(int low_start, int low_end, int band_start, int band_end,
370 int high_start, int high_end) {
371 setRatioLines(0, low_start, low_end, low_upper_threshold_, low_upper_ratio_,
372 true, hover_ == kLowUpperRatio);
373 setRatioLines(kRatioDbLines, low_start, low_end, low_lower_threshold_, low_lower_ratio_,
374 false, hover_ == kLowLowerRatio);
375 setRatioLines(2 * kRatioDbLines, band_start, band_end, band_upper_threshold_, band_upper_ratio_,
376 true, hover_ == kBandUpperRatio);
377 setRatioLines(3 * kRatioDbLines, band_start, band_end, band_lower_threshold_, band_lower_ratio_,
378 false, hover_ == kBandLowerRatio);
379 setRatioLines(4 * kRatioDbLines, high_start, high_end, high_upper_threshold_, high_upper_ratio_,
380 true, hover_ == kHighUpperRatio);
381 setRatioLines(5 * kRatioDbLines, high_start, high_end, high_lower_threshold_, high_lower_ratio_,
382 false, hover_ == kHighLowerRatio);
383}
384
385void CompressorEditor::renderHover(OpenGlWrapper& open_gl, int low_start, int low_end,
386 int band_start, int band_end, int high_start, int high_end) {
387 if (hover_ == kNone)
388 return;
389
390 float width = getWidth();
391 float height = getHeight();
392 float threshold_height = 2.0f / height;
393
394 float low_start_x = low_start * 2.0f / width - 1.0f;
395 float low_width = (low_end - low_start) * 2.0f / width;
396 float band_start_x = band_start * 2.0f / width - 1.0f;
397 float band_width = (band_end - band_start) * 2.0f / width;
398 float high_start_x = high_start * 2.0f / width - 1.0f;
399 float high_width = (high_end - high_start) * 2.0f / width;
400
401 switch (hover_) {
402 case kLowUpperThreshold:
403 hover_quad_.setQuad(0, low_start_x, getOpenGlYForDb(low_upper_threshold_) - 0.5f * threshold_height,
404 low_width, threshold_height);
405 break;
406 case kBandUpperThreshold:
407 hover_quad_.setQuad(0, band_start_x, getOpenGlYForDb(band_upper_threshold_) - 0.5f * threshold_height,
408 band_width, threshold_height);
409 break;
410 case kHighUpperThreshold:
411 hover_quad_.setQuad(0, high_start_x, getOpenGlYForDb(high_upper_threshold_) - 0.5f * threshold_height,
412 high_width, threshold_height);
413 break;
414 case kLowLowerThreshold:
415 hover_quad_.setQuad(0, low_start_x, getOpenGlYForDb(low_lower_threshold_) - 0.5f * threshold_height,
416 low_width, threshold_height);
417 break;
418 case kBandLowerThreshold:
419 hover_quad_.setQuad(0, band_start_x, getOpenGlYForDb(band_lower_threshold_) - 0.5f * threshold_height,
420 band_width, threshold_height);
421 break;
422 case kHighLowerThreshold:
423 hover_quad_.setQuad(0, high_start_x, getOpenGlYForDb(high_lower_threshold_) - 0.5f * threshold_height,
424 high_width, threshold_height);
425 break;
426 default:
427 return;
428 }
429
430 if (isRatio(hover_))
431 hover_quad_.setColor(findColour(Skin::kLightenScreen, true));
432 else
433 hover_quad_.setColor(findColour(Skin::kWidgetCenterLine, true));
434
435 hover_quad_.render(open_gl, true);
436}
437
439 static constexpr float kOutputBarHeight = 2.2f;
440 if (low_input_ms_ == nullptr || band_input_ms_ == nullptr || high_input_ms_ == nullptr ||
441 low_output_ms_ == nullptr || band_output_ms_ == nullptr || high_output_ms_ == nullptr) {
442 return;
443 }
444
445 vital::poly_float low_rms = vital::utils::sqrt(low_input_ms_->value());
446 vital::poly_float low_input_y = getOpenGlYForMagnitude(low_rms);
447
448 vital::poly_float scaled_low_rms = vital::utils::sqrt(low_output_ms_->value());
449 vital::poly_float low_output_y = getOpenGlYForMagnitude(scaled_low_rms);
450
451 vital::poly_float band_rms = vital::utils::sqrt(band_input_ms_->value());
452 vital::poly_float band_input_y = getOpenGlYForMagnitude(band_rms);
453
454 vital::poly_float scaled_band_rms = vital::utils::sqrt(band_output_ms_->value());
455 vital::poly_float band_output_y = getOpenGlYForMagnitude(scaled_band_rms);
456
457 vital::poly_float high_rms = vital::utils::sqrt(high_input_ms_->value());
458 vital::poly_float high_input_y = getOpenGlYForMagnitude(high_rms);
459
460 vital::poly_float scaled_high_rms = vital::utils::sqrt(high_output_ms_->value());
461 vital::poly_float high_output_y = getOpenGlYForMagnitude(scaled_high_rms);
462
463 int width = getWidth();
464 float active_area = 1.0f - 4.0f * kCompressorAreaBuffer;
465 float active_section_width = active_area / kMaxBands;
466
467 int low_start = std::round(kCompressorAreaBuffer * width);
468 int low_end = std::round((kCompressorAreaBuffer + active_section_width) * width);
469 int band_start = std::round((2.0f * kCompressorAreaBuffer + active_section_width) * width);
470 int band_end = width - band_start;
471 int high_start = width - low_end;
472 int high_end = width - low_start;
473
474 if (!low_band_active_) {
475 band_start = low_start;
476 low_start = low_end = -width;
477 }
478 if (!high_band_active_) {
479 band_end = high_end;
480 high_start = high_end = -width;
481 }
482
483 setThresholdPositions(low_start, low_end, band_start, band_end, high_start, high_end, 1.0f);
484 thresholds_.render(open_gl, true);
485
486 setThresholdPositions(low_start, low_end, band_start, band_end, high_start, high_end, 0.0f);
487 thresholds_.render(open_gl, true);
488
489 setThresholdPositions(low_start, low_end, band_start, band_end, high_start, high_end, -1.0f);
490 thresholds_.render(open_gl, true);
491
492 setRatioLinePositions(low_start, low_end, band_start, band_end, high_start, high_end);
493 ratio_lines_.setColor(findColour(Skin::kLightenScreen, true));
494 ratio_lines_.render(open_gl, true);
495
496 renderHover(open_gl, low_start, low_end, band_start, band_end, high_start, high_end);
497
498 int bar_width = kBarWidth * active_section_width * width;
499 int low_middle = (low_start + low_end) * 0.5f;
500 int band_middle = (band_start + band_end) * 0.5f;
501 int high_middle = (high_start + high_end) * 0.5f;
502
503 float gl_bar_width = bar_width * 2.0f / width;
504 float low_left = (low_middle - bar_width) * 2.0f / width - 1.0f;
505 float low_right = (low_middle + 1) * 2.0f / width - 1.0f;
506 float band_left = (band_middle - bar_width) * 2.0f / width - 1.0f;
507 float band_right = (band_middle + 1) * 2.0f / width - 1.0f;
508 float high_left = (high_middle - bar_width) * 2.0f / width - 1.0f;
509 float high_right = (high_middle + 1) * 2.0f / width - 1.0f;
510 output_dbs_.setQuad(0, low_left, low_output_y[0] - kOutputBarHeight, gl_bar_width, kOutputBarHeight);
511 output_dbs_.setQuad(1, low_right, low_output_y[1] - kOutputBarHeight, gl_bar_width, kOutputBarHeight);
512 output_dbs_.setQuad(2, band_left, band_output_y[0] - kOutputBarHeight, gl_bar_width, kOutputBarHeight);
513 output_dbs_.setQuad(3, band_right, band_output_y[1] - kOutputBarHeight, gl_bar_width, kOutputBarHeight);
514 output_dbs_.setQuad(4, high_left, high_output_y[0] - kOutputBarHeight, gl_bar_width, kOutputBarHeight);
515 output_dbs_.setQuad(5, high_right, high_output_y[1] - kOutputBarHeight, gl_bar_width, kOutputBarHeight);
516
517 float input_height = 2.0f / getHeight();
518 input_dbs_.setQuad(0, low_left, low_input_y[0] - 0.5f * input_height, gl_bar_width, input_height);
519 input_dbs_.setQuad(1, low_right, low_input_y[1] - 0.5f * input_height, gl_bar_width, input_height);
520 input_dbs_.setQuad(2, band_left, band_input_y[0] - 0.5f * input_height, gl_bar_width, input_height);
521 input_dbs_.setQuad(3, band_right, band_input_y[1] - 0.5f * input_height, gl_bar_width, input_height);
522 input_dbs_.setQuad(4, high_left, high_input_y[0] - 0.5f * input_height, gl_bar_width, input_height);
523 input_dbs_.setQuad(5, high_right, high_input_y[1] - 0.5f * input_height, gl_bar_width, input_height);
524
525 output_dbs_.setColor(findColour(Skin::kWidgetPrimary1, true));
526 output_dbs_.render(open_gl, animate);
527
528 input_dbs_.setColor(findColour(Skin::kWidgetPrimary2, true));
529 input_dbs_.render(open_gl, animate);
530}
531
534 hover_quad_.destroy(open_gl);
535 input_dbs_.destroy(open_gl);
536 output_dbs_.destroy(open_gl);
537 thresholds_.destroy(open_gl);
538 ratio_lines_.destroy(open_gl);
539}
540
542 low_upper_threshold_ = controls["compressor_low_upper_threshold"]->value();
543 band_upper_threshold_ = controls["compressor_band_upper_threshold"]->value();
544 high_upper_threshold_ = controls["compressor_high_upper_threshold"]->value();
545 low_lower_threshold_ = controls["compressor_low_lower_threshold"]->value();
546 band_lower_threshold_ = controls["compressor_band_lower_threshold"]->value();
547 high_lower_threshold_ = controls["compressor_high_lower_threshold"]->value();
548 low_upper_ratio_ = controls["compressor_low_upper_ratio"]->value();
549 band_upper_ratio_ = controls["compressor_band_upper_ratio"]->value();
550 high_upper_ratio_ = controls["compressor_high_upper_ratio"]->value();
551 low_lower_ratio_ = controls["compressor_low_lower_ratio"]->value();
552 band_lower_ratio_ = controls["compressor_band_lower_ratio"]->value();
553 high_lower_ratio_ = controls["compressor_high_lower_ratio"]->value();
554}
555
556void CompressorEditor::setLowUpperThreshold(float db, bool clamp) {
557 low_upper_threshold_ = db;
559 SynthBase* synth = parent_->getSynth();
560
561 if (clamp)
562 low_upper_threshold_ = db;
563 synth->valueChangedInternal("compressor_low_upper_threshold", db);
564 if (low_upper_threshold_ < low_lower_threshold_ && clamp)
565 setLowLowerThreshold(db, clamp);
566
567 section_parent_->showPopupDisplay(this, formatString(low_upper_threshold_, " dB"), BubbleComponent::below, true);
568}
569
570void CompressorEditor::setBandUpperThreshold(float db, bool clamp) {
571 band_upper_threshold_ = db;
573 SynthBase* synth = parent_->getSynth();
574
575 if (clamp)
576 band_upper_threshold_ = db;
577 synth->valueChangedInternal("compressor_band_upper_threshold", db);
578 if (band_upper_threshold_ < band_lower_threshold_ && clamp)
579 setBandLowerThreshold(db, clamp);
580
581 section_parent_->showPopupDisplay(this, formatString(band_upper_threshold_, " dB"), BubbleComponent::below, true);
582}
583
584void CompressorEditor::setHighUpperThreshold(float db, bool clamp) {
585 high_upper_threshold_ = db;
587 SynthBase* synth = parent_->getSynth();
588
589 if (clamp)
590 high_upper_threshold_ = db;
591 synth->valueChangedInternal("compressor_high_upper_threshold", db);
592 if (high_upper_threshold_ < high_lower_threshold_ && clamp)
593 setHighLowerThreshold(db, clamp);
594
595 section_parent_->showPopupDisplay(this, formatString(high_upper_threshold_, " dB"), BubbleComponent::below, true);
596}
597
598void CompressorEditor::setLowLowerThreshold(float db, bool clamp) {
599 low_lower_threshold_ = db;
601 SynthBase* synth = parent_->getSynth();
602
603 if (clamp)
604 low_lower_threshold_ = db;
605 synth->valueChangedInternal("compressor_low_lower_threshold", db);
606 if (low_lower_threshold_ > low_upper_threshold_ && clamp)
607 setLowUpperThreshold(db, clamp);
608
609 section_parent_->showPopupDisplay(this, formatString(low_lower_threshold_, " dB"), BubbleComponent::below, true);
610}
611
612void CompressorEditor::setBandLowerThreshold(float db, bool clamp) {
613 band_lower_threshold_ = db;
615 SynthBase* synth = parent_->getSynth();
616
617 if (clamp)
618 band_lower_threshold_ = db;
619 synth->valueChangedInternal("compressor_band_lower_threshold", db);
620 if (band_lower_threshold_ > band_upper_threshold_ && clamp)
621 setBandUpperThreshold(db, clamp);
622
623 section_parent_->showPopupDisplay(this, formatString(band_lower_threshold_, " dB"), BubbleComponent::below, true);
624}
625
626void CompressorEditor::setHighLowerThreshold(float db, bool clamp ) {
627 high_lower_threshold_ = db;
629 SynthBase* synth = parent_->getSynth();
630
631 if (clamp)
632 high_lower_threshold_ = db;
633 synth->valueChangedInternal("compressor_high_lower_threshold", db);
634 if (high_lower_threshold_ > high_upper_threshold_ && clamp)
635 setHighUpperThreshold(db, clamp);
636
637 section_parent_->showPopupDisplay(this, formatString(high_lower_threshold_, " dB"), BubbleComponent::below, true);
638}
639
640void CompressorEditor::setLowUpperRatio(float ratio) {
641 SynthBase* synth = parent_->getSynth();
642
643 low_upper_ratio_ = vital::utils::clamp(ratio, kMinUpperRatio, kMaxUpperRatio);
644 synth->valueChangedInternal("compressor_low_upper_ratio", ratio);
645}
646
647void CompressorEditor::setBandUpperRatio(float ratio) {
648 SynthBase* synth = parent_->getSynth();
649
650 band_upper_ratio_ = vital::utils::clamp(ratio, kMinUpperRatio, kMaxUpperRatio);
651 synth->valueChangedInternal("compressor_band_upper_ratio", ratio);
652}
653
654void CompressorEditor::setHighUpperRatio(float ratio) {
655 SynthBase* synth = parent_->getSynth();
656
657 high_upper_ratio_ = vital::utils::clamp(ratio, kMinUpperRatio, kMaxUpperRatio);
658 synth->valueChangedInternal("compressor_high_upper_ratio", ratio);
659}
660
661void CompressorEditor::setLowLowerRatio(float ratio) {
662 SynthBase* synth = parent_->getSynth();
663
664 low_lower_ratio_ = vital::utils::clamp(ratio, kMinLowerRatio, kMaxLowerRatio);
665 synth->valueChangedInternal("compressor_low_lower_ratio", ratio);
666}
667
668void CompressorEditor::setBandLowerRatio(float ratio) {
669 SynthBase* synth = parent_->getSynth();
670
671 band_lower_ratio_ = vital::utils::clamp(ratio, kMinLowerRatio, kMaxLowerRatio);
672 synth->valueChangedInternal("compressor_band_lower_ratio", ratio);
673}
674
675void CompressorEditor::setHighLowerRatio(float ratio) {
676 SynthBase* synth = parent_->getSynth();
677
678 high_lower_ratio_ = vital::utils::clamp(ratio, kMinLowerRatio, kMaxLowerRatio);
679 synth->valueChangedInternal("compressor_high_lower_ratio", ratio);
680}
681
682String CompressorEditor::formatValue(float value) {
683 static constexpr int number_length = 5;
684 static constexpr int max_decimals = 3;
685
686 String format = String(value, max_decimals);
687 format = format.substring(0, number_length);
688 int spaces = number_length - format.length();
689
690 for (int i = 0; i < spaces; ++i)
691 format = " " + format;
692
693 return format;
694}
695
697 if (parent_ == nullptr)
698 parent_ = findParentComponentOfClass<SynthGuiInterface>();
699
700 if (section_parent_ == nullptr)
701 section_parent_ = findParentComponentOfClass<SynthSection>();
702
703 if (parent_ == nullptr)
704 return;
705
706 if (low_input_ms_ == nullptr)
707 low_input_ms_ = parent_->getSynth()->getStatusOutput("compressor_low_input");
708 if (band_input_ms_ == nullptr)
709 band_input_ms_ = parent_->getSynth()->getStatusOutput("compressor_band_input");
710 if (high_input_ms_ == nullptr)
711 high_input_ms_ = parent_->getSynth()->getStatusOutput("compressor_high_input");
712 if (low_output_ms_ == nullptr)
713 low_output_ms_ = parent_->getSynth()->getStatusOutput("compressor_low_output");
714 if (band_output_ms_ == nullptr)
715 band_output_ms_ = parent_->getSynth()->getStatusOutput("compressor_band_output");
716 if (high_output_ms_ == nullptr)
717 high_output_ms_ = parent_->getSynth()->getStatusOutput("compressor_high_output");
718
720}
721
722float CompressorEditor::getYForDb(float db) {
723 return getHeight() * (1.0f - getOpenGlYForDb(vital::utils::clamp(db, kMinDb, kMaxDb))) * 0.5f;
724}
725
726float CompressorEditor::getCompressedDb(float input_db, float upper_threshold, float upper_ratio,
727 float lower_threshold, float lower_ratio) {
728 if (input_db < lower_threshold)
729 return vital::utils::interpolate(input_db, lower_threshold, lower_ratio);
730 if (input_db > upper_threshold)
731 return vital::utils::interpolate(input_db, upper_threshold, upper_ratio);
732 return input_db;
733}
734
735Colour CompressorEditor::getColorForRatio(float ratio) {
736 if (!active_)
737 return findColour(Skin::kWidgetSecondaryDisabled, true);
738
739 if (ratio > 0.0f)
740 return findColour(Skin::kWidgetSecondary1, true);
741 if (ratio < 0.0f)
742 return findColour(Skin::kWidgetSecondary2, true);
743
744 return findColour(Skin::kWidgetSecondaryDisabled, true);
745}
void mouseUp(const MouseEvent &e) override
Handles mouse up events.
Definition compressor_editor.cpp:269
static constexpr float kMouseMultiplier
General multiplier for mouse-drag edits.
Definition compressor_editor.h:60
static constexpr int kMaxBands
Maximum number of bands supported.
Definition compressor_editor.h:63
CompressorEditor()
Constructs a new CompressorEditor.
Definition compressor_editor.cpp:84
void destroy(OpenGlWrapper &open_gl) override
Destroys and cleans up OpenGL-related objects.
Definition compressor_editor.cpp:532
static constexpr float kMinLowerRatio
Minimum ratio value for the lower ratio segments.
Definition compressor_editor.h:40
void mouseDown(const MouseEvent &e) override
Handles mouse down events.
Definition compressor_editor.cpp:166
void mouseDrag(const MouseEvent &e) override
Handles mouse drag events.
Definition compressor_editor.cpp:207
static constexpr float kGrabRadius
Grab radius in pixels for clickable points (thresholds, ratio handles).
Definition compressor_editor.h:25
static constexpr float kMinUpperRatio
Minimum ratio value for the upper ratio segments.
Definition compressor_editor.h:44
static constexpr float kCompressorAreaBuffer
Buffer area around the compressor visualization.
Definition compressor_editor.h:52
static constexpr float kMaxEditDb
Maximum editable dB value (slightly below kMaxDb).
Definition compressor_editor.h:37
static constexpr float kMinDb
Minimum decibel value displayed in the compressor editor.
Definition compressor_editor.h:28
static constexpr float kMinEditDb
Minimum editable dB value (slightly above kMinDb).
Definition compressor_editor.h:35
void renderCompressor(OpenGlWrapper &open_gl, bool animate)
Renders the compressor-specific elements.
Definition compressor_editor.cpp:438
void resized() override
Called when the component is resized.
Definition compressor_editor.cpp:292
static constexpr int kDbLineSections
Number of dB line sections in the display.
Definition compressor_editor.h:68
static constexpr int kRatioDbLines
Total number of dB lines for ratio calculations.
Definition compressor_editor.h:72
static constexpr float kBarWidth
Width of the displayed bars relative to the component width.
Definition compressor_editor.h:54
void init(OpenGlWrapper &open_gl) override
Initializes the OpenGL context and related objects.
Definition compressor_editor.cpp:301
void setAllValues(vital::control_map &controls)
Sets all threshold and ratio values from a given control map.
Definition compressor_editor.cpp:541
static constexpr float kRatioEditMultiplier
Multiplier applied to ratio edits for finer control.
Definition compressor_editor.h:49
virtual ~CompressorEditor()
Destructor.
Definition compressor_editor.cpp:128
static constexpr float kMaxLowerRatio
Maximum ratio value for the lower ratio segments.
Definition compressor_editor.h:42
static constexpr float kMaxDb
Maximum decibel value displayed in the compressor editor.
Definition compressor_editor.h:30
static constexpr float kMaxUpperRatio
Maximum ratio value for the upper ratio segments.
Definition compressor_editor.h:46
void parentHierarchyChanged() override
Called when the component's parent hierarchy changes, used for initialization.
Definition compressor_editor.cpp:696
void paintBackground(Graphics &g) override
Draws the background of the editor.
Definition compressor_editor.cpp:281
void mouseDoubleClick(const MouseEvent &e) override
Handles mouse double-click events.
Definition compressor_editor.cpp:171
void mouseMove(const MouseEvent &e) override
Handles mouse move events (primarily used for updating hover state).
Definition compressor_editor.cpp:198
void mouseExit(const MouseEvent &e) override
Handles mouse exit events.
Definition compressor_editor.cpp:276
void render(OpenGlWrapper &open_gl, bool animate) override
Renders the compressor visualization.
Definition compressor_editor.cpp:310
void addRoundedCorners()
Adds rounded corners to the component's edges.
Definition open_gl_component.cpp:138
virtual void resized() override
Called when the component is resized.
Definition open_gl_component.cpp:121
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
virtual void destroy(OpenGlWrapper &open_gl)
Destroys any OpenGL-specific resources allocated by this component.
Definition open_gl_component.cpp:168
virtual void paintBackground(Graphics &g)
Paints a standard background for the component.
Definition open_gl_component.cpp:105
virtual void init(OpenGlWrapper &open_gl)
Initializes any OpenGL-specific resources needed by the component.
Definition open_gl_component.cpp:148
virtual void parentHierarchyChanged() override
Called when the component's parent hierarchy changes.
Definition open_gl_component.cpp:128
A component for rendering multiple quads using OpenGL, with customizable colors, rounding,...
Definition open_gl_multi_quad.h:16
void setShaderValue(int i, float shader_value, int value_index=0)
Sets a shader value for all four vertices of a quad.
Definition open_gl_multi_quad.h:254
virtual void init(OpenGlWrapper &open_gl) override
Initializes OpenGL buffers and shader attributes.
Definition open_gl_multi_quad.cpp:37
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
virtual void render(OpenGlWrapper &open_gl, bool animate) override
Renders the quads using OpenGL.
Definition open_gl_multi_quad.cpp:92
virtual void destroy(OpenGlWrapper &open_gl) override
Releases OpenGL resources when the component is destroyed.
Definition open_gl_multi_quad.cpp:69
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
@ kWidgetPrimary2
Definition skin.h:166
@ kWidgetPrimary1
Definition skin.h:165
@ kWidgetSecondary1
Definition skin.h:168
@ kLightenScreen
Definition skin.h:141
@ kWidgetSecondaryDisabled
Definition skin.h:170
@ kWidgetCenterLine
Definition skin.h:164
@ kWidgetSecondary2
Definition skin.h:169
A base class providing foundational functionality for the Vital synthesizer’s engine,...
Definition synth_base.h:42
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
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
void hidePopupDisplay(bool primary)
Hides the currently shown popup display.
Definition synth_section.cpp:140
void showPopupDisplay(Component *source, const std::string &text, BubbleComponent::BubblePlacement placement, bool primary)
Shows a brief popup display (like a tooltip).
Definition synth_section.cpp:133
force_inline poly_float value() const
Returns the current status value.
Definition synth_module.h:49
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 magnitudeToDb(poly_float value)
Converts a magnitude value to decibels (vectorized).
Definition poly_utils.h:144
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 sqrt(poly_float value)
Computes the square root of each element in a poly_float.
Definition poly_utils.h:169
force_inline poly_float interpolate(poly_float from, poly_float to, mono_float t)
Performs a linear interpolation between two poly_floats using a scalar t in [0..1].
Definition poly_utils.h:182
force_inline poly_float ceil(poly_float value)
Ceils each lane in value.
Definition poly_utils.h:799
std::map< std::string, Value * > control_map
Maps parameter names to Value pointers representing synth control parameters.
Definition synth_types.h:214
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
Provides various utility functions, classes, and constants for audio, math, and general-purpose opera...