use crate::building_blocks::{
Modulator, SampleBuffer, StereoSource, SynthParameterLabel, SynthParameterValue, SynthState,
interpolation::*,
};
#[derive(Clone)]
pub struct StereoSampler<const BUFSIZE: usize> {
playback_rate: f32,
amp: f32,
phase: usize,
frac_phase: f64,
bufnum: usize,
buflen: usize,
buflen_plus_one: usize,
buflen_plus_one_f64: f64,
frac_phase_increment: f64,
state: SynthState,
repeat: bool,
rate_mod: Option<Modulator<BUFSIZE>>,
amp_mod: Option<Modulator<BUFSIZE>>,
}
impl<const BUFSIZE: usize> StereoSampler<BUFSIZE> {
pub fn with_bufnum_len(bufnum: usize, buflen: usize, repeat: bool) -> StereoSampler<BUFSIZE> {
StereoSampler {
phase: 2, frac_phase: 2.0,
bufnum,
buflen, buflen_plus_one: buflen + 1,
buflen_plus_one_f64: (buflen + 1) as f64,
playback_rate: 1.0,
frac_phase_increment: 1.0,
state: SynthState::Fresh,
amp: 1.0,
repeat,
rate_mod: None,
amp_mod: None,
}
}
fn get_next_block_plain(
&mut self,
start_sample: usize,
sample_buffers: &[SampleBuffer],
) -> [[f32; BUFSIZE]; 2] {
let mut out_buf: [[f32; BUFSIZE]; 2] = [[0.0; BUFSIZE]; 2];
if let SampleBuffer::Stereo(left, right) = &sample_buffers[self.bufnum] {
for s in start_sample..BUFSIZE {
out_buf[0][s] = left[self.phase] * self.amp;
out_buf[1][s] = right[self.phase] * self.amp;
if self.phase < self.buflen_plus_one {
self.phase += 1;
} else if self.repeat {
self.frac_phase = 2.0;
self.phase = 2;
} else {
self.finish();
}
}
}
out_buf
}
fn get_next_block_plain_reverse(
&mut self,
start_sample: usize,
sample_buffers: &[SampleBuffer],
) -> [[f32; BUFSIZE]; 2] {
let mut out_buf: [[f32; BUFSIZE]; 2] = [[0.0; BUFSIZE]; 2];
if let SampleBuffer::Stereo(left, right) = &sample_buffers[self.bufnum] {
for s in start_sample..BUFSIZE {
out_buf[0][s] = left[self.phase] * self.amp;
out_buf[1][s] = right[self.phase] * self.amp;
if self.phase > 2 {
self.phase -= 1;
} else if self.repeat {
self.frac_phase = self.buflen_plus_one_f64;
self.phase = self.buflen_plus_one;
} else {
self.finish();
}
}
}
out_buf
}
fn get_next_block_interpolated(
&mut self,
start_sample: usize,
sample_buffers: &[SampleBuffer],
) -> [[f32; BUFSIZE]; 2] {
let mut out_buf: [[f32; BUFSIZE]; 2] = [[0.0; BUFSIZE]; 2];
if let SampleBuffer::Stereo(left, right) = &sample_buffers[self.bufnum] {
for s in start_sample..BUFSIZE {
let idx = self.frac_phase.floor();
let frac = self.frac_phase - idx;
let idx_u = idx as usize;
out_buf[0][s] = interpolate(
frac as f32,
left[idx_u - 1],
left[idx_u],
left[idx_u + 1],
left[idx_u + 2],
self.amp,
);
out_buf[1][s] = interpolate(
frac as f32,
right[idx_u - 1],
right[idx_u],
right[idx_u + 1],
right[idx_u + 2],
self.amp,
);
self.frac_phase += self.frac_phase_increment;
if self.repeat && self.frac_phase.floor() > self.buflen_plus_one_f64 {
self.frac_phase = 2.0;
self.phase = 2;
} else {
self.finish();
}
}
}
out_buf
}
fn get_next_block_interpolated_reverse(
&mut self,
start_sample: usize,
sample_buffers: &[SampleBuffer],
) -> [[f32; BUFSIZE]; 2] {
let mut out_buf: [[f32; BUFSIZE]; 2] = [[0.0; BUFSIZE]; 2];
if let SampleBuffer::Stereo(left, right) = &sample_buffers[self.bufnum] {
for s in start_sample..BUFSIZE {
let idx = self.frac_phase.ceil();
let frac = idx - self.frac_phase;
let idx_u = idx as usize;
out_buf[0][s] = interpolate(
frac as f32,
left[idx_u + 1],
left[idx_u],
left[idx_u - 1],
left[idx_u - 2],
self.amp,
);
out_buf[1][s] = interpolate(
frac as f32,
right[idx_u + 1],
right[idx_u],
right[idx_u - 1],
right[idx_u - 2],
self.amp,
);
self.frac_phase += self.frac_phase_increment;
if self.repeat && self.frac_phase.ceil() < 2.0 {
self.frac_phase = self.buflen_plus_one_f64;
self.phase = self.buflen_plus_one;
} else {
self.finish();
}
}
}
out_buf
}
fn get_next_block_modulated(
&mut self,
start_sample: usize,
sample_buffers: &[SampleBuffer],
) -> [[f32; BUFSIZE]; 2] {
let mut out_buf: [[f32; BUFSIZE]; 2] = [[0.0; BUFSIZE]; 2];
if let SampleBuffer::Stereo(left, right) = &sample_buffers[self.bufnum] {
let rate_buf = if let Some(m) = self.rate_mod.as_mut() {
m.process(self.playback_rate, start_sample, sample_buffers)
} else {
[self.playback_rate; BUFSIZE]
};
let amp_buf = if let Some(m) = self.amp_mod.as_mut() {
m.process(self.amp, start_sample, sample_buffers)
} else {
[self.amp; BUFSIZE]
};
for sample_idx in start_sample..BUFSIZE {
self.frac_phase_increment = rate_buf[sample_idx] as f64;
if self.frac_phase_increment.is_sign_positive() {
let idx = self.frac_phase.floor();
let frac = self.frac_phase - idx;
let idx_u = idx as usize;
out_buf[0][sample_idx] = interpolate(
frac as f32,
left[idx_u - 1],
left[idx_u],
left[idx_u + 1],
left[idx_u + 2],
amp_buf[sample_idx],
);
out_buf[1][sample_idx] = interpolate(
frac as f32,
right[idx_u - 1],
right[idx_u],
right[idx_u + 1],
right[idx_u + 2],
amp_buf[sample_idx],
);
} else {
let idx = self.frac_phase.ceil();
let frac = idx - self.frac_phase;
let idx_u = idx as usize;
out_buf[0][sample_idx] = interpolate(
frac as f32,
left[idx_u + 1],
left[idx_u],
left[idx_u - 1],
left[idx_u - 2],
amp_buf[sample_idx],
);
out_buf[1][sample_idx] = interpolate(
frac as f32,
right[idx_u + 1],
right[idx_u],
right[idx_u - 1],
right[idx_u - 2],
amp_buf[sample_idx],
);
}
self.frac_phase += self.frac_phase_increment;
if self.repeat && self.frac_phase.floor() > self.buflen_plus_one_f64 {
self.frac_phase = 2.0;
self.phase = 2;
} else if self.repeat && self.frac_phase.ceil() < 2.0 {
self.frac_phase = self.buflen_plus_one_f64;
self.phase = self.buflen_plus_one;
} else {
self.finish();
}
}
}
out_buf
}
}
impl<const BUFSIZE: usize> StereoSource<BUFSIZE> for StereoSampler<BUFSIZE> {
fn reset(&mut self) {}
fn set_modulator(
&mut self,
par: SynthParameterLabel,
init: f32,
modulator: Modulator<BUFSIZE>,
) {
match par {
SynthParameterLabel::PlaybackRate => {
self.playback_rate = init;
self.rate_mod = Some(modulator);
}
SynthParameterLabel::OscillatorAmplitude => {
self.amp = init;
self.amp_mod = Some(modulator);
}
_ => {}
}
}
fn set_parameter(&mut self, par: SynthParameterLabel, val: &SynthParameterValue) {
match par {
SynthParameterLabel::PlaybackStart => {
if let SynthParameterValue::ScalarF32(value_ref) = val {
let value = *value_ref;
let mut value_clamped = value;
if value == 1.0 {
value_clamped = 0.0
} else if value > 1.0 {
value_clamped = value - ((value as usize) as f32);
} else if value < 0.0 {
let v_abs = value.abs();
let v_abs_clamped = v_abs - ((v_abs as usize) as f32);
value_clamped = 1.0 - v_abs_clamped;
}
let offset = (self.buflen as f32 * value_clamped) as usize;
self.phase = offset + 2; self.frac_phase = self.phase as f64;
}
}
SynthParameterLabel::PlaybackRate => {
if let SynthParameterValue::ScalarF32(value) = val {
self.playback_rate = *value;
self.frac_phase_increment = *value as f64;
}
}
SynthParameterLabel::OscillatorAmplitude => {
if let SynthParameterValue::ScalarF32(value) = val {
self.amp = *value;
}
}
_ => (),
};
}
fn finish(&mut self) {
self.state = SynthState::Finished;
}
fn is_finished(&self) -> bool {
matches!(self.state, SynthState::Finished)
}
fn get_next_block(
&mut self,
start_sample: usize,
sample_buffers: &[SampleBuffer],
) -> [[f32; BUFSIZE]; 2] {
if self.rate_mod.is_some() || self.amp_mod.is_some() {
self.get_next_block_modulated(start_sample, sample_buffers)
} else if self.playback_rate == 1.0 {
self.get_next_block_plain(start_sample, sample_buffers)
} else if self.playback_rate == -1.0 {
self.get_next_block_plain_reverse(start_sample, sample_buffers)
} else if self.playback_rate.is_sign_negative() {
self.get_next_block_interpolated_reverse(start_sample, sample_buffers)
} else {
self.get_next_block_interpolated(start_sample, sample_buffers)
}
}
}