Add debug plots

This commit is contained in:
2024-05-12 15:17:06 -04:00
parent fc9e04ffd2
commit 162220aa72
5 changed files with 134 additions and 5 deletions

View File

@@ -5,7 +5,9 @@ use cpal::{
BufferSize, StreamConfig,
};
use realfft::RealFftPlanner;
use std::sync::mpsc;
use std::sync::mpsc::{self, Sender};
use super::debug_plot::PlotData;
pub struct AudioFFT {
pub stream: cpal::Stream,
@@ -13,7 +15,10 @@ pub struct AudioFFT {
}
impl AudioFFT {
pub fn new(size: usize) -> Result<(Self, mpsc::Receiver<Vec<u8>>)> {
pub fn new(
size: usize,
plot_tx: Sender<(&'static str, PlotData)>,
) -> Result<(Self, mpsc::Receiver<Vec<u8>>)> {
let output_len = size / 2 + 1;
// Create mpsc queue
@@ -45,9 +50,15 @@ impl AudioFFT {
assert_eq!(size, fft_in.len());
fft.process_with_scratch(&mut fft_in, &mut fft_out, &mut fft_scratch)
.unwrap();
plot_tx
.send(("FFT Output", PlotData::Bode32(fft_out.clone())))
.unwrap();
fft_in.clear();
let output: Vec<u8> = fft_out.iter().map(|c| (c.arg() * 255.0) as u8).collect();
assert_eq!(output_len, output.len());
plot_tx
.send(("FFT Processed Output", PlotData::U8(output.clone())))
.unwrap();
tx.send(output).unwrap();
}
},

99
src/app/debug_plot.rs Normal file
View File

@@ -0,0 +1,99 @@
use std::collections::HashMap;
use std::sync::mpsc::{self, Sender};
use egui::{Context, Ui};
use egui_plot::{Line, Plot, PlotBounds, PlotPoints};
use realfft::num_complex::Complex32;
pub enum PlotData {
U8(Vec<u8>),
//F32(Vec<f32>),
Bode32(Vec<Complex32>),
}
pub struct DebugPlots {
plots: HashMap<&'static str, PlotData>,
plot_en: HashMap<&'static str, bool>,
rx: mpsc::Receiver<(&'static str, PlotData)>,
tx: mpsc::Sender<(&'static str, PlotData)>,
}
impl DebugPlots {
pub fn new() -> Self {
let (tx, rx) = mpsc::channel();
DebugPlots {
plots: HashMap::new(),
plot_en: HashMap::new(),
rx,
tx,
}
}
pub fn get_sender(&self) -> Sender<(&'static str, PlotData)> {
self.tx.clone()
}
pub fn update_plots(&mut self) {
while let Ok((key, plot)) = self.rx.try_recv() {
if self.plots.insert(key, plot).is_none() {
self.plot_en.insert(key, false);
}
}
}
pub fn render_menu_buttons(&mut self, ui: &mut Ui) {
ui.menu_button("Debug Plots", |ui| {
for &k in self.plots.keys() {
if !self.plot_en.contains_key(k) {
self.plot_en.insert(k, false);
}
let enabled = self.plot_en.get_mut(k).unwrap();
ui.checkbox(enabled, k);
}
});
}
pub fn render_plot_windows(&mut self, ctx: &Context) {
for (key, plot) in self.plots.iter() {
let enabled = self.plot_en.get_mut(key).unwrap();
if *enabled {
DebugPlots::render_window(ctx, key, plot, enabled);
}
}
}
fn render_window(ctx: &Context, title: &'static str, plot: &PlotData, open: &mut bool) {
egui::Window::new(title).open(open).show(ctx, |ui| {
ui.heading(title);
match plot {
PlotData::U8(v) => {
ui.heading("u8 Plot");
let line = Line::new(PlotPoints::from_iter(
v.iter().enumerate().map(|(i, y)| [i as f64, *y as f64]),
));
let plot = Plot::new(title);
plot.show(ui, |plot_ui| {
plot_ui.line(line);
plot_ui.set_plot_bounds(PlotBounds::from_min_max(
[-1.0, -1.0],
[(v.len() + 1) as f64, 256.0],
));
});
}
PlotData::Bode32(v) => {
ui.heading("Bode Plot");
let mag_line =
Line::new(PlotPoints::from_iter(v.iter().enumerate().map(|(i, c)| {
[i as f64, ((c.re * c.re) + (c.im * c.im)).sqrt() as f64]
})));
let phase_line = Line::new(PlotPoints::from_iter(
v.iter()
.enumerate()
.map(|(i, c)| [i as f64, c.arg() as f64]),
));
let plot = Plot::new(title);
plot.show(ui, |plot_ui| {
plot_ui.line(mag_line);
plot_ui.line(phase_line);
});
ui.heading("TODO");
}
};
});
}
}