78 lines
2.1 KiB
Rust
78 lines
2.1 KiB
Rust
|
use pitch_detection::detector::yin::YINDetector;
|
||
|
use pitch_detection::detector::PitchDetector;
|
||
|
|
||
|
pub fn generate_pitch_detector(size: usize) -> impl PitchDetector<f32> {
|
||
|
let padding = size / 2;
|
||
|
|
||
|
YINDetector::new(size, padding)
|
||
|
}
|
||
|
|
||
|
/// Returns an option with (Frequency, Clarity)
|
||
|
pub fn pitch_detect(
|
||
|
detector: &mut dyn PitchDetector<f32>,
|
||
|
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<const LEN: usize>(
|
||
|
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<Bin>], output: &mut [Vec<Bin>]| {
|
||
|
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))
|
||
|
}
|