use crate::building_blocks::{
Modulator, MonoSource, SampleBuffer, SynthParameterLabel, SynthParameterValue,
};
use std::f32::consts::PI;
#[derive(Clone)]
pub struct NaiveBlitOsc<const BUFSIZE: usize> {
freq: f32,
amp: f32,
num_harm: f32,
m: f32,
phase: f32,
phase_inc: f32,
p: f32,
sr: f32,
freq_mod: Option<Modulator<BUFSIZE>>, }
impl<const BUFSIZE: usize> NaiveBlitOsc<BUFSIZE> {
pub fn new(freq: f32, amp: f32, sr: f32) -> Self {
let p = freq / sr;
NaiveBlitOsc {
freq,
amp,
m: 23.0,
num_harm: 10.0,
phase: 0.0,
phase_inc: PI / p,
p,
sr,
freq_mod: None,
}
}
fn update_harmonics(&mut self) {
let max_harmonics = (0.5 * self.p).floor();
if self.num_harm == 0.0 {
self.m = 2.0 * max_harmonics + 1.0; } else {
self.m = 2.0 * self.num_harm.floor() + 1.0; }
}
fn set_frequency(&mut self, freq: f32) {
self.freq = freq;
self.p = self.sr / freq;
self.phase_inc = PI / self.p;
self.update_harmonics();
}
}
#[inline(always)]
fn sinc_ish_m(phase: f32, m: f32) -> f32 {
let den_f = phase.sin();
if den_f < f32::EPSILON {
1.0 } else {
(phase * m).sin() / (m * den_f)
}
}
impl<const BUFSIZE: usize> MonoSource<BUFSIZE> for NaiveBlitOsc<BUFSIZE> {
fn reset(&mut self) {}
fn set_modulator(
&mut self,
par: SynthParameterLabel,
init: f32,
modulator: Modulator<BUFSIZE>,
) {
if par == SynthParameterLabel::PitchFrequency {
self.freq = init;
self.freq_mod = Some(modulator);
}
}
fn set_parameter(&mut self, par: SynthParameterLabel, value: &SynthParameterValue) {
match par {
SynthParameterLabel::PitchFrequency => {
if let SynthParameterValue::ScalarF32(f) = value {
self.set_frequency(*f);
}
}
SynthParameterLabel::NumHarmonics => {
if let SynthParameterValue::ScalarF32(f) = value {
self.num_harm = *f;
self.update_harmonics();
}
}
SynthParameterLabel::OscillatorAmplitude => {
if let SynthParameterValue::ScalarF32(l) = value {
self.amp = *l;
}
}
_ => (),
};
}
fn finish(&mut self) {}
fn is_finished(&self) -> bool {
false
}
fn get_next_block(
&mut self,
start_sample: usize,
in_buffers: &[SampleBuffer],
) -> [f32; BUFSIZE] {
let mut out_buf: [f32; BUFSIZE] = [0.0; BUFSIZE];
if self.freq_mod.is_some() {
let freq_buf =
self.freq_mod
.as_mut()
.unwrap()
.process(self.amp, start_sample, in_buffers);
for (i, current_sample) in out_buf
.iter_mut()
.take(BUFSIZE)
.skip(start_sample)
.enumerate()
{
self.set_frequency(freq_buf[i]);
*current_sample = sinc_ish_m(self.phase, self.m) * self.amp;
self.phase += self.phase_inc;
if self.phase >= PI {
self.phase -= PI;
}
}
} else {
for current_sample in out_buf.iter_mut().take(BUFSIZE).skip(start_sample) {
*current_sample = sinc_ish_m(self.phase, self.m) * self.amp;
self.phase += self.phase_inc;
if self.phase >= PI {
self.phase -= PI;
}
}
}
out_buf
}
}