use std::time::Duration;
pub struct Fade {
values: Vec<f32>,
}
impl Fade {
pub fn new(length: Duration, sample_rate: usize) -> Self {
let length_samples = (sample_rate as f64 * length.as_secs_f64()).ceil() as usize;
let values = (0..length_samples)
.map(|position| {
let t = 2.0 * position as f64 / length_samples as f64 - 1.0;
let value = 0.5 + 0.5 * (t * std::f64::consts::FRAC_PI_2).sin();
value as f32
})
.collect();
Self { values }
}
#[cfg(test)]
pub fn bypass() -> Self {
Self { values: Vec::new() }
}
pub fn len(&self) -> usize {
self.values.len()
}
pub fn value(&self, position: usize) -> f32 {
match self.values.get(position) {
Some(value) => *value,
None => 1.0,
}
}
pub fn fade_in_value(&self, position: usize) -> f32 {
self.value(position)
}
pub fn fade_out_value(&self, position: usize) -> f32 {
self.value(self.len() - position)
}
}
#[cfg(test)]
mod tests {
use approx::assert_relative_eq;
use super::*;
#[test]
fn starts_and_end() {
let fade = Fade::new(Duration::from_millis(100), 44100);
let length = fade.len();
assert_relative_eq!(fade.value(0), 0.0);
assert_relative_eq!(fade.value(length / 2), 0.5);
assert_relative_eq!(fade.value(length - 1), 1.0);
}
#[test]
fn correct_length() {
let fade = Fade::new(Duration::from_secs(1), 44100);
assert_eq!(fade.len(), 44100);
}
}