Add dummy device for testing

This commit is contained in:
Lucas Schumacher 2024-06-19 09:50:55 -04:00
parent edcf10f73c
commit a8340a3fb9
3 changed files with 133 additions and 4 deletions

View File

@ -7,7 +7,7 @@ use realfft::num_complex::Complex32;
pub enum PlotData { pub enum PlotData {
U8(Vec<u8>), U8(Vec<u8>),
//F32(Vec<f32>), F32(Vec<f32>),
Bode32(Vec<Complex32>), Bode32(Vec<Complex32>),
} }
#[derive(Clone)] #[derive(Clone)]
@ -94,6 +94,18 @@ impl DebugPlots {
)); ));
}); });
} }
PlotData::F32(v) => {
ui.heading("f32 plot");
let line = Line::new(PlotPoints::from_ys_f32(&v));
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, -2.0],
[(v.len() + 1) as f64, 2.0],
));
});
}
PlotData::Bode32(v) => { PlotData::Bode32(v) => {
ui.heading("Bode Plot"); ui.heading("Bode Plot");
let mag_line = let mag_line =

109
src/backend/dummy.rs Normal file
View File

@ -0,0 +1,109 @@
use anyhow::Result;
use core::panic;
use std::{
sync::mpsc::{self, RecvTimeoutError, SyncSender, TrySendError},
time::{Duration, Instant},
usize,
};
use crate::app::debug_plot::{DebugPlotSender, PlotData};
const LUT_LEN: usize = 4096;
pub struct DummyDevice {
close: SyncSender<()>,
}
impl DummyDevice {
pub fn new(
sample_rate: usize,
fft_input: SyncSender<Vec<f32>>,
_plot_tx: DebugPlotSender,
) -> Result<Self> {
let sin_lut: Vec<f32> = (0..LUT_LEN)
.map(|i| ((i as f32 / LUT_LEN as f32) * std::f32::consts::TAU).sin())
.collect();
let (close, close_rx) = mpsc::sync_channel(0);
let buffer_size: usize = 2048;
let loop_interval = Duration::from_secs_f32((1. / sample_rate as f32) * buffer_size as f32);
let freq = (sample_rate / 4) as f32;
let phase_delta = sin_lut.len() as f32 * (freq / sample_rate as f32);
std::thread::spawn(move || {
let mut phase = 0_f32;
loop {
let start = Instant::now();
let samples: Vec<f32> = (0..buffer_size)
.map(|_i| {
phase = (phase + phase_delta) % sin_lut.len() as f32;
sin_lut[phase as usize]
})
.collect();
_plot_tx
.send("Dummy output", PlotData::F32(samples.clone()))
.unwrap();
match fft_input.try_send(samples) {
Ok(_) => {}
Err(TrySendError::Full(_)) => log::warn!("Dummy Backend buffer full."),
Err(TrySendError::Disconnected(_)) => {
panic!("Dummy device lost connection to frontend!")
}
}
match close_rx.recv_timeout(loop_interval - start.elapsed()) {
Ok(_) => break,
Err(RecvTimeoutError::Disconnected) => {
panic!("Dummy device lost connection to frontend!")
}
Err(RecvTimeoutError::Timeout) => {}
}
}
});
Ok(Self { close })
}
}
impl crate::backend::Device for DummyDevice {
fn show_settings(&mut self, ui: &mut egui::Ui) {
ui.label("TODO");
}
fn can_tune(&self) -> bool {
false
}
fn tune(&mut self, _freq: usize) -> anyhow::Result<()> {
anyhow::bail!("Can't tune this device")
}
fn close(self: Box<Self>) {
self.close.send(()).unwrap();
}
}
pub struct DummyBackend {
sample_rate: usize,
}
impl DummyBackend {
pub fn new() -> Self {
Self { sample_rate: 48000 }
}
}
impl super::Backend for DummyBackend {
fn display_text(&self) -> &'static str {
"Dummy"
}
fn show_device_selection(&mut self, ui: &mut egui::Ui) {
ui.label("TODO");
}
fn build_device(
&mut self,
fft_input: SyncSender<Vec<f32>>,
_plot_tx: DebugPlotSender,
) -> anyhow::Result<Box<dyn super::Device>> {
Ok(Box::new(DummyDevice::new(
self.sample_rate,
fft_input,
_plot_tx,
)?))
}
}

View File

@ -4,6 +4,7 @@ use egui::Ui;
use crate::app::debug_plot::DebugPlotSender; use crate::app::debug_plot::DebugPlotSender;
mod audio; mod audio;
mod dummy;
pub trait Device { pub trait Device {
fn show_settings(&mut self, ui: &mut Ui); fn show_settings(&mut self, ui: &mut Ui);
fn can_tune(&self) -> bool; fn can_tune(&self) -> bool;
@ -24,16 +25,23 @@ pub struct Backends(pub Vec<Box<dyn Backend>>);
#[cfg(all(not(target_arch = "wasm32"), not(target_os = "android")))] #[cfg(all(not(target_arch = "wasm32"), not(target_os = "android")))]
impl Default for Backends { impl Default for Backends {
fn default() -> Self { fn default() -> Self {
Backends(vec![Box::new(audio::AudioBackend::new())]) Backends(vec![
Box::new(audio::AudioBackend::new()),
Box::new(dummy::DummyBackend::new()),
])
} }
} }
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
impl Default for Backends { impl Default for Backends {
fn default() -> Self {} fn default() -> Self {
Backends(vec![Box::new(dummy::DummyBackend::new())])
}
} }
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
impl Default for Backends { impl Default for Backends {
fn default() -> Self {} fn default() -> Self {
Backends(vec![Box::new(dummy::DummyBackend::new())])
}
} }