nooise 1.0.2

Fluid focus music for the terminal
struct Comb {
    buffer: Vec<f32>,
    index: usize,
    feedback: f32,
    filter_store: f32,
    damp1: f32,
    damp2: f32,
}

impl Comb {
    fn new(size: usize, feedback: f32, damp: f32) -> Self {
        Self {
            buffer: vec![0.0; size.max(1)],
            index: 0,
            feedback,
            filter_store: 0.0,
            damp1: damp,
            damp2: 1.0 - damp,
        }
    }

    fn process(&mut self, input: f32) -> f32 {
        let output = self.buffer[self.index];
        self.filter_store = output * self.damp2 + self.filter_store * self.damp1;
        self.buffer[self.index] = input + self.filter_store * self.feedback;
        self.index = (self.index + 1) % self.buffer.len();
        output
    }
}

struct AllPass {
    buffer: Vec<f32>,
    index: usize,
    feedback: f32,
}

impl AllPass {
    fn new(size: usize, feedback: f32) -> Self {
        Self {
            buffer: vec![0.0; size.max(1)],
            index: 0,
            feedback,
        }
    }

    fn process(&mut self, input: f32) -> f32 {
        let buffered = self.buffer[self.index];
        let output = -input + buffered;
        self.buffer[self.index] = input + buffered * self.feedback;
        self.index = (self.index + 1) % self.buffer.len();
        output
    }
}

pub(crate) struct Freeverb {
    combs_left: Vec<Comb>,
    combs_right: Vec<Comb>,
    allpasses_left: Vec<AllPass>,
    allpasses_right: Vec<AllPass>,
    wet: f32,
}

impl Freeverb {
    pub(crate) fn new(sample_rate: f32, room_size: f32, damp: f32, wet: f32) -> Self {
        let scale = sample_rate / 44_100.0;
        let comb_tunings = [1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617];
        let allpass_tunings = [556, 441, 341, 225];
        let feedback = 0.28 + room_size.clamp(0.0, 1.0) * 0.68;
        let damp = damp.clamp(0.0, 1.0) * 0.4;

        let combs_left = comb_tunings
            .iter()
            .map(|size| Comb::new((*size as f32 * scale) as usize, feedback, damp))
            .collect();
        let combs_right = comb_tunings
            .iter()
            .map(|size| Comb::new(((*size + 23) as f32 * scale) as usize, feedback, damp))
            .collect();
        let allpasses_left = allpass_tunings
            .iter()
            .map(|size| AllPass::new((*size as f32 * scale) as usize, 0.5))
            .collect();
        let allpasses_right = allpass_tunings
            .iter()
            .map(|size| AllPass::new(((*size + 23) as f32 * scale) as usize, 0.5))
            .collect();

        Self {
            combs_left,
            combs_right,
            allpasses_left,
            allpasses_right,
            wet: wet.clamp(0.0, 1.0),
        }
    }

    pub(crate) fn process(&mut self, input_left: f32, input_right: f32) -> (f32, f32) {
        let input = (input_left + input_right) * 0.5;
        let mut left = self
            .combs_left
            .iter_mut()
            .map(|comb| comb.process(input))
            .sum::<f32>();
        let mut right = self
            .combs_right
            .iter_mut()
            .map(|comb| comb.process(input))
            .sum::<f32>();

        for allpass in &mut self.allpasses_left {
            left = allpass.process(left);
        }
        for allpass in &mut self.allpasses_right {
            right = allpass.process(right);
        }

        (left * self.wet * 0.18, right * self.wet * 0.18)
    }
}