From 49e5ab06704b47f058e2544b15e15e7dbb83f9c6 Mon Sep 17 00:00:00 2001 From: Charles Zhang Date: Wed, 19 Jun 2024 23:59:07 -0500 Subject: [PATCH] add spectrum readout --- Cargo.lock | 39 +++ Cargo.toml | 1 + src/audio/callback.rs | 141 ++++++----- src/frame/main_canvas.rs | 2 +- src/frame/setting_panel.rs | 8 +- src/frame/spectrogram_meter.rs | 102 ++++---- src/frame/spectrum_meter.rs | 16 ++ src/setting/spectrum.rs | 21 +- src/utils/color.rs | 418 ++++++++++++++++----------------- src/utils/data_struct.rs | 25 +- 10 files changed, 439 insertions(+), 334 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 271928d..e66e87a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -191,6 +191,12 @@ dependencies = [ "x11rb 0.12.0", ] +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + [[package]] name = "arrayvec" version = "0.7.4" @@ -1698,6 +1704,7 @@ dependencies = [ "ruhear", "rustfft", "serde", + "tiny-skia", ] [[package]] @@ -2479,6 +2486,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" + [[package]] name = "syn" version = "1.0.109" @@ -2530,6 +2543,32 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "tiny-skia" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "png", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + [[package]] name = "tinyvec" version = "1.6.0" diff --git a/Cargo.toml b/Cargo.toml index 57e80c5..f531d94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ rayon = "1.10" crossbeam-channel = "0.5.12" puffin = { version = "0.19", optional = true } puffin_http = { version = "0.16", optional = true } +tiny-skia = "0.11.4" # dasp = { version = "0.11.0", features = ["ring_buffer"] } [features] diff --git a/src/audio/callback.rs b/src/audio/callback.rs index 5371b66..429d8cd 100644 --- a/src/audio/callback.rs +++ b/src/audio/callback.rs @@ -4,7 +4,7 @@ use egui::*; use realfft::RealFftPlanner; use rustfft::num_complex::{Complex, ComplexFloat}; use std::sync::{Arc, Mutex}; - +use tiny_skia::*; const SQRT_2: f32 = 1.4142135; pub fn get_callback( @@ -40,11 +40,6 @@ pub fn get_callback( let r = data[1][i]; let m = (l + r) / 2.0; let s = (l - r) / 2.0; - // buf.raw.l.push(l); - // buf.raw.r.push(r); - // buf.raw.m.push(m); - // buf.raw.s.push(s); - // let raw_len = buf.raw.l.len(); if spectrum_on { if buf.spectrum.ab { @@ -390,10 +385,6 @@ pub fn get_callback( send_data.iir.push(peak_buffer.sum / 4800.0); } } - - // if raw_len >= 8192 { - // buf.raw.keep_last(4096); - // } } // Send data @@ -425,12 +416,23 @@ fn process_spectrogram( raw_hann_dt: &mut [f32], raw_hann_t: &mut [f32], ) { - let resolution = 2048; - let speed = 4; - buf.spectrogram.image.drain(0..resolution * speed); - buf.spectrogram - .image - .extend(vec![Color32::TRANSPARENT; resolution * speed]); + // let resolution = 2048; + // let speed = 4; + // buf.spectrogram.image.drain(0..resolution * speed); + // buf.spectrogram + // .image + // .extend(vec![Color32::TRANSPARENT; resolution * speed]); + let mut paint = Paint::default(); + paint.anti_alias = true; + let pixmap_w = 2048; + let pixmap_h = 4; + let mut pixmap = Pixmap::new(pixmap_w, pixmap_h).unwrap(); + + let r = buf.setting.theme.main.r(); + let g = buf.setting.theme.main.g(); + let b = buf.setting.theme.main.b(); + let boost = buf.setting.spectrogram.brightness_boost as f32; + let mut real_planner = RealFftPlanner::::new(); let r2c = real_planner.plan_fft_forward(2048); let mut spectrum = r2c.make_output_vec(); @@ -447,62 +449,71 @@ fn process_spectrogram( if fc_temp > 0.0 && fc_temp < 22000.0 { let image_x = if buf.setting.spectrogram.curve == SpectrogramCurve::Linear { - fc_temp.floor() / 22000.0 * resolution as f32 + fc_temp / 22000.0 * pixmap_w as f32 } else { - 0.2991878257 * (fc_temp.log10() - 1.0) * resolution as f32 + 0.2991878257 * (fc_temp.log10() - 1.0) * pixmap_w as f32 }; - let image_y = 1920.0 + tc_temp * 46.875 * speed as f32; - - let o_x_weight = image_x - image_x.floor(); - let o_y_weight = image_y - image_y.floor(); - let o_x = image_x.floor() as usize; - let o_y = image_y.floor() as usize; - let o_00_weight = o_x_weight * o_y_weight; - let o_01_weight = o_x_weight * (1.0 - o_y_weight); - let o_10_weight = (1.0 - o_x_weight) * o_y_weight; - let o_11_weight = (1.0 - o_x_weight) * (1.0 - o_y_weight); - let o_00_index = o_x + o_y * resolution; - let o_01_index = o_x + (o_y + 1) * resolution; - let o_10_index = o_x + 1 + o_y * resolution; - let o_11_index = o_x + 1 + (o_y + 1) * resolution; + let image_y = 2.0 * (tc_temp / 0.0213333333 + 1.0); + let intensity = if fft_x[i].norm().log10() > -80.0 { + (255.0 * fft_x[i].norm().log10() + 80.0) / 80.0 + } else { + 0.0 + }; + paint.set_color_rgba8(r, g, b, (boost * 255.0 * intensity) as u8); + pixmap.fill_rect( + tiny_skia::Rect::from_ltrb(image_x, image_y, image_x + 1.0, image_y + 1.0) + .expect("Can't draw on spectogram pixmap"), + &paint, + Transform::identity(), + None, + ); - let o_00_c = buf.spectrogram.image[o_00_index].a(); - let o_01_c = buf.spectrogram.image[o_01_index].a(); - let o_10_c = buf.spectrogram.image[o_10_index].a(); - let o_11_c = buf.spectrogram.image[o_11_index].a(); + // let o_x_weight = image_x - image_x.floor(); + // let o_y_weight = image_y - image_y.floor(); + // let o_x = image_x.floor() as usize; + // let o_y = image_y.floor() as usize; + // let o_00_weight = o_x_weight * o_y_weight; + // let o_01_weight = o_x_weight * (1.0 - o_y_weight); + // let o_10_weight = (1.0 - o_x_weight) * o_y_weight; + // let o_11_weight = (1.0 - o_x_weight) * (1.0 - o_y_weight); + // let o_00_index = o_x + o_y * resolution; + // let o_01_index = o_x + (o_y + 1) * resolution; + // let o_10_index = o_x + 1 + o_y * resolution; + // let o_11_index = o_x + 1 + (o_y + 1) * resolution; - let r = buf.setting.theme.main.r(); - let g = buf.setting.theme.main.g(); - let b = buf.setting.theme.main.b(); - let boost = buf.setting.spectrogram.brightness_boost as f32; + // let o_00_c = buf.spectrogram.image[o_00_index].a(); + // let o_01_c = buf.spectrogram.image[o_01_index].a(); + // let o_10_c = buf.spectrogram.image[o_10_index].a(); + // let o_11_c = buf.spectrogram.image[o_11_index].a(); - buf.spectrogram.image[o_00_index] = Color32::from_rgba_unmultiplied( - r, - g, - b, - o_00_c.wrapping_add((boost * 255.0 * fft_x[i].norm() * o_00_weight) as u8), - ); - buf.spectrogram.image[o_01_index] = Color32::from_rgba_unmultiplied( - r, - g, - b, - o_01_c.wrapping_add((boost * 255.0 * fft_x[i].norm() * o_01_weight) as u8), - ); - buf.spectrogram.image[o_10_index] = Color32::from_rgba_unmultiplied( - r, - g, - b, - o_10_c.wrapping_add((boost * 255.0 * fft_x[i].norm() * o_10_weight) as u8), - ); - buf.spectrogram.image[o_11_index] = Color32::from_rgba_unmultiplied( - r, - g, - b, - o_11_c.wrapping_add((boost * 255.0 * fft_x[i].norm() * o_11_weight) as u8), - ); + // buf.spectrogram.image[o_00_index] = Color32::from_rgba_unmultiplied( + // r, + // g, + // b, + // o_00_c.wrapping_add((boost * 255.0 * fft_x[i].norm() * o_00_weight) as u8), + // ); + // buf.spectrogram.image[o_01_index] = Color32::from_rgba_unmultiplied( + // r, + // g, + // b, + // o_01_c.wrapping_add((boost * 255.0 * fft_x[i].norm() * o_01_weight) as u8), + // ); + // buf.spectrogram.image[o_10_index] = Color32::from_rgba_unmultiplied( + // r, + // g, + // b, + // o_10_c.wrapping_add((boost * 255.0 * fft_x[i].norm() * o_10_weight) as u8), + // ); + // buf.spectrogram.image[o_11_index] = Color32::from_rgba_unmultiplied( + // r, + // g, + // b, + // o_11_c.wrapping_add((boost * 255.0 * fft_x[i].norm() * o_11_weight) as u8), + // ); } } - send_data.spectrogram_image = buf.spectrogram.image[0..1920 * resolution].to_owned(); + // send_data.spectrogram_image = buf.spectrogram.image[0..1920 * resolution].to_owned(); + send_data.spectrogram_frame = pixmap.clone(); buf.spectrogram.ab = !buf.spectrogram.ab; } diff --git a/src/frame/main_canvas.rs b/src/frame/main_canvas.rs index 3276330..7cd3ca9 100644 --- a/src/frame/main_canvas.rs +++ b/src/frame/main_canvas.rs @@ -84,7 +84,7 @@ impl NanometersApp { update_vector_data.c.extend_from_slice(&data.vectorscope.c); update_waveform_data.concat(&data.waveform); update_osc_data = data.oscilloscope; - update_spectrogram_image = data.spectrogram_image; + // update_spectrogram_image = data.spectrogram_image; update_spectrum_data = data.spectrum; }); diff --git a/src/frame/setting_panel.rs b/src/frame/setting_panel.rs index bb8feff..6adc562 100644 --- a/src/frame/setting_panel.rs +++ b/src/frame/setting_panel.rs @@ -228,7 +228,8 @@ impl NanometersApp { ui.vertical(|ui| { ui.heading("Oscilloscope"); ui.horizontal(|ui| { - ui.label("Follow Pitch"); + ui.label("Follow Pitch") + .on_hover_text("Whether to follow the pitch"); if ui .selectable_value(&mut self.setting.oscilloscope.follow_pitch, true, "On") .changed() @@ -244,7 +245,7 @@ impl NanometersApp { }); if self.setting.oscilloscope.follow_pitch { ui.horizontal(|ui| { - ui.label("Cycle"); + ui.label("Cycle").on_hover_text("Display how many cycles"); if ui .selectable_value( &mut self.setting.oscilloscope.cycle, @@ -268,7 +269,8 @@ impl NanometersApp { }); }; ui.horizontal(|ui| { - ui.label("Shadow"); + ui.label("Shadow") + .on_hover_text("Whether to display shadow (need more CPU)"); ui.selectable_value(&mut self.setting.oscilloscope.shadow, true, "On"); ui.selectable_value(&mut self.setting.oscilloscope.shadow, false, "Off"); }); diff --git a/src/frame/spectrogram_meter.rs b/src/frame/spectrogram_meter.rs index f6b39e7..5b8abd6 100644 --- a/src/frame/spectrogram_meter.rs +++ b/src/frame/spectrogram_meter.rs @@ -18,8 +18,8 @@ impl NanometersApp { let ppp = ui.ctx().pixels_per_point(); let width = (rect.width()) as usize; let height = (rect.height()) as usize; - let resolution = 2048; - let speed = 1; + // let resolution = 2048; + // let speed = 1; ui.painter().rect_filled(rect, 0.0, self.setting.theme.bg); // Calculate image match self.setting.spectrogram.mode { @@ -30,57 +30,57 @@ impl NanometersApp { SpectrogramMode::Sharp => { match self.setting.spectrogram.orientation { SpectrogramOrientation::H => { - if !image.is_empty() { - let colorimage = ColorImage { - size: [resolution, (width / speed) as usize], - pixels: image[(1920 - (width / speed) as usize) * resolution - ..1920 * resolution] - .to_owned(), - }; - let texture = ui.ctx().load_texture( - "spectrogram", - colorimage, - Default::default(), - ); - self.spectrogram.texture = Some(texture); - } - if self.spectrogram.texture.is_some() { - Image::from_texture(self.spectrogram.texture.as_ref().unwrap()) - .maintain_aspect_ratio(false) - .fit_to_exact_size(vec2(rect.height(), rect.width())) - .rotate(-90.0_f32.to_radians(), vec2(1.0, 0.0)) - .paint_at( - ui, - Rect::from_min_size( - pos2(rect.min.x - rect.height(), rect.min.y), - vec2(rect.height(), rect.width()), - ), - ); - } + // if !image.is_empty() { + // let colorimage = ColorImage { + // size: [resolution, (width / speed) as usize], + // pixels: image[(1920 - (width / speed) as usize) * resolution + // ..1920 * resolution] + // .to_owned(), + // }; + // let texture = ui.ctx().load_texture( + // "spectrogram", + // colorimage, + // Default::default(), + // ); + // self.spectrogram.texture = Some(texture); + // } + // if self.spectrogram.texture.is_some() { + // Image::from_texture(self.spectrogram.texture.as_ref().unwrap()) + // .maintain_aspect_ratio(false) + // .fit_to_exact_size(vec2(rect.height(), rect.width())) + // .rotate(-90.0_f32.to_radians(), vec2(1.0, 0.0)) + // .paint_at( + // ui, + // Rect::from_min_size( + // pos2(rect.min.x - rect.height(), rect.min.y), + // vec2(rect.height(), rect.width()), + // ), + // ); + // } } SpectrogramOrientation::V => { - if !image.is_empty() { - let colorimage = ColorImage { - size: [resolution, (height / speed) as usize], - pixels: image[(1920 - (height / speed) as usize) * resolution - ..1920 * resolution] - .to_owned(), - }; - let texture = ui.ctx().load_texture( - "spectrogram", - colorimage, - Default::default(), - ); - self.spectrogram.texture = Some(texture); - } - if self.spectrogram.texture.is_some() { - ui.painter().image( - self.spectrogram.texture.as_ref().unwrap().id(), - rect, - Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0)), - Color32::WHITE, - ); - } + // if !image.is_empty() { + // let colorimage = ColorImage { + // size: [resolution, (height / speed) as usize], + // pixels: image[(1920 - (height / speed) as usize) * resolution + // ..1920 * resolution] + // .to_owned(), + // }; + // let texture = ui.ctx().load_texture( + // "spectrogram", + // colorimage, + // Default::default(), + // ); + // self.spectrogram.texture = Some(texture); + // } + // if self.spectrogram.texture.is_some() { + // ui.painter().image( + // self.spectrogram.texture.as_ref().unwrap().id(), + // rect, + // Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0)), + // Color32::WHITE, + // ); + // } } }; } diff --git a/src/frame/spectrum_meter.rs b/src/frame/spectrum_meter.rs index c0c7821..554dd7d 100644 --- a/src/frame/spectrum_meter.rs +++ b/src/frame/spectrum_meter.rs @@ -4,6 +4,7 @@ use crate::setting::SpectrumMode; use crate::utils::*; use crate::NanometersApp; use egui::*; +use rustfft::num_complex::ComplexFloat; use text::Fonts; impl NanometersApp { @@ -25,6 +26,7 @@ impl NanometersApp { self.spectrum.ch1 = vec![0.0; 2049]; } + // Ref lines match self.setting.spectrum.freq_line { SpectrumFreqLine::Off => {} SpectrumFreqLine::On => { @@ -77,6 +79,8 @@ impl NanometersApp { Stroke::new(1.0, self.setting.theme.main), ); + // Main + let mut max_index = 0; match self.setting.spectrum.mode { SpectrumMode::FFT => { let mut wave_0_points = Vec::new(); @@ -100,6 +104,9 @@ impl NanometersApp { ); } else { for i in 0..2049 { + if data.l[i] >= data.l[max_index] { + max_index = i; + } if data.l[i] > self.spectrum.ch0[i] || self.spectrum.ch0[i].is_nan() { self.spectrum.ch0[i] = data.l[i]; wave_0_points.push(pos2( @@ -141,6 +148,15 @@ impl NanometersApp { SpectrumMode::ColorBar => {} SpectrumMode::Both => {} } + if max_index > 0 && max_index < 2048 { + let delta = (data.l[max_index + 1].abs() - data.l[max_index - 1].abs()) + / (2.0 + * (2.0 * data.l[max_index].abs() + - data.l[max_index - 1].abs() + - data.l[max_index + 1].abs())); + let freq = (max_index as f32 + delta) * 11.7130307467; + let freq_str = format!("{:.1} Hz", freq); + } } } diff --git a/src/setting/spectrum.rs b/src/setting/spectrum.rs index 8ce09b5..9639d89 100644 --- a/src/setting/spectrum.rs +++ b/src/setting/spectrum.rs @@ -40,7 +40,7 @@ pub enum SpectrumFreqLine { Bright, } -#[derive(Default, Clone, Copy, Debug, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct SpectrumSetting { #[serde(skip)] pub(crate) spectrum_switch: SpectrumSwitch, @@ -57,6 +57,25 @@ pub struct SpectrumSetting { pub(crate) threshold_follow_slope: bool, } +impl Default for SpectrumSetting { + fn default() -> Self { + Self { + spectrum_switch: SpectrumSwitch::Main, + mode: SpectrumMode::FFT, + smoothing: 0.0, + slope: 0.0, + channel: SpectrumChannel::LR, + low: -150.0, + high: 20.0, + freq_readout: SpectrumFreqReadout::Off, + freq_line: SpectrumFreqLine::Off, + ref_line: 0.0, + threshold: 0.0, + threshold_follow_slope: false, + } + } +} + #[derive(Default, Clone, Debug, Serialize, Deserialize)] pub struct Spectrum { #[serde(skip)] diff --git a/src/utils/color.rs b/src/utils/color.rs index 2fd1e1b..62ecc5d 100644 --- a/src/utils/color.rs +++ b/src/utils/color.rs @@ -23,223 +23,223 @@ pub fn normalize_color(low: f32, mid: f32, high: f32) -> Color32 { Color32::from_rgb(r, g, b) } -pub fn color_lut_129() -> Vec { - (0..129) - .into_iter() - .map(|i| { - let h = i as f64 * 360.0 / 129.0; - let s = 1.0; - let v = 1.0; - hsv_to_rgb(h as u16, s, v).unwrap() - }) - .collect() -} +// pub fn color_lut_129() -> Vec { +// (0..129) +// .into_iter() +// .map(|i| { +// let h = i as f64 * 360.0 / 129.0; +// let s = 1.0; +// let v = 1.0; +// hsv_to_rgb(h as u16, s, v).unwrap() +// }) +// .collect() +// } -pub fn hsl_to_rgb(h: u16, s: f64, l: f64) -> Option { - match h { - 0..=60 => { - let c = color_hsl_c(l, s); - let x = color_hsl_x(c, h as f64); - let m = color_hsl_m(l, c); - Some(egui::Color32::from_rgb( - ((c + m) * 255.0) as u8, - ((x + m) * 255.0) as u8, - (m * 255.0) as u8, - )) - } - 61..=120 => { - let c = color_hsl_c(l, s); - let x = color_hsl_x(c, h as f64); - let m = color_hsl_m(l, c); - Some(egui::Color32::from_rgb( - ((x + m) * 255.0) as u8, - ((c + m) * 255.0) as u8, - (m * 255.0) as u8, - )) - } - 121..=180 => { - let c = color_hsl_c(l, s); - let x = color_hsl_x(c, h as f64); - let m = color_hsl_m(l, c); - Some(egui::Color32::from_rgb( - (m * 255.0) as u8, - ((c + m) * 255.0) as u8, - ((x + m) * 255.0) as u8, - )) - } - 181..=240 => { - let c = color_hsl_c(l, s); - let x = color_hsl_x(c, h as f64); - let m = color_hsl_m(l, c); - Some(egui::Color32::from_rgb( - (m * 255.0) as u8, - ((x + m) * 255.0) as u8, - ((c + m) * 255.0) as u8, - )) - } - 241..=300 => { - let c = color_hsl_c(l, s); - let x = color_hsl_x(c, h as f64); - let m = color_hsl_m(l, c); - Some(egui::Color32::from_rgb( - ((x + m) * 255.0) as u8, - (m * 255.0) as u8, - ((c + m) * 255.0) as u8, - )) - } - 301..=360 => { - let c = color_hsl_c(l, s); - let x = color_hsl_x(c, h as f64); - let m = color_hsl_m(l, c); - Some(egui::Color32::from_rgb( - ((c + m) * 255.0) as u8, - (m * 255.0) as u8, - ((x + m) * 255.0) as u8, - )) - } - _ => None, - } -} +// pub fn hsl_to_rgb(h: u16, s: f64, l: f64) -> Option { +// match h { +// 0..=60 => { +// let c = color_hsl_c(l, s); +// let x = color_hsl_x(c, h as f64); +// let m = color_hsl_m(l, c); +// Some(egui::Color32::from_rgb( +// ((c + m) * 255.0) as u8, +// ((x + m) * 255.0) as u8, +// (m * 255.0) as u8, +// )) +// } +// 61..=120 => { +// let c = color_hsl_c(l, s); +// let x = color_hsl_x(c, h as f64); +// let m = color_hsl_m(l, c); +// Some(egui::Color32::from_rgb( +// ((x + m) * 255.0) as u8, +// ((c + m) * 255.0) as u8, +// (m * 255.0) as u8, +// )) +// } +// 121..=180 => { +// let c = color_hsl_c(l, s); +// let x = color_hsl_x(c, h as f64); +// let m = color_hsl_m(l, c); +// Some(egui::Color32::from_rgb( +// (m * 255.0) as u8, +// ((c + m) * 255.0) as u8, +// ((x + m) * 255.0) as u8, +// )) +// } +// 181..=240 => { +// let c = color_hsl_c(l, s); +// let x = color_hsl_x(c, h as f64); +// let m = color_hsl_m(l, c); +// Some(egui::Color32::from_rgb( +// (m * 255.0) as u8, +// ((x + m) * 255.0) as u8, +// ((c + m) * 255.0) as u8, +// )) +// } +// 241..=300 => { +// let c = color_hsl_c(l, s); +// let x = color_hsl_x(c, h as f64); +// let m = color_hsl_m(l, c); +// Some(egui::Color32::from_rgb( +// ((x + m) * 255.0) as u8, +// (m * 255.0) as u8, +// ((c + m) * 255.0) as u8, +// )) +// } +// 301..=360 => { +// let c = color_hsl_c(l, s); +// let x = color_hsl_x(c, h as f64); +// let m = color_hsl_m(l, c); +// Some(egui::Color32::from_rgb( +// ((c + m) * 255.0) as u8, +// (m * 255.0) as u8, +// ((x + m) * 255.0) as u8, +// )) +// } +// _ => None, +// } +// } -fn color_hsl_c(l: f64, s: f64) -> f64 { - (1.0 - (2.0 * l - 1.0).abs()) * s -} +// fn color_hsl_c(l: f64, s: f64) -> f64 { +// (1.0 - (2.0 * l - 1.0).abs()) * s +// } -fn color_hsl_x(c: f64, h: f64) -> f64 { - c * (1.0 - ((h / 60.0) % 2.0 - 1.0).abs()) -} +// fn color_hsl_x(c: f64, h: f64) -> f64 { +// c * (1.0 - ((h / 60.0) % 2.0 - 1.0).abs()) +// } -fn color_hsl_m(l: f64, c: f64) -> f64 { - l - c / 2.0 -} +// fn color_hsl_m(l: f64, c: f64) -> f64 { +// l - c / 2.0 +// } -pub fn hsv_to_rgb(h: u16, s: f64, v: f64) -> Option { - match h { - 0..=60 => { - let c = color_hsv_c(v, s); - let x = color_hsv_x(c, h as f64); - let m = color_hsv_m(v, c); - Some(egui::Color32::from_rgb( - ((c + m) * 255.0) as u8, - ((x + m) * 255.0) as u8, - (m * 255.0) as u8, - )) - } - 61..=120 => { - let c = color_hsv_c(v, s); - let x = color_hsv_x(c, h as f64); - let m = color_hsv_m(v, c); - Some(egui::Color32::from_rgb( - ((x + m) * 255.0) as u8, - ((c + m) * 255.0) as u8, - (m * 255.0) as u8, - )) - } - 121..=180 => { - let c = color_hsv_c(v, s); - let x = color_hsv_x(c, h as f64); - let m = color_hsv_m(v, c); - Some(egui::Color32::from_rgb( - (m * 255.0) as u8, - ((c + m) * 255.0) as u8, - ((x + m) * 255.0) as u8, - )) - } - 181..=240 => { - let c = color_hsv_c(v, s); - let x = color_hsv_x(c, h as f64); - let m = color_hsv_m(v, c); - Some(egui::Color32::from_rgb( - (m * 255.0) as u8, - ((x + m) * 255.0) as u8, - ((c + m) * 255.0) as u8, - )) - } - 241..=300 => { - let c = color_hsv_c(v, s); - let x = color_hsv_x(c, h as f64); - let m = color_hsv_m(v, c); - Some(egui::Color32::from_rgb( - ((x + m) * 255.0) as u8, - (m * 255.0) as u8, - ((c + m) * 255.0) as u8, - )) - } - 301..=360 => { - let c = color_hsv_c(v, s); - let x = color_hsv_x(c, h as f64); - let m = color_hsv_m(v, c); - Some(egui::Color32::from_rgb( - ((c + m) * 255.0) as u8, - (m * 255.0) as u8, - ((x + m) * 255.0) as u8, - )) - } - _ => None, - } -} +// pub fn hsv_to_rgb(h: u16, s: f64, v: f64) -> Option { +// match h { +// 0..=60 => { +// let c = color_hsv_c(v, s); +// let x = color_hsv_x(c, h as f64); +// let m = color_hsv_m(v, c); +// Some(egui::Color32::from_rgb( +// ((c + m) * 255.0) as u8, +// ((x + m) * 255.0) as u8, +// (m * 255.0) as u8, +// )) +// } +// 61..=120 => { +// let c = color_hsv_c(v, s); +// let x = color_hsv_x(c, h as f64); +// let m = color_hsv_m(v, c); +// Some(egui::Color32::from_rgb( +// ((x + m) * 255.0) as u8, +// ((c + m) * 255.0) as u8, +// (m * 255.0) as u8, +// )) +// } +// 121..=180 => { +// let c = color_hsv_c(v, s); +// let x = color_hsv_x(c, h as f64); +// let m = color_hsv_m(v, c); +// Some(egui::Color32::from_rgb( +// (m * 255.0) as u8, +// ((c + m) * 255.0) as u8, +// ((x + m) * 255.0) as u8, +// )) +// } +// 181..=240 => { +// let c = color_hsv_c(v, s); +// let x = color_hsv_x(c, h as f64); +// let m = color_hsv_m(v, c); +// Some(egui::Color32::from_rgb( +// (m * 255.0) as u8, +// ((x + m) * 255.0) as u8, +// ((c + m) * 255.0) as u8, +// )) +// } +// 241..=300 => { +// let c = color_hsv_c(v, s); +// let x = color_hsv_x(c, h as f64); +// let m = color_hsv_m(v, c); +// Some(egui::Color32::from_rgb( +// ((x + m) * 255.0) as u8, +// (m * 255.0) as u8, +// ((c + m) * 255.0) as u8, +// )) +// } +// 301..=360 => { +// let c = color_hsv_c(v, s); +// let x = color_hsv_x(c, h as f64); +// let m = color_hsv_m(v, c); +// Some(egui::Color32::from_rgb( +// ((c + m) * 255.0) as u8, +// (m * 255.0) as u8, +// ((x + m) * 255.0) as u8, +// )) +// } +// _ => None, +// } +// } -fn color_hsv_c(v: f64, s: f64) -> f64 { - v * s -} +// fn color_hsv_c(v: f64, s: f64) -> f64 { +// v * s +// } -fn color_hsv_x(c: f64, h: f64) -> f64 { - c * (1.0 - ((h / 60.0) % 2.0 - 1.0).abs()) -} +// fn color_hsv_x(c: f64, h: f64) -> f64 { +// c * (1.0 - ((h / 60.0) % 2.0 - 1.0).abs()) +// } -fn color_hsv_m(v: f64, c: f64) -> f64 { - v - c -} +// fn color_hsv_m(v: f64, c: f64) -> f64 { +// v - c +// } -#[cfg(test)] -mod tests { - use super::*; +// #[cfg(test)] +// mod tests { +// use super::*; - #[test] - fn test_hsl_to_rgb() { - assert_eq!( - hsl_to_rgb(0, 0.0, 0.0), - Some(egui::Color32::from_rgb(0, 0, 0)) - ); - assert_eq!( - hsl_to_rgb(0, 0.0, 1.0), - Some(egui::Color32::from_rgb(255, 255, 255)) - ); - assert_eq!( - hsl_to_rgb(0, 1.0, 0.5), - Some(egui::Color32::from_rgb(255, 0, 0)) - ); - assert_eq!( - hsl_to_rgb(120, 1.0, 0.5), - Some(egui::Color32::from_rgb(0, 255, 0)) - ); - assert_eq!( - hsl_to_rgb(240, 1.0, 0.5), - Some(egui::Color32::from_rgb(0, 0, 255)) - ); - } +// #[test] +// fn test_hsl_to_rgb() { +// assert_eq!( +// hsl_to_rgb(0, 0.0, 0.0), +// Some(egui::Color32::from_rgb(0, 0, 0)) +// ); +// assert_eq!( +// hsl_to_rgb(0, 0.0, 1.0), +// Some(egui::Color32::from_rgb(255, 255, 255)) +// ); +// assert_eq!( +// hsl_to_rgb(0, 1.0, 0.5), +// Some(egui::Color32::from_rgb(255, 0, 0)) +// ); +// assert_eq!( +// hsl_to_rgb(120, 1.0, 0.5), +// Some(egui::Color32::from_rgb(0, 255, 0)) +// ); +// assert_eq!( +// hsl_to_rgb(240, 1.0, 0.5), +// Some(egui::Color32::from_rgb(0, 0, 255)) +// ); +// } - #[test] - fn test_hsv_to_rgb() { - assert_eq!( - hsv_to_rgb(0, 0.0, 0.0), - Some(egui::Color32::from_rgb(0, 0, 0)) - ); - assert_eq!( - hsv_to_rgb(0, 0.0, 1.0), - Some(egui::Color32::from_rgb(255, 255, 255)) - ); - assert_eq!( - hsv_to_rgb(0, 1.0, 0.5), - Some(egui::Color32::from_rgb(127, 0, 0)) - ); - assert_eq!( - hsv_to_rgb(120, 1.0, 0.5), - Some(egui::Color32::from_rgb(0, 127, 0)) - ); - assert_eq!( - hsv_to_rgb(240, 1.0, 0.5), - Some(egui::Color32::from_rgb(0, 0, 127)) - ); - } -} +// #[test] +// fn test_hsv_to_rgb() { +// assert_eq!( +// hsv_to_rgb(0, 0.0, 0.0), +// Some(egui::Color32::from_rgb(0, 0, 0)) +// ); +// assert_eq!( +// hsv_to_rgb(0, 0.0, 1.0), +// Some(egui::Color32::from_rgb(255, 255, 255)) +// ); +// assert_eq!( +// hsv_to_rgb(0, 1.0, 0.5), +// Some(egui::Color32::from_rgb(127, 0, 0)) +// ); +// assert_eq!( +// hsv_to_rgb(120, 1.0, 0.5), +// Some(egui::Color32::from_rgb(0, 127, 0)) +// ); +// assert_eq!( +// hsv_to_rgb(240, 1.0, 0.5), +// Some(egui::Color32::from_rgb(0, 0, 127)) +// ); +// } +// } diff --git a/src/utils/data_struct.rs b/src/utils/data_struct.rs index a7af18f..555ea37 100644 --- a/src/utils/data_struct.rs +++ b/src/utils/data_struct.rs @@ -1,6 +1,7 @@ use crate::setting::*; use egui::*; use std::{collections::binary_heap, fmt::Display}; +use tiny_skia::Pixmap; #[derive(Debug, Clone, Default)] pub struct RawData { @@ -217,7 +218,7 @@ pub struct SpectrogramCalcBuffer { pub ab: bool, pub a: SpectrogramOneWindow, pub b: SpectrogramOneWindow, - pub image: Vec, + // pub image: Vec, } impl SpectrogramCalcBuffer { @@ -226,7 +227,7 @@ impl SpectrogramCalcBuffer { ab: false, a: SpectrogramOneWindow::new(), b: SpectrogramOneWindow::new(), - image: vec![Color32::TRANSPARENT; 4000 * 4000], + // image: vec![Color32::TRANSPARENT; 4000 * 4000], } } } @@ -313,7 +314,7 @@ impl SpectrumSendData { } } -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub struct SendData { pub waveform: WaveformSendData, pub iir: Vec, @@ -321,7 +322,8 @@ pub struct SendData { pub vectorscope: VectorscopeSendData, pub spectrum: RawData, pub oscilloscope: OscilloscopeSendData, - pub spectrogram_image: Vec, + // pub spectrogram_image: Vec, + pub spectrogram_frame: Pixmap, } impl SendData { @@ -331,3 +333,18 @@ impl SendData { } } } + +impl Default for SendData { + fn default() -> Self { + Self { + waveform: WaveformSendData::new(), + iir: vec![0.0; 2], + db: DBData::new(), + vectorscope: VectorscopeSendData::new(), + spectrum: RawData::new(), + oscilloscope: OscilloscopeSendData::new(), + // spectrogram_image: vec![Color32::TRANSPARENT; 4000 * 4000], + spectrogram_frame: Pixmap::new(1, 1).unwrap(), + } + } +}