use crate::building_blocks::{
EnvelopeSegmentInfo, EnvelopeSegmentType, Modulator, MonoSource, SampleBuffer,
SynthParameterLabel, SynthParameterValue, SynthState,
};
#[derive(Clone, Copy)]
pub struct LinearRamp<const BUFSIZE: usize> {
ramp_samples: usize,
sample_count: usize,
cur_lvl: f32,
to: f32,
from: f32,
inc_dec: f32,
state: SynthState,
}
impl<const BUFSIZE: usize> LinearRamp<BUFSIZE> {
pub fn new(from: f32, to: f32, ramp_time: f32, samplerate: f32) -> Self {
let ramp_samples = (samplerate * ramp_time).round();
LinearRamp {
ramp_samples: ramp_samples as usize,
sample_count: 0,
cur_lvl: from,
to,
from,
inc_dec: (to - from) / ramp_samples,
state: SynthState::Fresh,
}
}
}
impl<const BUFSIZE: usize> MonoSource<BUFSIZE> for LinearRamp<BUFSIZE> {
fn reset(&mut self) {
self.sample_count = 0;
self.cur_lvl = self.from;
}
fn finish(&mut self) {
self.state = SynthState::Finished;
}
fn is_finished(&self) -> bool {
matches!(self.state, SynthState::Finished)
}
fn set_modulator(&mut self, _: SynthParameterLabel, _: f32, _: Modulator<BUFSIZE>) {}
fn set_parameter(&mut self, _: SynthParameterLabel, _: &SynthParameterValue) {}
fn get_next_block(&mut self, start_sample: usize, _: &[SampleBuffer]) -> [f32; BUFSIZE] {
let mut out: [f32; BUFSIZE] = [0.0; BUFSIZE];
for current_sample in out.iter_mut().take(BUFSIZE).skip(start_sample) {
*current_sample = self.cur_lvl;
if self.sample_count < self.ramp_samples {
self.cur_lvl += self.inc_dec;
} else {
self.cur_lvl = self.to;
self.finish();
}
self.sample_count += 1;
}
out
}
}
#[derive(Clone, Copy)]
pub struct LogRamp<const BUFSIZE: usize> {
ramp_samples: usize,
sample_count: usize,
time_inc: f32,
time_count: f32,
curve: f32,
cur_lvl: f32,
mul: f32,
from: f32,
state: SynthState,
}
impl<const BUFSIZE: usize> LogRamp<BUFSIZE> {
pub fn new(from: f32, to: f32, ramp_time: f32, samplerate: f32) -> Self {
let ramp_samples = (samplerate * ramp_time).round();
let time_inc = 1.0 / ramp_samples;
let mul = to - from;
LogRamp {
ramp_samples: ramp_samples as usize,
sample_count: 0,
cur_lvl: 0.0,
time_inc,
curve: -4.5 * mul.signum(),
time_count: 0.0,
mul,
from,
state: SynthState::Fresh,
}
}
}
impl<const BUFSIZE: usize> MonoSource<BUFSIZE> for LogRamp<BUFSIZE> {
fn reset(&mut self) {
self.sample_count = 0;
self.cur_lvl = self.from;
}
fn finish(&mut self) {
self.state = SynthState::Finished;
}
fn is_finished(&self) -> bool {
matches!(self.state, SynthState::Finished)
}
fn set_modulator(&mut self, _: SynthParameterLabel, _: f32, _: Modulator<BUFSIZE>) {}
fn set_parameter(&mut self, _: SynthParameterLabel, _: &SynthParameterValue) {}
fn get_next_block(&mut self, start_sample: usize, _: &[SampleBuffer]) -> [f32; BUFSIZE] {
let mut out: [f32; BUFSIZE] = [0.0; BUFSIZE];
for current_sample in out.iter_mut().take(BUFSIZE).skip(start_sample) {
*current_sample = self.from + self.cur_lvl * self.mul;
self.cur_lvl = if self.sample_count < self.ramp_samples {
((self.curve * self.time_count).exp() - 1.0) / (self.curve.exp() - 1.0)
} else {
self.finish();
1.0
};
self.time_count += self.time_inc;
self.sample_count += 1;
}
out
}
}
#[derive(Clone, Copy)]
pub struct ExpRamp<const BUFSIZE: usize> {
ramp_samples: usize,
sample_count: usize,
time_inc: f32,
time_count: f32,
curve: f32,
cur_lvl: f32,
mul: f32,
from: f32,
state: SynthState,
}
impl<const BUFSIZE: usize> ExpRamp<BUFSIZE> {
pub fn new(from: f32, to: f32, ramp_time: f32, samplerate: f32) -> Self {
let ramp_samples = (samplerate * ramp_time).round();
let time_inc = 1.0 / ramp_samples;
let mul = to - from;
ExpRamp {
ramp_samples: ramp_samples as usize,
sample_count: 0,
cur_lvl: 0.0,
time_inc,
curve: 4.5 * mul.signum(),
time_count: 0.0,
mul,
from,
state: SynthState::Fresh,
}
}
}
impl<const BUFSIZE: usize> MonoSource<BUFSIZE> for ExpRamp<BUFSIZE> {
fn reset(&mut self) {
self.sample_count = 0;
self.cur_lvl = self.from;
}
fn finish(&mut self) {
self.state = SynthState::Finished;
}
fn is_finished(&self) -> bool {
matches!(self.state, SynthState::Finished)
}
fn set_modulator(&mut self, _: SynthParameterLabel, _: f32, _: Modulator<BUFSIZE>) {}
fn set_parameter(&mut self, _: SynthParameterLabel, _: &SynthParameterValue) {}
fn get_next_block(&mut self, start_sample: usize, _: &[SampleBuffer]) -> [f32; BUFSIZE] {
let mut out: [f32; BUFSIZE] = [0.0; BUFSIZE];
for current_sample in out.iter_mut().take(BUFSIZE).skip(start_sample) {
*current_sample = self.from + self.cur_lvl * self.mul;
self.cur_lvl = if self.sample_count < self.ramp_samples {
((self.curve * self.time_count).exp() - 1.0) / (self.curve.exp() - 1.0)
} else {
self.finish();
1.0
};
self.time_count += self.time_inc;
self.sample_count += 1;
}
out
}
}
#[derive(Clone, Copy)]
pub struct SineRamp<const BUFSIZE: usize> {
ramp_samples: usize,
sample_count: usize,
time_inc: f32,
time_count: f32,
cur_lvl: f32,
mul: f32,
from: f32,
state: SynthState,
}
impl<const BUFSIZE: usize> SineRamp<BUFSIZE> {
pub fn new(from: f32, to: f32, ramp_time: f32, samplerate: f32) -> Self {
let ramp_samples = (samplerate * ramp_time).round();
let time_inc = 1.0 / ramp_samples;
let mul = to - from;
SineRamp {
ramp_samples: ramp_samples as usize,
sample_count: 0,
cur_lvl: 0.0,
time_inc,
time_count: 0.0,
mul,
from,
state: SynthState::Fresh,
}
}
}
impl<const BUFSIZE: usize> MonoSource<BUFSIZE> for SineRamp<BUFSIZE> {
fn reset(&mut self) {
self.sample_count = 0;
self.cur_lvl = self.from;
}
fn finish(&mut self) {
self.state = SynthState::Finished;
}
fn is_finished(&self) -> bool {
matches!(self.state, SynthState::Finished)
}
fn set_modulator(&mut self, _: SynthParameterLabel, _: f32, _: Modulator<BUFSIZE>) {}
fn set_parameter(&mut self, _: SynthParameterLabel, _: &SynthParameterValue) {}
fn get_next_block(&mut self, start_sample: usize, _: &[SampleBuffer]) -> [f32; BUFSIZE] {
let mut out: [f32; BUFSIZE] = [0.0; BUFSIZE];
for current_sample in out.iter_mut().take(BUFSIZE).skip(start_sample) {
*current_sample = self.from + self.cur_lvl * self.mul;
self.cur_lvl = if self.sample_count < self.ramp_samples {
(std::f32::consts::PI / 2.0 * self.time_count).sin()
} else {
self.finish();
1.0
};
self.time_count += self.time_inc;
self.sample_count += 1;
}
out
}
}
#[derive(Clone, Copy)]
pub struct CosRamp<const BUFSIZE: usize> {
ramp_samples: usize,
sample_count: usize,
time_inc: f32,
time_count: f32,
cur_lvl: f32,
mul: f32,
from: f32,
state: SynthState,
}
impl<const BUFSIZE: usize> CosRamp<BUFSIZE> {
pub fn new(from: f32, to: f32, ramp_time: f32, samplerate: f32) -> Self {
let ramp_samples = (samplerate * ramp_time).round();
let time_inc = 1.0 / ramp_samples;
let mul = to - from;
CosRamp {
ramp_samples: ramp_samples as usize,
sample_count: 0,
cur_lvl: 0.0,
time_inc,
time_count: 0.0,
mul,
from,
state: SynthState::Fresh,
}
}
}
impl<const BUFSIZE: usize> MonoSource<BUFSIZE> for CosRamp<BUFSIZE> {
fn reset(&mut self) {
self.sample_count = 0;
self.cur_lvl = self.from;
}
fn finish(&mut self) {
self.state = SynthState::Finished;
}
fn is_finished(&self) -> bool {
matches!(self.state, SynthState::Finished)
}
fn set_modulator(&mut self, _: SynthParameterLabel, _: f32, _: Modulator<BUFSIZE>) {}
fn set_parameter(&mut self, _: SynthParameterLabel, _: &SynthParameterValue) {}
fn get_next_block(&mut self, start_sample: usize, _: &[SampleBuffer]) -> [f32; BUFSIZE] {
let mut out: [f32; BUFSIZE] = [0.0; BUFSIZE];
for current_sample in out.iter_mut().take(BUFSIZE).skip(start_sample) {
*current_sample = self.from + self.cur_lvl * self.mul;
self.cur_lvl = if self.sample_count < self.ramp_samples {
1.0 - (std::f32::consts::PI / 2.0 * self.time_count).cos()
} else {
self.finish();
1.0
};
self.time_count += self.time_inc;
self.sample_count += 1;
}
out
}
}
#[derive(Clone, Copy)]
pub struct ConstantMod<const BUFSIZE: usize> {
time_samples: usize,
sample_count: usize,
value: f32,
state: SynthState,
}
impl<const BUFSIZE: usize> ConstantMod<BUFSIZE> {
pub fn new(time: f32, value: f32, samplerate: f32) -> Self {
ConstantMod {
time_samples: (samplerate * time) as usize,
sample_count: 0,
value,
state: SynthState::Fresh,
}
}
}
impl<const BUFSIZE: usize> MonoSource<BUFSIZE> for ConstantMod<BUFSIZE> {
fn reset(&mut self) {}
fn finish(&mut self) {
self.state = SynthState::Finished;
}
fn is_finished(&self) -> bool {
matches!(self.state, SynthState::Finished)
}
fn set_modulator(&mut self, _: SynthParameterLabel, _: f32, _: Modulator<BUFSIZE>) {}
fn set_parameter(&mut self, _: SynthParameterLabel, _: &SynthParameterValue) {}
fn get_next_block(&mut self, start_sample: usize, _: &[SampleBuffer]) -> [f32; BUFSIZE] {
self.sample_count += BUFSIZE - start_sample;
if self.sample_count > self.time_samples {
self.finish();
}
let mut out = [0.0; BUFSIZE];
for sample in out.iter_mut().take(BUFSIZE).skip(start_sample) {
*sample = self.value;
}
out
}
}
#[derive(Clone)]
pub struct MultiPointEnvelope<const BUFSIZE: usize> {
segments: Vec<Box<dyn MonoSource<BUFSIZE> + Sync + Send>>,
segment_samples: Vec<usize>,
segment_idx: usize,
sample_count: usize, loop_env: bool,
state: SynthState,
samplerate: f32,
}
impl<const BUFSIZE: usize> MultiPointEnvelope<BUFSIZE> {
pub fn new(segment_infos: Vec<EnvelopeSegmentInfo>, loop_env: bool, samplerate: f32) -> Self {
let mut segments: Vec<Box<dyn MonoSource<BUFSIZE> + Sync + Send>> = Vec::new();
let mut segment_samples = Vec::new();
for info in segment_infos.iter() {
segment_samples.push((info.time * samplerate).round() as usize);
segments.push(match info.segment_type {
EnvelopeSegmentType::Lin => {
Box::new(LinearRamp::new(info.from, info.to, info.time, samplerate))
}
EnvelopeSegmentType::Log => {
Box::new(LogRamp::new(info.from, info.to, info.time, samplerate))
}
EnvelopeSegmentType::Exp => {
Box::new(ExpRamp::new(info.from, info.to, info.time, samplerate))
}
EnvelopeSegmentType::Sin => {
Box::new(ExpRamp::new(info.from, info.to, info.time, samplerate))
}
EnvelopeSegmentType::Cos => {
Box::new(ExpRamp::new(info.from, info.to, info.time, samplerate))
}
EnvelopeSegmentType::Constant => {
Box::new(ConstantMod::new(info.time, info.to, samplerate))
}
});
}
MultiPointEnvelope {
segments,
segment_samples,
segment_idx: 0,
sample_count: 0,
loop_env,
state: SynthState::Fresh,
samplerate,
}
}
pub fn empty(samplerate: f32) -> Self {
MultiPointEnvelope {
segments: Vec::new(),
segment_samples: Vec::new(),
segment_idx: 0,
sample_count: 0,
loop_env: false,
state: SynthState::Fresh,
samplerate,
}
}
}
impl<const BUFSIZE: usize> MonoSource<BUFSIZE> for MultiPointEnvelope<BUFSIZE> {
fn reset(&mut self) {
self.sample_count = 0;
self.segment_idx = 0;
for s in self.segments.iter_mut() {
s.reset();
}
}
fn finish(&mut self) {
self.state = SynthState::Finished;
}
fn is_finished(&self) -> bool {
if let Some(last) = self.segments.last() {
!self.loop_env && last.is_finished()
} else {
true }
}
fn set_modulator(&mut self, _: SynthParameterLabel, _: f32, _: Modulator<BUFSIZE>) {}
fn set_parameter(&mut self, par: SynthParameterLabel, val: &SynthParameterValue) {
if let SynthParameterLabel::Envelope = par
&& let SynthParameterValue::MultiPointEnvelope(segment_infos, loop_env, _) = val
{
let mut segments: Vec<Box<dyn MonoSource<BUFSIZE> + Sync + Send>> = Vec::new();
let mut segment_samples = Vec::new();
for info in segment_infos.iter() {
segment_samples.push((info.time * self.samplerate).round() as usize);
segments.push(match info.segment_type {
EnvelopeSegmentType::Lin => Box::new(LinearRamp::new(
info.from,
info.to,
info.time,
self.samplerate,
)),
EnvelopeSegmentType::Log => {
Box::new(LogRamp::new(info.from, info.to, info.time, self.samplerate))
}
EnvelopeSegmentType::Exp => {
Box::new(ExpRamp::new(info.from, info.to, info.time, self.samplerate))
}
EnvelopeSegmentType::Sin => Box::new(SineRamp::new(
info.from,
info.to,
info.time,
self.samplerate,
)),
EnvelopeSegmentType::Cos => {
Box::new(CosRamp::new(info.from, info.to, info.time, self.samplerate))
}
EnvelopeSegmentType::Constant => {
Box::new(ConstantMod::new(info.time, info.to, self.samplerate))
}
});
}
self.segments = segments;
self.segment_samples = segment_samples;
self.loop_env = *loop_env;
}
}
fn get_next_block(&mut self, start_sample: usize, bufs: &[SampleBuffer]) -> [f32; BUFSIZE] {
if self.segment_idx >= self.segments.len() {
if let Some(last_seg) = self.segments.last_mut() {
return last_seg.get_next_block(start_sample, bufs);
} else {
return [0.0; BUFSIZE]; }
}
let block_samples_to_fill_total = BUFSIZE - start_sample;
if block_samples_to_fill_total < self.segment_samples[self.segment_idx] - self.sample_count
{
self.sample_count += block_samples_to_fill_total;
self.segments[self.segment_idx].get_next_block(start_sample, bufs)
} else {
let mut out: [f32; BUFSIZE] = [0.0; BUFSIZE];
let mut block_samples_to_fill_rest = block_samples_to_fill_total;
let mut start_index = start_sample;
while block_samples_to_fill_rest > 0 {
if let Some(current_segment) = self.segments.get_mut(self.segment_idx) {
let samples_left_in_segment =
self.segment_samples[self.segment_idx] - self.sample_count;
let out_current = current_segment.get_next_block(start_index, bufs);
if samples_left_in_segment >= block_samples_to_fill_rest {
out[start_index..BUFSIZE]
.copy_from_slice(&out_current[start_index..BUFSIZE]);
self.sample_count += BUFSIZE - start_index;
break; } else {
let end_index = start_index + samples_left_in_segment;
out[start_index..end_index]
.copy_from_slice(&out_current[start_index..end_index]);
block_samples_to_fill_rest -= samples_left_in_segment;
start_index = end_index;
self.segment_idx += 1; self.sample_count = 0; }
} else if self.loop_env {
self.reset(); } else {
break; }
}
out
}
}
}