From 4022fdd37cd71b0d950a20b3ec63b84f7e38c7b3 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Wed, 22 Mar 2023 00:17:17 +0100 Subject: [PATCH] Draw separate upwards and downwards curves --- plugins/spectral_compressor/src/analyzer.rs | 4 ++ .../src/compressor_bank.rs | 4 ++ .../src/editor/analyzer.rs | 68 +++++++++++-------- 3 files changed, 48 insertions(+), 28 deletions(-) diff --git a/plugins/spectral_compressor/src/analyzer.rs b/plugins/spectral_compressor/src/analyzer.rs index 47460092..1ff632b7 100644 --- a/plugins/spectral_compressor/src/analyzer.rs +++ b/plugins/spectral_compressor/src/analyzer.rs @@ -30,6 +30,9 @@ pub struct AnalyzerData { /// The parameters used for the global threshold curve. This is used to draw the same curve used /// by the compressors on the analyzer. pub curve_params: CurveParams, + /// The upwards and downwards threshold offsets for the curve. These are used to draw the curve + /// twice with some distance between them if either is non-zero. + pub curve_offsets_db: (f32, f32), /// The number of used bins. This is part of the `AnalyzerData` since recomputing it in the /// editor could result in a race condition. @@ -53,6 +56,7 @@ impl Default for AnalyzerData { fn default() -> Self { Self { curve_params: CurveParams::default(), + curve_offsets_db: (0.0, 0.0), num_bins: 0, envelope_followers: [0.0; crate::MAX_WINDOW_SIZE / 2 + 1], gain_difference_db: [0.0; crate::MAX_WINDOW_SIZE / 2 + 1], diff --git a/plugins/spectral_compressor/src/compressor_bank.rs b/plugins/spectral_compressor/src/compressor_bank.rs index a1d4e897..11b34b54 100644 --- a/plugins/spectral_compressor/src/compressor_bank.rs +++ b/plugins/spectral_compressor/src/compressor_bank.rs @@ -621,6 +621,10 @@ impl CompressorBank { // The editor needs to know about this too so it can draw the spectra correctly analyzer_input_data.curve_params = params.threshold.curve_params(); + analyzer_input_data.curve_offsets_db = ( + params.compressors.upwards.threshold_offset_db.value(), + params.compressors.downwards.threshold_offset_db.value(), + ); analyzer_input_data.num_bins = num_bins; // The gain reduction data needs to be averaged, see above diff --git a/plugins/spectral_compressor/src/editor/analyzer.rs b/plugins/spectral_compressor/src/editor/analyzer.rs index 326587b3..e0fd7a17 100644 --- a/plugins/spectral_compressor/src/editor/analyzer.rs +++ b/plugins/spectral_compressor/src/editor/analyzer.rs @@ -42,9 +42,12 @@ const LN_FREQ_RANGE: f32 = LN_FREQ_RANGE_END_HZ - LN_FREQ_RANGE_START_HZ; /// backgrounds. const GR_BAR_OVERLAY_COLOR: vg::Color = vg::Color::rgbaf(0.85, 0.95, 1.0, 0.8); -/// The color used for drawing the target curve. Looks somewhat similar to `GR_BAR_OVERLAY_COLOR` -/// when factoring in the blending -const TARGET_CURVE_COLOR: vg::Color = vg::Color::rgbaf(0.45, 0.55, 0.6, 0.9); +/// The color used for drawing the downwards compression threshold curve. Looks somewhat similar to +/// `GR_BAR_OVERLAY_COLOR` when factoring in the blending. +const DOWNWARDS_THRESHOLD_CURVE_COLOR: vg::Color = vg::Color::rgbaf(0.45, 0.55, 0.6, 0.9); +/// The color used for drawing the upwards compression threshold curve. Slightly color to make to +/// make the output look less confusing. +const UPWARDS_THRESHOLD_CURVE_COLOR: vg::Color = vg::Color::rgbaf(0.55, 0.70, 0.65, 0.9); /// A very analyzer showing the envelope followers as a magnitude spectrum with an overlay for the /// gain reduction. @@ -93,7 +96,7 @@ impl View for Analyzer { let nyquist = self.sample_rate.load(Ordering::Relaxed) / 2.0; draw_spectrum(cx, canvas, analyzer_data, nyquist); - draw_target_curve(cx, canvas, analyzer_data); + draw_threshold_curve(cx, canvas, analyzer_data); draw_gain_reduction(cx, canvas, analyzer_data, nyquist); // TODO: Display the frequency range below the graph @@ -257,12 +260,15 @@ fn draw_spectrum( canvas.fill_path(&mut mesh_path, &mesh_paint); } -/// Overlays the target curve over the spectrum analyzer. -fn draw_target_curve(cx: &mut DrawContext, canvas: &mut Canvas, analyzer_data: &AnalyzerData) { +/// Overlays the threshold curve over the spectrum analyzer. If either the upwards or downwards +/// threshold offsets are non-zero then two curves are drawn. +fn draw_threshold_curve(cx: &mut DrawContext, canvas: &mut Canvas, analyzer_data: &AnalyzerData) { let bounds = cx.bounds(); let line_width = cx.style.dpi_factor as f32 * 3.0; - let paint = vg::Paint::color(TARGET_CURVE_COLOR).with_line_width(line_width); + let downwards_paint = + vg::Paint::color(DOWNWARDS_THRESHOLD_CURVE_COLOR).with_line_width(line_width); + let upwards_paint = vg::Paint::color(UPWARDS_THRESHOLD_CURVE_COLOR).with_line_width(line_width); // This can be done slightly cleverer but for our purposes drawing line segments that are either // 1 pixel apart or that split the curve up into 100 segments (whichever results in the least @@ -270,32 +276,38 @@ fn draw_target_curve(cx: &mut DrawContext, canvas: &mut Canvas, analyzer_data: & let curve = Curve::new(&analyzer_data.curve_params); let num_points = 100.min(bounds.w.ceil() as usize); - let mut path = vg::Path::new(); - for i in 0..num_points { - let x_t = i as f32 / (num_points - 1) as f32; - let ln_freq = LN_FREQ_RANGE_START_HZ + (LN_FREQ_RANGE * x_t); + let mut draw_with_offset = |offset_db: f32, paint: vg::Paint| { + let mut path = vg::Path::new(); + for i in 0..num_points { + let x_t = i as f32 / (num_points - 1) as f32; + let ln_freq = LN_FREQ_RANGE_START_HZ + (LN_FREQ_RANGE * x_t); - // Evaluating the curve results in a value in dB, which must then be mapped to the same - // scale used in `draw_spectrum()` - let y_db = curve.evaluate_ln(ln_freq); - let y_t = db_to_unclamped_t(y_db); + // Evaluating the curve results in a value in dB, which must then be mapped to the same + // scale used in `draw_spectrum()` + let y_db = curve.evaluate_ln(ln_freq) + offset_db; + let y_t = db_to_unclamped_t(y_db); - let physical_x_pos = bounds.x + (bounds.w * x_t); - // This value increases from bottom to top - let physical_y_pos = bounds.y + (bounds.h * (1.0 - y_t)); + let physical_x_pos = bounds.x + (bounds.w * x_t); + // This value increases from bottom to top + let physical_y_pos = bounds.y + (bounds.h * (1.0 - y_t)); - if i == 0 { - path.move_to(physical_x_pos, physical_y_pos); - } else { - path.line_to(physical_x_pos, physical_y_pos); + if i == 0 { + path.move_to(physical_x_pos, physical_y_pos); + } else { + path.line_to(physical_x_pos, physical_y_pos); + } } - } - // This does a way better job at cutting off the tops and bottoms of the graph than we could do - // by hand - canvas.scissor(bounds.x, bounds.y, bounds.w, bounds.h); - canvas.stroke_path(&mut path, &paint); - canvas.reset_scissor(); + // This does a way better job at cutting off the tops and bottoms of the graph than we could do + // by hand + canvas.scissor(bounds.x, bounds.y, bounds.w, bounds.h); + canvas.stroke_path(&mut path, &paint); + canvas.reset_scissor(); + }; + + let (upwards_offset_db, downwards_offset_db) = analyzer_data.curve_offsets_db; + draw_with_offset(upwards_offset_db, upwards_paint); + draw_with_offset(downwards_offset_db, downwards_paint); } /// Overlays the gain reduction display over the spectrum analyzer.