use crate::AudioEffect;
#[derive(Debug, Clone)]
pub struct AutoTuneConfig {
pub correction: f32,
pub scale: Scale,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Scale {
Chromatic,
Major,
Minor,
}
impl Default for AutoTuneConfig {
fn default() -> Self {
Self {
correction: 0.5,
scale: Scale::Chromatic,
}
}
}
pub struct AutoTune {
config: AutoTuneConfig,
buffer: Vec<f32>,
write_pos: usize,
}
impl AutoTune {
#[must_use]
pub fn new(config: AutoTuneConfig, sample_rate: f32) -> Self {
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
let buffer_size = (sample_rate * 0.05) as usize;
Self {
config,
buffer: vec![0.0; buffer_size],
write_pos: 0,
}
}
pub fn set_correction(&mut self, correction: f32) {
self.config.correction = correction.clamp(0.0, 1.0);
}
#[allow(dead_code, clippy::unused_self)]
fn find_nearest_note(&self, frequency: f32) -> f32 {
frequency
}
}
impl AudioEffect for AutoTune {
fn process_sample(&mut self, input: f32) -> f32 {
self.buffer[self.write_pos] = input;
self.write_pos = (self.write_pos + 1) % self.buffer.len();
input * (1.0 - self.config.correction * 0.1)
}
fn reset(&mut self) {
self.buffer.fill(0.0);
self.write_pos = 0;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_autotune() {
let config = AutoTuneConfig::default();
let mut autotune = AutoTune::new(config, 48000.0);
let output = autotune.process_sample(0.5);
assert!(output.is_finite());
}
}