From 3999b158a0e18061df4d0a29fda5c5d6aaa0cb44 Mon Sep 17 00:00:00 2001 From: Marco Farruggio Date: Thu, 3 Sep 2026 14:37:25 +0100 Subject: [PATCH 1/5] general clean ups, particularly sample formats, with const for many functions --- src/host/equilibrium.rs | 5 +- src/host/mod.rs | 8 ++- src/sample_format.rs | 152 ++++++++++++++-------------------------- 3 files changed, 59 insertions(+), 106 deletions(-) diff --git a/src/host/equilibrium.rs b/src/host/equilibrium.rs index 8b4d960c1..5409bb568 100644 --- a/src/host/equilibrium.rs +++ b/src/host/equilibrium.rs @@ -10,9 +10,8 @@ pub fn fill_equilibrium(buffer: &mut [u8], sample_format: SampleFormat) { ($sample_type:ty) => {{ let sample_size = std::mem::size_of::<$sample_type>(); - debug_assert_eq!( - buffer.len() % sample_size, - 0, + debug_assert!( + buffer.len() % sample_size == 0, "Buffer size must be aligned to sample size for format {:?}", sample_format ); diff --git a/src/host/mod.rs b/src/host/mod.rs index b1df58e1d..385a91e55 100644 --- a/src/host/mod.rs +++ b/src/host/mod.rs @@ -256,12 +256,16 @@ pub(crate) fn frames_to_duration( if rate == 0 { return std::time::Duration::ZERO; } + + let frames = frames as u64; let rate = rate as u64; - let secs = frames as u64 / rate; + + let secs = frames / rate; // rem_frames < rate <= u32::MAX, so rem_frames * 1_000_000_000 < u64::MAX - let rem_frames = frames as u64 % rate; + let rem_frames = frames % rate; // Round to nearest so the duration isn't biased. let nanos = (rem_frames * 1_000_000_000 + rate / 2) / rate; + std::time::Duration::new(secs, nanos as u32) } diff --git a/src/sample_format.rs b/src/sample_format.rs index fd1f0ceb1..faee51754 100644 --- a/src/sample_format.rs +++ b/src/sample_format.rs @@ -35,9 +35,6 @@ pub use dasp_sample::{FromSample, Sample}; ))] use wasm_bindgen::prelude::*; -// I48 and U48 are not currently supported by cpal but available in dasp_sample: -// pub use dasp_sample::{I48, U48}; - /// Format that each sample has. Usually, this corresponds to the sampling /// depth of the audio source. For example, 16 bit quantized samples can be /// encoded in `i16` or `u16`. Note that the quantized sampling depth is not @@ -78,8 +75,6 @@ pub enum SampleFormat { /// `i32` with a valid range of `i32::MIN..=i32::MAX` with `0` being the origin. I32, - // /// `I48` with a valid range of '-(1 << 47)..(1 << 47)' with `0` being the origin - // I48, /// `i64` with a valid range of `i64::MIN..=i64::MAX` with `0` being the origin. I64, @@ -97,9 +92,6 @@ pub enum SampleFormat { /// `u32` with a valid range of `u32::MIN..=u32::MAX` with `1 << 31` being the origin. U32, - /// `U48` with a valid range of '0..(1 << 48)' with `1 << 47` being the origin - // U48, - /// `u64` with a valid range of `u64::MIN..=u64::MAX` with `1 << 63` being the origin. U64, @@ -125,23 +117,21 @@ impl SampleFormat { /// sample format (e.g., i24 has size of i32). #[inline] #[must_use] - pub fn sample_size(&self) -> usize { - match *self { - SampleFormat::I8 => mem::size_of::(), - SampleFormat::U8 => mem::size_of::(), + pub const fn sample_size(self) -> usize { + match self { + SampleFormat::I8 => mem::size_of::(), + SampleFormat::U8 => mem::size_of::(), SampleFormat::I16 => mem::size_of::(), SampleFormat::U16 => mem::size_of::(), SampleFormat::I24 => mem::size_of::(), SampleFormat::U24 => mem::size_of::(), SampleFormat::I32 => mem::size_of::(), SampleFormat::U32 => mem::size_of::(), - // SampleFormat::I48 => mem::size_of::(), - // SampleFormat::U48 => mem::size_of::(), SampleFormat::I64 => mem::size_of::(), SampleFormat::U64 => mem::size_of::(), SampleFormat::F32 => mem::size_of::(), SampleFormat::F64 => mem::size_of::(), - SampleFormat::DsdU8 => mem::size_of::(), + SampleFormat::DsdU8 => mem::size_of::(), SampleFormat::DsdU16 => mem::size_of::(), SampleFormat::DsdU32 => mem::size_of::(), } @@ -152,21 +142,19 @@ impl SampleFormat { /// this sample format (e.g., I24 has size of i32 but 24 bits per sample). #[inline] #[must_use] - pub fn bits_per_sample(&self) -> u32 { - match *self { - SampleFormat::I8 => i8::BITS, - SampleFormat::U8 => u8::BITS, + pub const fn bits_per_sample(self) -> u32 { + match self { + SampleFormat::I8 => i8::BITS, + SampleFormat::U8 => u8::BITS, SampleFormat::I16 => i16::BITS, SampleFormat::U16 => u16::BITS, SampleFormat::I24 => 24, SampleFormat::U24 => 24, SampleFormat::I32 => i32::BITS, SampleFormat::U32 => u32::BITS, - // SampleFormat::I48 => 48, - // SampleFormat::U48 => 48, SampleFormat::I64 => i64::BITS, SampleFormat::U64 => u64::BITS, - SampleFormat::F32 => 32, + SampleFormat::F32 => 32, // f32/64::BITS is currently unstable, so we hardcode the values here. SampleFormat::F64 => 64, SampleFormat::DsdU8 | SampleFormat::DsdU16 | SampleFormat::DsdU32 => 1, } @@ -174,66 +162,59 @@ impl SampleFormat { #[inline] #[must_use] - pub fn is_int(&self) -> bool { + pub const fn is_int(self) -> bool { matches!( - *self, + self, SampleFormat::I8 - | SampleFormat::I16 - | SampleFormat::I24 - | SampleFormat::I32 - // | SampleFormat::I48 - | SampleFormat::I64 + | SampleFormat::I16 + | SampleFormat::I24 + | SampleFormat::I32 + | SampleFormat::I64 ) } #[inline] #[must_use] - pub fn is_uint(&self) -> bool { + pub const fn is_uint(self) -> bool { matches!( - *self, + self, SampleFormat::U8 - | SampleFormat::U16 - | SampleFormat::U24 - | SampleFormat::U32 - // | SampleFormat::U48 - | SampleFormat::U64 + | SampleFormat::U16 + | SampleFormat::U24 + | SampleFormat::U32 + | SampleFormat::U64 ) } #[inline] #[must_use] - pub fn is_float(&self) -> bool { - matches!(*self, SampleFormat::F32 | SampleFormat::F64) + pub const fn is_float(self) -> bool { + matches!(self, SampleFormat::F32 | SampleFormat::F64) } #[inline] #[must_use] - pub fn is_dsd(&self) -> bool { - matches!( - *self, - SampleFormat::DsdU8 | SampleFormat::DsdU16 | SampleFormat::DsdU32 - ) + pub const fn is_dsd(self) -> bool { + matches!(self, SampleFormat::DsdU8 | SampleFormat::DsdU16 | SampleFormat::DsdU32) } } impl Display for SampleFormat { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - SampleFormat::I8 => "i8", + SampleFormat::I8 => "i8", SampleFormat::I16 => "i16", SampleFormat::I24 => "i24", SampleFormat::I32 => "i32", - // SampleFormat::I48 => "i48", SampleFormat::I64 => "i64", - SampleFormat::U8 => "u8", + SampleFormat::U8 => "u8", SampleFormat::U16 => "u16", SampleFormat::U24 => "u24", SampleFormat::U32 => "u32", - // SampleFormat::U48 => "u48", SampleFormat::U64 => "u64", SampleFormat::F32 => "f32", SampleFormat::F64 => "f64", - SampleFormat::DsdU8 => "dsdu8", + SampleFormat::DsdU8 => "dsdu8", SampleFormat::DsdU16 => "dsdu16", SampleFormat::DsdU32 => "dsdu32", } @@ -264,58 +245,27 @@ pub trait SizedSample: Sample { const FORMAT: SampleFormat; } -impl SizedSample for i8 { - const FORMAT: SampleFormat = SampleFormat::I8; -} - -impl SizedSample for i16 { - const FORMAT: SampleFormat = SampleFormat::I16; -} - -impl SizedSample for I24 { - const FORMAT: SampleFormat = SampleFormat::I24; -} - -impl SizedSample for i32 { - const FORMAT: SampleFormat = SampleFormat::I32; -} - -// impl SizedSample for I48 { -// const FORMAT: SampleFormat = SampleFormat::I48; -// } - -impl SizedSample for i64 { - const FORMAT: SampleFormat = SampleFormat::I64; +macro_rules! impl_sized_sample { + ($($sample_type:ty => $format:expr),* $(,)?) => { + $( + impl SizedSample for $sample_type { + const FORMAT: SampleFormat = $format; + } + )* + }; } -impl SizedSample for u8 { - const FORMAT: SampleFormat = SampleFormat::U8; -} - -impl SizedSample for u16 { - const FORMAT: SampleFormat = SampleFormat::U16; -} - -impl SizedSample for U24 { - const FORMAT: SampleFormat = SampleFormat::U24; -} - -impl SizedSample for u32 { - const FORMAT: SampleFormat = SampleFormat::U32; -} - -// impl SizedSample for U48 { -// const FORMAT: SampleFormat = SampleFormat::U48; -// } - -impl SizedSample for u64 { - const FORMAT: SampleFormat = SampleFormat::U64; -} - -impl SizedSample for f32 { - const FORMAT: SampleFormat = SampleFormat::F32; -} - -impl SizedSample for f64 { - const FORMAT: SampleFormat = SampleFormat::F64; -} +impl_sized_sample! { + i8 => SampleFormat::I8, + i16 => SampleFormat::I16, + I24 => SampleFormat::I24, + i32 => SampleFormat::I32, + i64 => SampleFormat::I64, + u8 => SampleFormat::U8, + u16 => SampleFormat::U16, + U24 => SampleFormat::U24, + u32 => SampleFormat::U32, + u64 => SampleFormat::U64, + f32 => SampleFormat::F32, + f64 => SampleFormat::F64, +} \ No newline at end of file From 8609e77f20cead685032f26739d3212a092b928c Mon Sep 17 00:00:00 2001 From: Marco Farruggio Date: Thu, 3 Sep 2026 14:50:09 +0100 Subject: [PATCH 2/5] undid the match arm lining-up, so that code quality is happy --- src/sample_format.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sample_format.rs b/src/sample_format.rs index faee51754..10cd20b8d 100644 --- a/src/sample_format.rs +++ b/src/sample_format.rs @@ -119,8 +119,8 @@ impl SampleFormat { #[must_use] pub const fn sample_size(self) -> usize { match self { - SampleFormat::I8 => mem::size_of::(), - SampleFormat::U8 => mem::size_of::(), + SampleFormat::I8 => mem::size_of::(), + SampleFormat::U8 => mem::size_of::(), SampleFormat::I16 => mem::size_of::(), SampleFormat::U16 => mem::size_of::(), SampleFormat::I24 => mem::size_of::(), @@ -131,7 +131,7 @@ impl SampleFormat { SampleFormat::U64 => mem::size_of::(), SampleFormat::F32 => mem::size_of::(), SampleFormat::F64 => mem::size_of::(), - SampleFormat::DsdU8 => mem::size_of::(), + SampleFormat::DsdU8 => mem::size_of::(), SampleFormat::DsdU16 => mem::size_of::(), SampleFormat::DsdU32 => mem::size_of::(), } @@ -144,8 +144,8 @@ impl SampleFormat { #[must_use] pub const fn bits_per_sample(self) -> u32 { match self { - SampleFormat::I8 => i8::BITS, - SampleFormat::U8 => u8::BITS, + SampleFormat::I8 => i8::BITS, + SampleFormat::U8 => u8::BITS, SampleFormat::I16 => i16::BITS, SampleFormat::U16 => u16::BITS, SampleFormat::I24 => 24, @@ -202,7 +202,7 @@ impl SampleFormat { impl Display for SampleFormat { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - SampleFormat::I8 => "i8", + SampleFormat::I8 => "i8", SampleFormat::I16 => "i16", SampleFormat::I24 => "i24", SampleFormat::I32 => "i32", @@ -214,7 +214,7 @@ impl Display for SampleFormat { SampleFormat::U64 => "u64", SampleFormat::F32 => "f32", SampleFormat::F64 => "f64", - SampleFormat::DsdU8 => "dsdu8", + SampleFormat::DsdU8 => "dsdu8", SampleFormat::DsdU16 => "dsdu16", SampleFormat::DsdU32 => "dsdu32", } @@ -256,12 +256,12 @@ macro_rules! impl_sized_sample { } impl_sized_sample! { - i8 => SampleFormat::I8, + i8 => SampleFormat::I8, i16 => SampleFormat::I16, I24 => SampleFormat::I24, i32 => SampleFormat::I32, i64 => SampleFormat::I64, - u8 => SampleFormat::U8, + u8 => SampleFormat::U8, u16 => SampleFormat::U16, U24 => SampleFormat::U24, u32 => SampleFormat::U32, From 1718ccb096689ada46f96e78a0328387336a1180 Mon Sep 17 00:00:00 2001 From: Marco Farruggio Date: Thu, 3 Sep 2026 14:56:22 +0100 Subject: [PATCH 3/5] submitted to rust-fmt --- src/sample_format.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/sample_format.rs b/src/sample_format.rs index 10cd20b8d..8847e5100 100644 --- a/src/sample_format.rs +++ b/src/sample_format.rs @@ -166,10 +166,10 @@ impl SampleFormat { matches!( self, SampleFormat::I8 - | SampleFormat::I16 - | SampleFormat::I24 - | SampleFormat::I32 - | SampleFormat::I64 + | SampleFormat::I16 + | SampleFormat::I24 + | SampleFormat::I32 + | SampleFormat::I64 ) } @@ -179,10 +179,10 @@ impl SampleFormat { matches!( self, SampleFormat::U8 - | SampleFormat::U16 - | SampleFormat::U24 - | SampleFormat::U32 - | SampleFormat::U64 + | SampleFormat::U16 + | SampleFormat::U24 + | SampleFormat::U32 + | SampleFormat::U64 ) } @@ -195,7 +195,10 @@ impl SampleFormat { #[inline] #[must_use] pub const fn is_dsd(self) -> bool { - matches!(self, SampleFormat::DsdU8 | SampleFormat::DsdU16 | SampleFormat::DsdU32) + matches!( + self, + SampleFormat::DsdU8 | SampleFormat::DsdU16 | SampleFormat::DsdU32 + ) } } @@ -207,7 +210,7 @@ impl Display for SampleFormat { SampleFormat::I24 => "i24", SampleFormat::I32 => "i32", SampleFormat::I64 => "i64", - SampleFormat::U8 => "u8", + SampleFormat::U8 => "u8", SampleFormat::U16 => "u16", SampleFormat::U24 => "u24", SampleFormat::U32 => "u32", @@ -268,4 +271,4 @@ impl_sized_sample! { u64 => SampleFormat::U64, f32 => SampleFormat::F32, f64 => SampleFormat::F64, -} \ No newline at end of file +} From 0a1d75366e52553ef8026ff9e46e0fac81e3e38c Mon Sep 17 00:00:00 2001 From: Marco Farruggio Date: Sat, 5 Sep 2026 12:41:21 +0100 Subject: [PATCH 4/5] make frames_to_duration const --- src/host/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/host/mod.rs b/src/host/mod.rs index 385a91e55..9fbde786f 100644 --- a/src/host/mod.rs +++ b/src/host/mod.rs @@ -249,7 +249,7 @@ pub(crate) use error_emit::try_emit_error; feature = "audioworklet", ))] #[inline] -pub(crate) fn frames_to_duration( +pub(crate) const fn frames_to_duration( frames: crate::FrameCount, rate: crate::SampleRate, ) -> std::time::Duration { From 9615dc7bd11de80e29bc9761f0bb64a949dedc74 Mon Sep 17 00:00:00 2001 From: Marco Farruggio Date: Sat, 5 Sep 2026 12:44:27 +0100 Subject: [PATCH 5/5] use {text} in format strings, where logical --- UPGRADING.md | 6 +++--- src/device_description.rs | 2 +- src/host/alsa/enumerate.rs | 4 ++-- src/host/jack/device.rs | 4 ++-- src/host/jack/stream.rs | 4 ++-- src/lib.rs | 8 ++++---- src/platform/mod.rs | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/UPGRADING.md b/UPGRADING.md index 846a50551..9177e24a3 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -407,12 +407,12 @@ let device = host.device_by_id(&id); ```rust // Before (v0.17) for line in desc.extended() { // &[String] - println!("{}", line); // line: &String + println!("{line}"); // line: &String } // After (v0.18) for line in desc.extended() { // impl Iterator - println!("{}", line); // line: &str — Display, write!, format! all unchanged + println!("{line}"); // line: &str — Display, write!, format! all unchanged } ``` @@ -540,7 +540,7 @@ let name = device.name()?; // New: For user-facing display let desc = device.description()?; -println!("Device: {}", desc); // or desc.name() for just the name +println!("Device: {desc}"); // or desc.name() for just the name // New: For stable identification and persistence let id = device.id()?; diff --git a/src/device_description.rs b/src/device_description.rs index 5618958e5..84a8a9378 100644 --- a/src/device_description.rs +++ b/src/device_description.rs @@ -222,7 +222,7 @@ impl fmt::Display for DeviceDescription { write!(f, "{}", self.name)?; if let Some(mfr) = &self.manufacturer { - write!(f, " ({})", mfr)?; + write!(f, " ({mfr})")?; } if self.device_type != DeviceType::Unknown { diff --git a/src/host/alsa/enumerate.rs b/src/host/alsa/enumerate.rs index 144a04b54..35bd3e4d6 100644 --- a/src/host/alsa/enumerate.rs +++ b/src/host/alsa/enumerate.rs @@ -91,7 +91,7 @@ fn format_device_description(phys_dev: &PhysicalDevice, prefix: &str) -> String _ => "", }; - format!("{}\n{}", first_line, second_line) + format!("{first_line}\n{second_line}") } fn physical_devices() -> Vec { @@ -133,7 +133,7 @@ fn physical_devices() -> Vec { } }; - let device_name = device_name.unwrap_or_else(|| format!("Device {}", device_index)); + let device_name = device_name.unwrap_or_else(|| format!("Device {device_index}")); devices.push(PhysicalDevice { card_index, card_name: card_name.clone(), diff --git a/src/host/jack/device.rs b/src/host/jack/device.rs index 32f0a5ecd..f7bfffa2f 100644 --- a/src/host/jack/device.rs +++ b/src/host/jack/device.rs @@ -87,7 +87,7 @@ impl Device { connect_ports_automatically: bool, start_server_automatically: bool, ) -> Result { - let output_client_name = format!("{}_out", name); + let output_client_name = format!("{name}_out"); Device::new_device( output_client_name, connect_ports_automatically, @@ -101,7 +101,7 @@ impl Device { connect_ports_automatically: bool, start_server_automatically: bool, ) -> Result { - let input_client_name = format!("{}_in", name); + let input_client_name = format!("{name}_in"); Device::new_device( input_client_name, connect_ports_automatically, diff --git a/src/host/jack/stream.rs b/src/host/jack/stream.rs index 79da78084..efedc17f8 100644 --- a/src/host/jack/stream.rs +++ b/src/host/jack/stream.rs @@ -58,7 +58,7 @@ impl Stream { let mut port_names: Vec = vec![]; for i in 0..channels { let port = client - .register_port(&format!("in_{}", i), jack::AudioIn::default()) + .register_port(&format!("in_{i}"), jack::AudioIn::default()) .context(format!("Failed to register input port {i}"))?; if let Ok(port_name) = port.name() { port_names.push(port_name); @@ -117,7 +117,7 @@ impl Stream { let mut port_names: Vec = vec![]; for i in 0..channels { let port = client - .register_port(&format!("out_{}", i), jack::AudioOut::default()) + .register_port(&format!("out_{i}"), jack::AudioOut::default()) .context(format!("Failed to register output port {i}"))?; if let Ok(port_name) = port.name() { port_names.push(port_name); diff --git a/src/lib.rs b/src/lib.rs index bebc78946..3eb6408e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -113,7 +113,7 @@ //! # let host = cpal::default_host(); //! # let device = host.default_output_device().unwrap(); //! # let supported_config = device.default_output_config().unwrap(); -//! let err_fn = |err| eprintln!("an error occurred on the output audio stream: {}", err); +//! let err_fn = |err| eprintln!("an error occurred on the output audio stream: {err}"); //! let sample_format = supported_config.sample_format(); //! let config = supported_config.into(); //! let stream = match sample_format { @@ -284,7 +284,7 @@ pub type FrameCount = u32; /// /// // Serialize to string (e.g., for storage in config file) /// let id_string = device_id.to_string(); -/// println!("Device ID: {}", id_string); // e.g., "wasapi:device_identifier" +/// println!("Device ID: {id_string}"); // e.g., "wasapi:device_identifier" /// /// // Deserialize from string /// match DeviceId::from_str(&id_string) { @@ -294,7 +294,7 @@ pub type FrameCount = u32; /// println!("Found device: {:?}", device.id()); /// } /// } -/// Err(e) => eprintln!("Failed to parse device ID: {}", e), +/// Err(e) => eprintln!("Failed to parse device ID: {e}"), /// } /// ``` #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -400,7 +400,7 @@ impl std::str::FromStr for DeviceId { /// // Check supported buffer size range /// match config.buffer_size() { /// SupportedBufferSize::Range { min, max } => { -/// println!("Buffer size range: {} - {}", min, max); +/// println!("Buffer size range: {min} - {max}"); /// // Request a small buffer for low latency /// let mut stream_config = config.config(); /// stream_config.buffer_size = BufferSize::Fixed(256); diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 5b2d5aeb6..d6607a310 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -146,7 +146,7 @@ macro_rules! impl_platform_host { /// /// // Parse host string (may fail if host is not available on this platform) /// if let Ok(host_id) = HostId::from_str(host_string) { - /// println!("Successfully parsed: {}", host_id); + /// println!("Successfully parsed: {host_id}"); /// } /// } /// ```