use dev_helpers::rtrb; use dev_helpers::{AudioHost, AudioProcessor}; use microdsp::sfnov::{HardKneeCompression, SpectralFluxNoveltyDetector}; use std::thread; use std::time::Duration; enum DetectorMessage { NoveltyValue(f32), } const WINDOW_SIZE: usize = 1024; type DetectorType = SpectralFluxNoveltyDetector; struct NoveltyDetectorProcessor { detector: DetectorType, } impl NoveltyDetectorProcessor { fn new() -> Self { NoveltyDetectorProcessor { detector: DetectorType::new(WINDOW_SIZE), } } } impl AudioProcessor for NoveltyDetectorProcessor { fn process( &mut self, in_buffer: &[f32], _: &mut [f32], _: usize, to_main_thread: &mut rtrb::Producer, _: &mut rtrb::Consumer, ) -> bool { self.detector.process(in_buffer, |novelty| { let _ = to_main_thread.push(DetectorMessage::NoveltyValue(novelty.novelty())); }); true } } struct PeakDetector { threshold: f32, is_armed: bool, } impl PeakDetector { fn new(threshold: f32) -> Self { PeakDetector { threshold, is_armed: true, } } fn process(&mut self, input: f32) -> bool { if input > self.threshold && self.is_armed { self.is_armed = false; return true; } else if input < self.threshold { self.is_armed = true; }; false } } fn main() { let sample_rate = 44100.0; let mut audio_host = AudioHost::new(sample_rate, NoveltyDetectorProcessor::new()); println!("Listening for sounds..."); let poll_interval_ms = 30; let mut novelty_peak_detector = PeakDetector::new(0.4); loop { thread::sleep(Duration::from_millis(poll_interval_ms)); loop { match audio_host.from_audio_thread.pop() { Ok(message) => match message { DetectorMessage::NoveltyValue(value) => { if novelty_peak_detector.process(value) { println!("Onset detected (novelty {value})") } } }, _ => {} } } } }