1
0
Fork 0

Draw separate upwards and downwards curves

This commit is contained in:
Robbert van der Helm 2023-03-22 00:17:17 +01:00
parent 14cd737e8f
commit 4022fdd37c
3 changed files with 48 additions and 28 deletions

View file

@ -30,6 +30,9 @@ pub struct AnalyzerData {
/// The parameters used for the global threshold curve. This is used to draw the same curve used /// The parameters used for the global threshold curve. This is used to draw the same curve used
/// by the compressors on the analyzer. /// by the compressors on the analyzer.
pub curve_params: CurveParams, 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 /// The number of used bins. This is part of the `AnalyzerData` since recomputing it in the
/// editor could result in a race condition. /// editor could result in a race condition.
@ -53,6 +56,7 @@ impl Default for AnalyzerData {
fn default() -> Self { fn default() -> Self {
Self { Self {
curve_params: CurveParams::default(), curve_params: CurveParams::default(),
curve_offsets_db: (0.0, 0.0),
num_bins: 0, num_bins: 0,
envelope_followers: [0.0; crate::MAX_WINDOW_SIZE / 2 + 1], envelope_followers: [0.0; crate::MAX_WINDOW_SIZE / 2 + 1],
gain_difference_db: [0.0; crate::MAX_WINDOW_SIZE / 2 + 1], gain_difference_db: [0.0; crate::MAX_WINDOW_SIZE / 2 + 1],

View file

@ -621,6 +621,10 @@ impl CompressorBank {
// The editor needs to know about this too so it can draw the spectra correctly // 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_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; analyzer_input_data.num_bins = num_bins;
// The gain reduction data needs to be averaged, see above // The gain reduction data needs to be averaged, see above

View file

@ -42,9 +42,12 @@ const LN_FREQ_RANGE: f32 = LN_FREQ_RANGE_END_HZ - LN_FREQ_RANGE_START_HZ;
/// backgrounds. /// backgrounds.
const GR_BAR_OVERLAY_COLOR: vg::Color = vg::Color::rgbaf(0.85, 0.95, 1.0, 0.8); 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` /// The color used for drawing the downwards compression threshold curve. Looks somewhat similar to
/// when factoring in the blending /// `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); 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 /// A very analyzer showing the envelope followers as a magnitude spectrum with an overlay for the
/// gain reduction. /// gain reduction.
@ -93,7 +96,7 @@ impl View for Analyzer {
let nyquist = self.sample_rate.load(Ordering::Relaxed) / 2.0; let nyquist = self.sample_rate.load(Ordering::Relaxed) / 2.0;
draw_spectrum(cx, canvas, analyzer_data, nyquist); 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); draw_gain_reduction(cx, canvas, analyzer_data, nyquist);
// TODO: Display the frequency range below the graph // TODO: Display the frequency range below the graph
@ -257,12 +260,15 @@ fn draw_spectrum(
canvas.fill_path(&mut mesh_path, &mesh_paint); canvas.fill_path(&mut mesh_path, &mesh_paint);
} }
/// Overlays the target curve over the spectrum analyzer. /// Overlays the threshold curve over the spectrum analyzer. If either the upwards or downwards
fn draw_target_curve(cx: &mut DrawContext, canvas: &mut Canvas, analyzer_data: &AnalyzerData) { /// 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 bounds = cx.bounds();
let line_width = cx.style.dpi_factor as f32 * 3.0; 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 // 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 // 1 pixel apart or that split the curve up into 100 segments (whichever results in the least
@ -270,6 +276,7 @@ fn draw_target_curve(cx: &mut DrawContext, canvas: &mut Canvas, analyzer_data: &
let curve = Curve::new(&analyzer_data.curve_params); let curve = Curve::new(&analyzer_data.curve_params);
let num_points = 100.min(bounds.w.ceil() as usize); let num_points = 100.min(bounds.w.ceil() as usize);
let mut draw_with_offset = |offset_db: f32, paint: vg::Paint| {
let mut path = vg::Path::new(); let mut path = vg::Path::new();
for i in 0..num_points { for i in 0..num_points {
let x_t = i as f32 / (num_points - 1) as f32; let x_t = i as f32 / (num_points - 1) as f32;
@ -277,7 +284,7 @@ fn draw_target_curve(cx: &mut DrawContext, canvas: &mut Canvas, analyzer_data: &
// Evaluating the curve results in a value in dB, which must then be mapped to the same // Evaluating the curve results in a value in dB, which must then be mapped to the same
// scale used in `draw_spectrum()` // scale used in `draw_spectrum()`
let y_db = curve.evaluate_ln(ln_freq); let y_db = curve.evaluate_ln(ln_freq) + offset_db;
let y_t = db_to_unclamped_t(y_db); let y_t = db_to_unclamped_t(y_db);
let physical_x_pos = bounds.x + (bounds.w * x_t); let physical_x_pos = bounds.x + (bounds.w * x_t);
@ -296,6 +303,11 @@ fn draw_target_curve(cx: &mut DrawContext, canvas: &mut Canvas, analyzer_data: &
canvas.scissor(bounds.x, bounds.y, bounds.w, bounds.h); canvas.scissor(bounds.x, bounds.y, bounds.w, bounds.h);
canvas.stroke_path(&mut path, &paint); canvas.stroke_path(&mut path, &paint);
canvas.reset_scissor(); 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. /// Overlays the gain reduction display over the spectrum analyzer.