Draw separate upwards and downwards curves
This commit is contained in:
parent
14cd737e8f
commit
4022fdd37c
|
@ -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],
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue