// johnmcm.com's replacement for libDF/src/wasm.rs (DeepFilterNet, MIT OR // Apache-2.0). The upstream bindings process one 10 ms frame per call with // the runtime's default thresholds; these // - take the model as bytes from the page (so it is not compiled in), // - use the thresholds of the upstream deep-filter command line tool // (min -15 dB, ERB and DF max 35 dB), whose output keeps speech at its // level; the runtime defaults (-10/30/20) leave it about 5 dB quieter, // - process a whole chunk per call, and // - report the delay (STFT plus model lookahead) to trim from the start. use ndarray::prelude::*; use wasm_bindgen::prelude::*; use crate::tract::*; #[wasm_bindgen] pub struct DeepFilter { m: DfTract, } #[wasm_bindgen] impl DeepFilter { /// A DeepFilterNet runtime for one channel at 48 kHz, from a model .tar.gz. #[wasm_bindgen(constructor)] pub fn new(model_bytes: &[u8], atten_lim_db: f32) -> Result { console_error_panic_hook::set_once(); let r = RuntimeParams::default_with_ch(1) .with_atten_lim(atten_lim_db) .with_thresholds(-15., 35., 35.); let p = DfParams::from_bytes(model_bytes).map_err(|e| JsError::new(&e.to_string()))?; let m = DfTract::new(p, &r).map_err(|e| JsError::new(&e.to_string()))?; Ok(DeepFilter { m }) } /// Samples per frame (480 at 48 kHz). #[wasm_bindgen(getter)] pub fn hop(&self) -> usize { self.m.hop_size } /// Samples the output lags the input by. #[wasm_bindgen(getter)] pub fn delay(&self) -> usize { self.m.fft_size - self.m.hop_size + self.m.lookahead * self.m.hop_size } /// Sample rate the model works at. #[wasm_bindgen(getter)] pub fn sr(&self) -> usize { self.m.sr } /// How much noise may be taken away, in dB; 100 is no limit. pub fn set_atten_lim(&mut self, db: f32) { self.m.set_atten_lim(db) } /// Post-filter strength; 0 turns it off. pub fn set_post_filter_beta(&mut self, beta: f32) { self.m.set_pf_beta(beta) } /// Cleans every whole frame of `input`, in order; state carries over between calls. pub fn process(&mut self, input: &[f32]) -> Result, JsError> { let hop = self.m.hop_size; let n = input.len() / hop; let mut out = vec![0f32; n * hop]; for i in 0..n { let a = ArrayView2::from_shape((1, hop), &input[i * hop..(i + 1) * hop]).unwrap(); let b = ArrayViewMut2::from_shape((1, hop), &mut out[i * hop..(i + 1) * hop]).unwrap(); self.m.process(a, b).map_err(|e| JsError::new(&e.to_string()))?; } Ok(out) } }