diff --git a/Cargo.toml b/Cargo.toml index 8508b2b..91091c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,3 +45,6 @@ default_trait_access = "allow" # The error types returned should be self-explanatory. missing_errors_doc = "allow" + +# Inevitable for short names. +similar_names = "allow" diff --git a/src/filter.rs b/src/filter.rs index 6d473b2..9f19272 100644 --- a/src/filter.rs +++ b/src/filter.rs @@ -32,9 +32,9 @@ const HIGH_LP_FILTER_HZ: f32 = 1600.0; /// Overlapping highs with mids. const HIGH_HP_FILTER_HZ: f32 = HIGH_LP_FILTER_HZ / 2.0; // Overlap with mid -const MIN_SAMPLES_PER_BIN: u32 = 64; - // 3-band crossover using 4th-order Linkwitz-Riley (LR4) filters (2 cascaded 2nd-order Butterworth) +#[derive(Debug)] +#[allow(clippy::struct_field_names)] struct FilterBank { low_lp_lr4: [DirectForm2Transposed; 2], low_hp_lr4: [DirectForm2Transposed; 2], @@ -106,13 +106,14 @@ impl FilterBank { } } + #[allow(clippy::unused_self)] // TODO fn shape_input_signal(&mut self, sample: f32) -> f32 { // TODO: Apply filtering to shape the input signal according to the // ISO 226:2003 equal-loudness-level contour at 40 phons (A-weighting). sample } - pub fn run(&mut self, sample: f32) -> FilteredSample { + fn run(&mut self, sample: f32) -> FilteredSample { let all = self.shape_input_signal(sample); let Self { low_lp_lr4, @@ -143,8 +144,8 @@ impl FilterBank { #[derive(Debug, Default)] struct WaveformBinAccumulator { - pub rms_sum: f64, - pub peak: f32, + rms_sum: f64, + peak: f32, } impl WaveformBinAccumulator { @@ -157,6 +158,7 @@ impl WaveformBinAccumulator { fn finish(self, rms_div: f64) -> WaveformBin { debug_assert!(rms_div > 0.0); let Self { rms_sum, peak } = self; + #[allow(clippy::cast_possible_truncation)] let ratio = (1.0 + (rms_sum / rms_div).sqrt()).log2() as f32; WaveformBin { ratio: WaveformVal::from_f32(ratio), @@ -200,7 +202,7 @@ impl FilteredWaveformBinAccumulator { if sample_count == 0 { return None; } - let rms_div = sample_count as f64; + let rms_div = f64::from(sample_count); let all = all.finish(rms_div); let low = low.finish(rms_div); let mid = mid.finish(rms_div); @@ -214,6 +216,7 @@ impl FilteredWaveformBinAccumulator { } } +#[derive(Debug)] pub struct WaveformFilter { samples_per_bin: u32, filter_bank: FilterBank, @@ -230,7 +233,8 @@ impl Default for WaveformFilter { } impl WaveformFilter { - fn new(sample_rate: Hertz, samples_per_bin: u32) -> Self { + #[must_use] + pub fn new(sample_rate: Hertz, samples_per_bin: u32) -> Self { Self { samples_per_bin, filter_bank: FilterBank::new(sample_rate), @@ -238,11 +242,11 @@ impl WaveformFilter { } } - fn finish_bin(&mut self) -> Option { + pub fn finish_bin(&mut self) -> Option { std::mem::take(&mut self.filtered_accumulator).finish() } - fn add_sample(&mut self, sample: f32) -> Option { + pub fn add_sample(&mut self, sample: f32) -> Option { let next_bin = if self.filtered_accumulator.sample_count >= self.samples_per_bin { self.finish_bin() } else { @@ -253,21 +257,8 @@ impl WaveformFilter { next_bin } - fn finish(mut self) -> Option { + #[must_use] + pub fn finish(mut self) -> Option { self.finish_bin() } } - -pub type WaveformFiltered = [FilteredWaveformBin]; - -pub struct WaveformAnalyzer<'a> { - file_path: &'a Path, - file_type: Option<&'a Mime>, - bins_per_sec: NonZeroU8, - filter: WaveformFilter, - waveform: FilteredWaveform, -} - -fn samples_per_bin(bins_per_sec: NonZeroU8, sample_rate: Hertz) -> u32 { - (sample_rate.hz() / f32::from(bins_per_sec.get())).floor() as u32 -} diff --git a/src/lib.rs b/src/lib.rs index bc6db7b..681d1c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,9 @@ // SPDX-License-Identifier: MPL-2.0 #![allow(rustdoc::invalid_rust_codeblocks)] +// Inevitable for short names. +// TODO: Remove this allowance when option in Cargo.toml works as expected. +#![allow(clippy::similar_names)] #![doc = include_str!("../README.md")] mod filter; diff --git a/src/waveform.rs b/src/waveform.rs index 1932daf..bf75528 100644 --- a/src/waveform.rs +++ b/src/waveform.rs @@ -15,13 +15,17 @@ impl WaveformVal { let mapped = (val * (f32::from(Self::MAX_VAL) + 1.0)).min(f32::from(Self::MAX_VAL)); debug_assert!(mapped >= f32::from(u8::MIN)); debug_assert!(mapped <= f32::from(u8::MAX)); + #[allow(clippy::cast_possible_truncation)] + #[allow(clippy::cast_sign_loss)] Self(mapped as u8) } + #[must_use] pub fn to_f32(self) -> f32 { f32::from(self.0) / f32::from(Self::MAX_VAL) } + #[must_use] pub const fn is_zero(self) -> bool { self.0 == 0 } @@ -44,7 +48,7 @@ pub struct WaveformBin { pub peak: WaveformVal, } -#[derive(Debug, Clone, Copy, Default)] +#[derive(Debug, Clone, Default)] pub struct FilteredWaveformBin { pub all: WaveformBin, pub low: WaveformBin, @@ -57,6 +61,7 @@ pub type FilteredWaveform = Vec; impl FilteredWaveformBin { /// + #[must_use] pub fn ratio_flatness(&self) -> f32 { let Self { low, mid, high, .. } = self; let low = 1.0 + low.ratio.to_f32(); // [1, 256] @@ -87,6 +92,7 @@ impl FilteredWaveformBin { Srgb::new(red, green, blue) } + #[must_use] pub fn rgb_color(&self, flatness_to_saturation: f32) -> (f32, f32, f32) { let mut rgb = self.ratio_spectral_rgb(); debug_assert!(flatness_to_saturation >= 0.0); @@ -100,6 +106,7 @@ impl FilteredWaveformBin { (rgb.red, rgb.green, rgb.blue) } + #[must_use] pub fn amplitude(&self) -> f32 { let all = self.all.ratio.to_f32(); (all * std::f32::consts::SQRT_2).min(1.0)