From a1b69e13bdb34482f9fdd1a5cb086fb7ce728bd2 Mon Sep 17 00:00:00 2001 From: a0kami Date: Mon, 14 Jul 2025 21:09:46 +0200 Subject: [PATCH] added sliders to dynamically select waveform resolution but also widgets refresh rate --- src/main.rs | 33 +++++++++++++++++++++++++++------ src/waveform.rs | 32 +++++++++++++++++++++++++------- 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index d1c38f7..154e9d0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +use iced::Element; + mod pw; mod waveform; @@ -23,23 +25,26 @@ struct Rgba { #[derive(Debug, Clone, Copy)] enum Message { + Waveform(waveform::Message), + RateUpdated(f64), Tick, } impl RumbleWrecker { fn new() -> Self { + // Spawn default output monitor capture via pipewire let (tx_left, rx_left) = std::sync::mpsc::channel::>(); let (tx_right, rx_right) = std::sync::mpsc::channel::>(); - std::thread::spawn(move || { let _pw_res = crate::pw::init_pw(tx_left, tx_right); }); + // Init widgets with image size let w = 1024u32; let h = 256u32; Self { - refresh_rate: 40, + refresh_rate: 32, stream_left: rx_left, stream_right: rx_right, waveform: waveform::Waveform::new(w, h), @@ -48,6 +53,14 @@ impl RumbleWrecker { fn update(&mut self, message: Message) { match message { + Message::Waveform(msg) => { + self.waveform.update(msg); + } + + Message::RateUpdated(new_refresh_rate) => { + self.refresh_rate = (new_refresh_rate as u64).clamp(1, 200); + }, + Message::Tick => { let mut left_samples = Vec::::new(); let mut right_samples = Vec::::new(); @@ -59,18 +72,26 @@ impl RumbleWrecker { } if !left_samples.is_empty() && !right_samples.is_empty() { - self.waveform.update((&left_samples, &right_samples), 0.5); + self.waveform.tick((&left_samples, &right_samples)); } } } } fn view(&self) -> iced::Element<'_, Message> { - let waveform = self.waveform.view(); + let waveform : iced::Element<'_, Message> = self.waveform.view().map(Message::Waveform); - // refresh rate slider + let rate_label = iced::widget::text("Refresh rate:"); + let rate_value = iced::widget::text(format!("{:3}ms", &self.refresh_rate)); + let rate_slider: Element<'_, Message> = iced::widget::slider(1f64..=200f64, self.refresh_rate as f64, Message::RateUpdated).into(); + let rate_row = iced::widget::Row::new() + .align_y(iced::Alignment::Center) + .spacing(12) + .push(rate_label) + .push(rate_value) + .push(rate_slider); - iced::widget::Column::new().push(waveform).into() + iced::widget::Column::new().push(waveform).push(rate_row).into() } fn subscription(&self) -> iced::Subscription { diff --git a/src/waveform.rs b/src/waveform.rs index 86307ad..eca9b94 100644 --- a/src/waveform.rs +++ b/src/waveform.rs @@ -1,12 +1,19 @@ use crate::Rgba; pub struct Waveform { + resolution: f32, rgba: Rgba, } +#[derive(Debug, Clone, Copy)] +pub enum Message { + ResolutionChanged(f32), +} + impl Waveform { pub fn new(width: u32, height: u32) -> Self { Self { + resolution: 0.5, rgba: Rgba { width: width, height: height, @@ -15,14 +22,22 @@ impl Waveform { } } - pub fn update(&mut self, samples: (&Vec, &Vec), resolution: f32 ) { + pub fn update(&mut self, waveform_message: Message) { + match waveform_message { + Message::ResolutionChanged(new_resolution) => { + self.resolution = new_resolution.clamp(0.01, 1.0); + } + } + } + + pub fn tick(&mut self, samples: (&Vec, &Vec)) { let (left_samples, right_samples) = samples; let mut last_rows = ((self.rgba.height/2) as usize, (self.rgba.height/2) as usize); - let span = (self.rgba.width as f32 * resolution) as usize; + let span = (self.rgba.width as f32 * self.resolution) as usize; let moved_start = self.rgba.width as usize - span; - if resolution < 1.0 { + if self.resolution < 1.0 { let mut previous_left_row = (self.rgba.height as usize, 0usize); let mut previous_right_row = (self.rgba.height as usize, 0usize); @@ -96,15 +111,18 @@ impl Waveform { } } - - - pub fn view(&self) -> iced::Element<'_, crate::Message> { + pub fn view(&self) -> iced::Element<'_, Message> { let img_handle = iced::widget::image::Handle::from_rgba( self.rgba.width, self.rgba.height, self.rgba.pixels.clone() ); - iced::widget::center_x(iced::widget::image(img_handle)).into() + let img: iced::Element<'_, Message> = iced::widget::image(img_handle).into(); + // let centered_img = iced::widget::center_x(img); + let resolution_slider = iced::widget::Slider::new(0.05..=1.0, self.resolution, Message::ResolutionChanged).step(0.05); + // let resolution_slider = iced::widget::slider(0.05..=1.0, self.resolution, Message::ResolutionChanged); + + iced::widget::Column::new().push(img).push(resolution_slider).into() } } \ No newline at end of file