#![feature(iter_collect_into)] use std::{sync::mpsc, thread::sleep, time::Duration}; use anyhow::{Context, Ok, Result}; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use pitch_detection::{detector::{mcleod::McLeodDetector, PitchDetector}, utils}; use rust_music_theory::note::{Note, NoteLetter, Pitch, Tuning}; fn main() -> Result<()> { // assumes pulseaudio system with f32 samples and 2204 sample packets dbg!(cpal::available_hosts()); let host = cpal::default_host(); let device = host.devices().unwrap().find(|d|d.name().unwrap() == "pulse").context("no pulse")?; let config = device.default_input_config()?; dbg!(config.sample_format()); let rate = config.sample_rate(); let (sender, notes) = mpsc::channel(); const POWER_THRESHOLD: f32 = 5.0; const CLARITY_THRESHOLD: f32 = 0.7; const PACKET_LEN: usize = 2204; let stream = device.build_input_stream(&config.into(), move | data: &[f32], _: &_| { assert!(data.len() >= PACKET_LEN); let data = &data[..PACKET_LEN]; // reinitialized every packet as it is not thread safe let mut detctor = McLeodDetector::new(PACKET_LEN, PACKET_LEN/2); let vol = utils::buffer::square_sum(data); sender.send((detctor.get_pitch(data, rate.0 as usize, POWER_THRESHOLD, CLARITY_THRESHOLD),vol)).unwrap(); }, move |err| {eprintln!("{err}")} , Some(Duration::from_secs(1)))?; stream.play()?; for (note,vol) in notes { if let Some(note) = note { //dbg!(note.frequency); dbg!(note.clarity); dbg!(vol); let note = Note::from_freq(note.frequency, Tuning::EqualTemperament); match note.pitch { Pitch { letter: NoteLetter::A, accidental: 0} => { println!("forward"); } Pitch { letter: NoteLetter::A, accidental: 1} => { println!("backward"); } Pitch { letter: NoteLetter::C, accidental: 0} => { println!("right"); } Pitch { letter: NoteLetter::C, accidental: 1} => { println!("left"); } Pitch { letter: NoteLetter::G, accidental: 0} => { println!("fire"); } pitch => { dbg!(pitch); } } } } drop(stream); Ok(()) }