use std::{error::Error, path::PathBuf};
use adaptif::Algorithm;
use adaptif::filters::FilterBase;
use adaptif::types::NoiseWindowView;
use adaptif::types::{BlockSize, WindowSize};
use adaptif::types::{InputSignal, NoiseReference};
use rand::{self, RngExt as _, SeedableRng as _, rngs::StdRng};
use rand_distr::StandardNormal;
pub struct MyAlgorithm {
pub alpha: f64,
pub window_size: WindowSize,
}
impl Algorithm<f64> for MyAlgorithm {
fn update_step(&mut self, weights: &mut [f64], error: f64, noise_window: NoiseWindowView<f64>) {
for (w, x) in weights.iter_mut().zip(noise_window.iter()) {
*w += self.alpha * error * x;
}
}
fn window_size(&self) -> WindowSize {
self.window_size
}
}
fn main() -> Result<(), Box<dyn Error>> {
let algorithm_cfg = MyAlgorithm {
alpha: 1.0,
window_size: WindowSize::new(16)?,
};
let block_size = BlockSize::new(1)?;
let mut filter = FilterBase::new(algorithm_cfg, block_size);
let (noisy_signal, noise) = load_signals()?;
let input_signal = InputSignal::new(noisy_signal)?;
let noise_ref = NoiseReference::new(noise)?;
let _output = filter.adapt(&input_signal, &noise_ref)?;
Ok(())
}
#[allow(clippy::missing_errors_doc, reason = "Example")]
pub fn load_signals() -> Result<(Vec<f64>, Vec<f64>), Box<dyn Error>> {
let clean_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("integration")
.join("fixtures");
let wav_path = std::fs::read_dir(clean_dir)?
.next()
.ok_or("No WAV fixtures")??
.path();
let mut reader = hound::WavReader::open(wav_path)?;
let clean_signal: Vec<f64> = reader
.samples::<i16>()
.map(|s| Ok(f64::from(s?) / f64::from(i16::MAX)))
.collect::<Result<_, hound::Error>>()?;
let mut rng = StdRng::seed_from_u64(42);
let noise: Vec<f64> = std::iter::repeat_with(|| rng.sample(StandardNormal))
.take(clean_signal.len())
.collect();
let noisy_signal: Vec<f64> = clean_signal
.iter()
.zip(&noise)
.map(|(c, n)| c + n)
.collect();
Ok((noisy_signal, noise))
}