From ab2d4a0af82091522ba0c7d6c911595c01efb07c Mon Sep 17 00:00:00 2001 From: alemi Date: Thu, 21 Sep 2023 03:50:48 +0200 Subject: [PATCH] feat: add log y axis to spectroscope (togglable) also fixed spectroscope bugging when paused --- src/app.rs | 9 ++++----- src/display/mod.rs | 1 + src/display/spectroscope.rs | 32 ++++++++++++++++++++++---------- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/app.rs b/src/app.rs index 9bdd4c2..88779f3 100644 --- a/src/app.rs +++ b/src/app.rs @@ -18,7 +18,6 @@ pub enum CurrentDisplayMode { } pub struct App { - pause: bool, channels: u8, graph: GraphConfig, oscilloscope: Oscilloscope, @@ -41,6 +40,7 @@ impl From::<&crate::ScopeArgs> for App { references: !args.no_reference, show_ui: !args.no_ui, scatter: args.scatter, + pause: false, marker_type: if args.no_braille { Marker::Dot } else { @@ -56,7 +56,6 @@ impl From::<&crate::ScopeArgs> for App { graph, oscilloscope, vectorscope, spectroscope, mode: CurrentDisplayMode::Oscilloscope, channels: args.channels, - pause: false, } } } @@ -75,7 +74,7 @@ impl App { let data = source.recv() .ok_or(io::Error::new(io::ErrorKind::BrokenPipe, "data source returned null"))?; - if !self.pause { + if !self.graph.pause { channels = fmt.oscilloscope(data, self.channels); } @@ -98,7 +97,7 @@ impl App { let mut size = f.size(); if self.graph.show_ui { f.render_widget( - make_header(&self.graph, &self.current_display().header(&self.graph), self.current_display().mode_str(), framerate, self.pause), + make_header(&self.graph, &self.current_display().header(&self.graph), self.current_display().mode_str(), framerate, self.graph.pause), Rect { x: size.x, y: size.y, width: size.width, height:1 } // a 1px line at the top ); size.height -= 1; @@ -157,7 +156,7 @@ impl App { KeyCode::Right => update_value_i(&mut self.graph.samples, true, 25, magnitude, 0..self.graph.width*2), KeyCode::Left => update_value_i(&mut self.graph.samples, false, 25, magnitude, 0..self.graph.width*2), KeyCode::Char('q') => quit = true, - KeyCode::Char(' ') => self.pause = !self.pause, + KeyCode::Char(' ') => self.graph.pause = !self.graph.pause, KeyCode::Char('s') => self.graph.scatter = !self.graph.scatter, KeyCode::Char('h') => self.graph.show_ui = !self.graph.show_ui, KeyCode::Char('r') => self.graph.references = !self.graph.references, diff --git a/src/display/mod.rs b/src/display/mod.rs index f60174c..6be21f4 100644 --- a/src/display/mod.rs +++ b/src/display/mod.rs @@ -11,6 +11,7 @@ pub enum Dimension { #[derive(Debug, Clone)] pub struct GraphConfig { + pub pause: bool, pub samples: u32, pub sampling_rate: u32, pub scale: u32, diff --git a/src/display/spectroscope.rs b/src/display/spectroscope.rs index 353fcb9..9e3815e 100644 --- a/src/display/spectroscope.rs +++ b/src/display/spectroscope.rs @@ -16,6 +16,7 @@ pub struct Spectroscope { pub average: u32, pub buf: Vec>>, pub window: bool, + pub log_y: bool, } fn magnitude(c: Complex) -> f64 { @@ -43,6 +44,7 @@ impl DisplayMode for Spectroscope { buffer_size: args.buffer / (2 * args.channels as u32), average: 1, buf: Vec::new(), window: false, + log_y: true, } } @@ -76,7 +78,10 @@ impl DisplayMode for Spectroscope { fn axis(&self, cfg: &GraphConfig, dimension: Dimension) -> Axis { let (name, bounds) = match dimension { Dimension::X => ("frequency -", [20.0f64.ln(), ((cfg.samples as f64 / cfg.width as f64) * 20000.0).ln()]), - Dimension::Y => ("| level", [0.0, cfg.scale as f64 / 10.0]), // TODO super arbitraty! wtf + Dimension::Y => ( + if self.log_y { "| level" } else { "| amplitude" }, + [0.0, if self.log_y { (cfg.scale as f64 / 10.0).ln() } else { cfg.scale as f64 / 10.0 }]), + // TODO super arbitraty! wtf! also ugly inline ifs, get this thing together! }; let mut a = Axis::default(); if cfg.show_ui { // TODO don't make it necessary to check show_ui inside here @@ -87,13 +92,15 @@ impl DisplayMode for Spectroscope { fn process(&mut self, cfg: &GraphConfig, data: &Vec>) -> Vec { if self.average == 0 { self.average = 1 } // otherwise fft breaks - for (i, chan) in data.iter().enumerate() { - if self.buf.len() <= i { - self.buf.push(VecDeque::new()); - } - self.buf[i].push_back(chan.clone()); - while self.buf[i].len() > self.average as usize { - self.buf[i].pop_front(); + if !cfg.pause { + for (i, chan) in data.iter().enumerate() { + if self.buf.len() <= i { + self.buf.push(VecDeque::new()); + } + self.buf[i].push_back(chan.clone()); + while self.buf[i].len() > self.average as usize { + self.buf[i].pop_front(); + } } } @@ -113,7 +120,11 @@ impl DisplayMode for Spectroscope { fft.process(tmp.as_mut_slice()); out.push(DataSet::new( self.channel_name(n), - tmp[..=tmp.len() / 2].iter().enumerate().map(|(i,x)| ((i as f64 * resolution).ln(), magnitude(*x))).collect(), + tmp[..=tmp.len() / 2] + .iter() + .enumerate() + .map(|(i,x)| ((i as f64 * resolution).ln(), if self.log_y { magnitude(*x).ln() } else { magnitude(*x) })) + .collect(), cfg.marker_type, if cfg.scatter { GraphType::Scatter } else { GraphType::Line }, cfg.palette(n), @@ -129,13 +140,14 @@ impl DisplayMode for Spectroscope { KeyCode::PageUp => update_value_i(&mut self.average, true, 1, 1., 1..65535), KeyCode::PageDown => update_value_i(&mut self.average, false, 1, 1., 1..65535), KeyCode::Char('w') => self.window = !self.window, + KeyCode::Char('l') => self.log_y = !self.log_y, _ => {} } } } fn references(&self, cfg: &GraphConfig) -> Vec { - let s = cfg.scale as f64 / 10.0; + let s = if self.log_y { (cfg.scale as f64 / 10.0).ln() } else { cfg.scale as f64 / 10.0 }; vec![ DataSet::new("".into(), vec![(0.0, 0.0), ((cfg.samples as f64).ln(), 0.0)], cfg.marker_type, GraphType::Line, cfg.axis_color),