use crate::{
SampleRate,
timing::BpMea,
unit::{GroupIdx, GroupSamples, MAX_CH_LEN},
};
#[derive(Debug, PartialEq, Eq)]
pub enum DelayUnit {
Beat = 0,
Meas,
Second,
}
#[derive(Debug)]
pub struct Delay {
pub unit: DelayUnit,
pub group: GroupIdx,
pub rate: u8,
pub freq: f32,
pub(crate) offset: usize,
pub(crate) bufs: [Vec<i32>; MAX_CH_LEN],
}
impl Default for Delay {
fn default() -> Self {
Self {
unit: DelayUnit::Beat,
group: GroupIdx(0),
rate: Default::default(),
freq: Default::default(),
offset: Default::default(),
bufs: Default::default(),
}
}
}
enum BufLenCalcError {
TooLarge,
ZeroFreq,
}
const MAX_BUF_LEN: usize = 16_777_216;
impl Delay {
#[must_use]
pub const fn buf_len(&self) -> usize {
self.bufs[0].len()
}
pub fn rebuild(&mut self, bp_mea: BpMea, beat_tempo: f32, sps: SampleRate) {
self.offset = 0;
match self.calc_buf_len(bp_mea, beat_tempo, sps) {
Ok(buf_len) => {
for buf in &mut self.bufs {
*buf = vec![0; buf_len];
}
}
Err(BufLenCalcError::TooLarge) => {
eprintln!("Resulting buffer for delay would be too large.");
}
Err(BufLenCalcError::ZeroFreq) => {
eprintln!("Can't calc buffer size because frequency is zero.");
}
}
}
#[expect(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
fn calc_buf_len(
&self,
bp_mea: BpMea,
beat_tempo: f32,
sps: SampleRate,
) -> Result<usize, BufLenCalcError> {
if self.freq == 0.0 {
return Err(BufLenCalcError::ZeroFreq);
}
let size = match self.unit {
DelayUnit::Beat => (f32::from(sps) * 60. / beat_tempo / self.freq) as usize,
DelayUnit::Meas => {
(f32::from(sps) * 60. * f32::from(bp_mea) / beat_tempo / self.freq) as usize
}
DelayUnit::Second => (f32::from(sps) / self.freq) as usize,
};
if size > MAX_BUF_LEN {
Err(BufLenCalcError::TooLarge)
} else {
Ok(size)
}
}
pub(crate) fn tone_supple(&mut self, ch: u8, group_smps: &mut GroupSamples) {
let Some(buf_sample) = self.bufs[ch as usize].get(self.offset) else {
eprintln!("buf sample offset overflow");
self.offset = 0;
return;
};
group_smps[self.group.usize()] += buf_sample * i32::from(self.rate) / 100;
self.bufs[ch as usize][self.offset] = group_smps[self.group.usize()];
}
pub(crate) const fn tone_increment(&mut self) {
self.offset += 1;
if self.offset >= self.bufs[0].len() {
self.offset = 0;
}
}
}