use serde::{Deserialize, Serialize};
use super::core::{Oscillator, Waveform};
use crate::error::Result;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum SubOctave {
Down1,
Down2,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubOscillator {
osc: Oscillator,
octave: SubOctave,
base_frequency: f32,
pub level: f32,
}
impl SubOscillator {
pub fn new(
waveform: Waveform,
base_frequency: f32,
octave: SubOctave,
sample_rate: f32,
) -> Result<Self> {
let divisor = match octave {
SubOctave::Down1 => 2.0,
SubOctave::Down2 => 4.0,
};
let sub_freq = base_frequency / divisor;
let osc = Oscillator::new(waveform, sub_freq.max(0.1), sample_rate)?;
Ok(Self {
osc,
octave,
base_frequency,
level: 1.0,
})
}
#[inline]
#[must_use]
pub fn next_sample(&mut self) -> f32 {
self.osc.next_sample() * self.level
}
pub fn set_base_frequency(&mut self, freq: f32) -> Result<()> {
let divisor = match self.octave {
SubOctave::Down1 => 2.0,
SubOctave::Down2 => 4.0,
};
self.osc.set_frequency((freq / divisor).max(0.1))?;
self.base_frequency = freq;
Ok(())
}
pub fn set_octave(&mut self, octave: SubOctave) -> Result<()> {
let divisor = match octave {
SubOctave::Down1 => 2.0,
SubOctave::Down2 => 4.0,
};
self.osc
.set_frequency((self.base_frequency / divisor).max(0.1))?;
self.octave = octave;
Ok(())
}
#[inline]
#[must_use]
pub fn octave(&self) -> SubOctave {
self.octave
}
#[inline]
#[must_use]
pub fn base_frequency(&self) -> f32 {
self.base_frequency
}
#[inline]
pub fn fill_buffer(&mut self, buffer: &mut [f32]) {
for sample in buffer.iter_mut() {
*sample = self.next_sample();
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sub_oscillator() {
let mut sub =
SubOscillator::new(Waveform::Square, 440.0, SubOctave::Down1, 44100.0).unwrap();
let mut buf = [0.0f32; 1024];
sub.fill_buffer(&mut buf);
assert!(buf.iter().all(|s| s.is_finite()));
assert!(buf.iter().any(|&s| s != 0.0));
}
#[test]
fn test_sub_oscillator_octave() {
let sub1 = SubOscillator::new(Waveform::Sine, 440.0, SubOctave::Down1, 44100.0).unwrap();
let sub2 = SubOscillator::new(Waveform::Sine, 440.0, SubOctave::Down2, 44100.0).unwrap();
assert!((sub1.osc.frequency() - 220.0).abs() < 0.01);
assert!((sub2.osc.frequency() - 110.0).abs() < 0.01);
}
#[test]
fn test_sub_oscillator_serde() {
let sub = SubOscillator::new(Waveform::Square, 440.0, SubOctave::Down2, 44100.0).unwrap();
let json = serde_json::to_string(&sub).unwrap();
let back: SubOscillator = serde_json::from_str(&json).unwrap();
assert_eq!(sub.octave(), back.octave());
}
}