Move analyzer drawing code to functions
This commit is contained in:
parent
6e3d2379b0
commit
29fde14c88
|
@ -23,6 +23,11 @@ use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use crate::analyzer::AnalyzerData;
|
use crate::analyzer::AnalyzerData;
|
||||||
|
|
||||||
|
// We'll show the bins from 30 Hz (to your chest) to 22 kHz, scaled logarithmically
|
||||||
|
const LN_40_HZ: f32 = 3.4011974; // 30.0f32.ln();
|
||||||
|
const LN_22_KHZ: f32 = 9.998797; // 22000.0f32.ln();
|
||||||
|
const LN_FREQ_RANGE: f32 = LN_22_KHZ - LN_40_HZ;
|
||||||
|
|
||||||
/// 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.
|
||||||
pub struct Analyzer {
|
pub struct Analyzer {
|
||||||
|
@ -64,7 +69,17 @@ impl View for Analyzer {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This only covers the style rules we're actually using
|
// The analyzer data is pulled directly from the spectral `CompressorBank`
|
||||||
|
let mut analyzer_data = self.analyzer_data.lock().unwrap();
|
||||||
|
let analyzer_data = analyzer_data.read();
|
||||||
|
let nyquist = self.sample_rate.load(Ordering::Relaxed) / 2.0;
|
||||||
|
|
||||||
|
draw_spectrum(cx, canvas, analyzer_data, nyquist);
|
||||||
|
// TODO: Draw target curve
|
||||||
|
draw_gain_reduction(cx, canvas, analyzer_data, nyquist);
|
||||||
|
// TODO: Display the frequency range below the graph
|
||||||
|
|
||||||
|
// Draw the border last
|
||||||
let border_width = match cx.border_width().unwrap_or_default() {
|
let border_width = match cx.border_width().unwrap_or_default() {
|
||||||
Units::Pixels(val) => val,
|
Units::Pixels(val) => val,
|
||||||
Units::Percentage(val) => bounds.w.min(bounds.h) * (val / 100.0),
|
Units::Percentage(val) => bounds.w.min(bounds.h) * (val / 100.0),
|
||||||
|
@ -72,35 +87,44 @@ impl View for Analyzer {
|
||||||
};
|
};
|
||||||
let border_color: vg::Color = cx.border_color().cloned().unwrap_or_default().into();
|
let border_color: vg::Color = cx.border_color().cloned().unwrap_or_default().into();
|
||||||
|
|
||||||
// Used for the spectrum analyzer lines
|
let mut path = vg::Path::new();
|
||||||
|
{
|
||||||
|
let x = bounds.x + border_width / 2.0;
|
||||||
|
let y = bounds.y + border_width / 2.0;
|
||||||
|
let w = bounds.w - border_width;
|
||||||
|
let h = bounds.h - border_width;
|
||||||
|
path.move_to(x, y);
|
||||||
|
path.line_to(x, y + h);
|
||||||
|
path.line_to(x + w, y + h);
|
||||||
|
path.line_to(x + w, y);
|
||||||
|
path.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
let paint = vg::Paint::color(border_color).with_line_width(border_width);
|
||||||
|
canvas.stroke_path(&mut path, &paint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw the spectrum analyzer part of the analyzer. These are drawn as vertical bars until the
|
||||||
|
/// spacing between the bars becomes less than 1 pixel, at which point it's drawn as a solid mesh
|
||||||
|
/// instead.
|
||||||
|
fn draw_spectrum(
|
||||||
|
cx: &mut DrawContext,
|
||||||
|
canvas: &mut Canvas,
|
||||||
|
analyzer_data: &AnalyzerData,
|
||||||
|
nyquist_hz: f32,
|
||||||
|
) {
|
||||||
|
let bounds = cx.bounds();
|
||||||
|
|
||||||
let line_width = cx.style.dpi_factor as f32 * 1.5;
|
let line_width = cx.style.dpi_factor as f32 * 1.5;
|
||||||
let text_color: vg::Color = cx.font_color().cloned().unwrap_or_default().into();
|
let text_color: vg::Color = cx.font_color().cloned().unwrap_or_default().into();
|
||||||
let spectrum_paint = vg::Paint::color(text_color).with_line_width(line_width);
|
let spectrum_paint = vg::Paint::color(text_color).with_line_width(line_width);
|
||||||
// Used for the gain reduction bars. Lighter and semitransparent to make it stand out
|
|
||||||
// against the spectrum analyzer
|
|
||||||
let bar_paint_color = vg::Color::rgbaf(0.7, 0.9, 1.0, 0.7);
|
|
||||||
let bar_paint = vg::Paint::color(bar_paint_color);
|
|
||||||
|
|
||||||
// The analyzer data is pulled directly from the spectral `CompressorBank`
|
let bin_frequency = |bin_idx: f32| (bin_idx / analyzer_data.num_bins as f32) * nyquist_hz;
|
||||||
let mut analyzer_data = self.analyzer_data.lock().unwrap();
|
|
||||||
let analyzer_data = analyzer_data.read();
|
|
||||||
let nyquist = self.sample_rate.load(Ordering::Relaxed) / 2.0;
|
|
||||||
let bin_frequency = |bin_idx: f32| (bin_idx / analyzer_data.num_bins as f32) * nyquist;
|
|
||||||
|
|
||||||
// TODO: Draw individual bars until the difference between the next two bars becomes less
|
// TODO: Draw individual bars until the difference between the next two bars becomes less
|
||||||
// than one pixel. At that point draw it as a single mesh to get rid of aliasing.
|
// than one pixel. At that point draw it as a single mesh to get rid of aliasing.
|
||||||
for (bin_idx, (magnetude, gain_difference_db)) in analyzer_data
|
for (bin_idx, magnetude) in analyzer_data.envelope_followers.iter().enumerate() {
|
||||||
.envelope_followers
|
|
||||||
.iter()
|
|
||||||
.zip(analyzer_data.gain_difference_db.iter())
|
|
||||||
.enumerate()
|
|
||||||
{
|
|
||||||
// We'll show the bins from 30 Hz (to your chest) to 22 kHz, scaled logarithmically
|
|
||||||
const LN_40_HZ: f32 = 3.4011974; // 30.0f32.ln();
|
|
||||||
const LN_22_KHZ: f32 = 9.998797; // 22000.0f32.ln();
|
|
||||||
const LN_FREQ_RANGE: f32 = LN_22_KHZ - LN_40_HZ;
|
|
||||||
|
|
||||||
{
|
|
||||||
let ln_frequency = bin_frequency(bin_idx as f32).ln();
|
let ln_frequency = bin_frequency(bin_idx as f32).ln();
|
||||||
let t = (ln_frequency - LN_40_HZ) / LN_FREQ_RANGE;
|
let t = (ln_frequency - LN_40_HZ) / LN_FREQ_RANGE;
|
||||||
if t <= 0.0 || t >= 1.0 {
|
if t <= 0.0 || t >= 1.0 {
|
||||||
|
@ -122,9 +146,25 @@ impl View for Analyzer {
|
||||||
path.line_to(bounds.x + (bounds.w * t), bounds.y + bounds.h);
|
path.line_to(bounds.x + (bounds.w * t), bounds.y + bounds.h);
|
||||||
canvas.stroke_path(&mut path, &spectrum_paint);
|
canvas.stroke_path(&mut path, &spectrum_paint);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Visualize the target curve
|
/// Overlays the gain reduction display over the spectrum analyzer.
|
||||||
|
fn draw_gain_reduction(
|
||||||
|
cx: &mut DrawContext,
|
||||||
|
canvas: &mut Canvas,
|
||||||
|
analyzer_data: &AnalyzerData,
|
||||||
|
nyquist_hz: f32,
|
||||||
|
) {
|
||||||
|
let bounds = cx.bounds();
|
||||||
|
|
||||||
|
// TODO: This color should be defined elsewhere
|
||||||
|
let bar_paint_color = vg::Color::rgbaf(0.7, 0.9, 1.0, 0.7);
|
||||||
|
let bar_paint = vg::Paint::color(bar_paint_color);
|
||||||
|
|
||||||
|
let bin_frequency = |bin_idx: f32| (bin_idx / analyzer_data.num_bins as f32) * nyquist_hz;
|
||||||
|
|
||||||
|
// TODO: This should be drawn as one mesh, or multiple meshes if there are empty gain reduction bars
|
||||||
|
for (bin_idx, gain_difference_db) in analyzer_data.gain_difference_db.iter().enumerate() {
|
||||||
// TODO: Draw this as a single mesh instead, this doesn't work.
|
// TODO: Draw this as a single mesh instead, this doesn't work.
|
||||||
// Avoid drawing tiny slivers for low gain reduction values
|
// Avoid drawing tiny slivers for low gain reduction values
|
||||||
if gain_difference_db.abs() > 0.2 {
|
if gain_difference_db.abs() > 0.2 {
|
||||||
|
@ -154,24 +194,4 @@ impl View for Analyzer {
|
||||||
canvas.fill_path(&mut path, &bar_paint);
|
canvas.fill_path(&mut path, &bar_paint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Display the frequency range below the graph
|
|
||||||
|
|
||||||
// Draw the border last
|
|
||||||
let mut path = vg::Path::new();
|
|
||||||
{
|
|
||||||
let x = bounds.x + border_width / 2.0;
|
|
||||||
let y = bounds.y + border_width / 2.0;
|
|
||||||
let w = bounds.w - border_width;
|
|
||||||
let h = bounds.h - border_width;
|
|
||||||
path.move_to(x, y);
|
|
||||||
path.line_to(x, y + h);
|
|
||||||
path.line_to(x + w, y + h);
|
|
||||||
path.line_to(x + w, y);
|
|
||||||
path.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
let paint = vg::Paint::color(border_color).with_line_width(border_width);
|
|
||||||
canvas.stroke_path(&mut path, &paint);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue