use aether_core::{node::DspNode, param::ParamBlock, state::StateBlob, BUFFER_SIZE, MAX_INPUTS};
use std::f32::consts::TAU;
#[derive(Clone, Copy)]
struct OscState {
phase: f32,
}
pub struct Oscillator {
phase: f32,
}
impl Oscillator {
pub fn new() -> Self {
Self { phase: 0.0 }
}
#[inline(always)]
fn generate_sample(&mut self, freq: f32, amp: f32, waveform: f32, sr: f32) -> f32 {
let phase_inc = freq / sr;
let sample = match waveform as u32 {
0 => (self.phase * TAU).sin(),
1 => 2.0 * self.phase - 1.0, 2 => {
if self.phase < 0.5 {
1.0
} else {
-1.0
}
} _ => {
if self.phase < 0.5 {
4.0 * self.phase - 1.0
} else {
3.0 - 4.0 * self.phase
}
}
};
self.phase = (self.phase + phase_inc).fract();
sample * amp
}
}
impl Default for Oscillator {
fn default() -> Self {
Self::new()
}
}
impl DspNode for Oscillator {
fn process(
&mut self,
_inputs: &[Option<&[f32; BUFFER_SIZE]>; MAX_INPUTS],
output: &mut [f32; BUFFER_SIZE],
params: &mut ParamBlock,
sample_rate: f32,
) {
for sample in output.iter_mut() {
let freq = params.get(0).current.max(0.01);
let amp = params.get(1).current.clamp(0.0, 1.0);
let wave = params.get(2).current;
*sample = self.generate_sample(freq, amp, wave, sample_rate);
params.tick_all();
}
}
fn capture_state(&self) -> StateBlob {
StateBlob::from_value(&OscState { phase: self.phase })
}
fn restore_state(&mut self, state: StateBlob) {
let s: OscState = state.to_value();
self.phase = s.phase;
}
fn type_name(&self) -> &'static str {
"Oscillator"
}
}