use pitch_detection::detector::yin::YINDetector; use pitch_detection::detector::PitchDetector; pub fn generate_pitch_detector(size: usize) -> impl PitchDetector { let padding = size / 2; YINDetector::new(size, padding) } /// Returns an option with (Frequency, Clarity) pub fn pitch_detect( detector: &mut dyn PitchDetector, signal: &[f32], sample_rate: u32, ) -> Option<(f32, f32)> { const POWER_THRESHOLD: f32 = 0.15; const CLARITY_THRESHOLD: f32 = 0.5; let pitch = detector.get_pitch( &signal, sample_rate as usize, POWER_THRESHOLD, CLARITY_THRESHOLD, ); pitch.map(|a| (a.frequency, a.clarity)) } pub fn generate_vocoder(sample_rate: u32) -> PhaseVocoder { PhaseVocoder::new(1, sample_rate as f64, 256, 4) } // From https://github.com/nwoeanhinnogaehr/pvoc-plugins/blob/master/src/plugins/pitchshifter.rs use pvoc::{Bin, PhaseVocoder}; pub fn pitch_shift( pvoc: &mut PhaseVocoder, input: &[f32], shift: f32, ) -> [f32; LEN] { let shift = shift as f64; let mut output = [0.0; LEN]; pvoc.process( &[&input], &mut [&mut output], |channels: usize, bins: usize, input: &[Vec], output: &mut [Vec]| { for i in 0..channels { for j in 0..bins / 2 { let index = ((j as f64) * shift) as usize; if index < bins / 2 { output[i][index].freq = input[i][j].freq * shift; output[i][index].amp += input[i][j].amp; } } } }, ); output } /// Returns closest midi note to `pitch` pub fn pitch_to_midi_note(pitch: f32) -> u8 { // With the frequency, check the closest note let note = 69 + (12. * (pitch / 440.).log2()).round() as i16; note.clamp(0, 127) as u8 } /// Returns a midi note's pitch pub fn midi_note_to_pitch(note: u8) -> f32 { 440.0f32 * 2.0f32.powf((note as f32 - 69.) / 12.) } /// Returns the closest note frequency pub fn closest_note_freq(freq: f32) -> f32 { midi_note_to_pitch(pitch_to_midi_note(freq)) }