use std::fmt::Debug;
use four_cc::FourCC;
use crate::utils::{
ahdsr::{AhdsrEnvelope, AhdsrParameters, AhdsrStage},
dsp::lfo::{Lfo, LfoWaveform},
};
pub const MODULATION_PROCESSOR_BLOCK_SIZE: usize = 64;
pub trait ModulationProcessor: Debug + Clone + Send {
fn reset(&mut self);
fn is_active(&self) -> bool;
fn process(&mut self, output: &mut [f32]);
}
#[derive(Debug, Clone)]
pub struct LfoModulationProcessor {
lfo: Lfo,
sample_rate: u32,
rate: f64,
waveform: LfoWaveform,
}
impl LfoModulationProcessor {
pub fn new(sample_rate: u32, rate: f64, waveform: LfoWaveform) -> Self {
let lfo = Lfo::new(sample_rate, rate, waveform);
Self {
lfo,
sample_rate,
rate,
waveform,
}
}
#[allow(unused)]
pub fn rate(&self) -> f64 {
self.rate
}
pub fn set_rate(&mut self, rate: f64) {
self.rate = rate;
self.lfo.set_rate(self.sample_rate, rate);
}
#[allow(unused)]
pub fn waveform(&self) -> LfoWaveform {
self.waveform
}
pub fn set_waveform(&mut self, waveform: LfoWaveform) {
self.waveform = waveform;
self.lfo.set_waveform(waveform);
}
}
impl ModulationProcessor for LfoModulationProcessor {
fn reset(&mut self) {
self.lfo.reset();
}
fn is_active(&self) -> bool {
true }
fn process(&mut self, output: &mut [f32]) {
self.lfo.process(output)
}
}
#[derive(Clone)]
pub struct AhdsrModulationProcessor {
envelope: AhdsrEnvelope,
parameters: AhdsrParameters,
}
impl std::fmt::Debug for AhdsrModulationProcessor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AhdsrModulationProcessor")
.field("stage", &self.envelope.stage())
.field("output", &self.envelope.output())
.finish()
}
}
#[allow(unused)]
impl AhdsrModulationProcessor {
pub fn new(parameters: AhdsrParameters) -> Self {
let envelope = AhdsrEnvelope::new();
Self {
envelope,
parameters,
}
}
pub fn note_on(&mut self, volume: f32) {
self.envelope.note_on(&self.parameters, volume);
}
pub fn note_off(&mut self) {
self.envelope.note_off(&self.parameters);
}
#[allow(unused)]
pub fn stage(&self) -> AhdsrStage {
self.envelope.stage()
}
#[allow(unused)]
pub fn parameters(&self) -> &AhdsrParameters {
&self.parameters
}
pub fn set_parameters(&mut self, parameters: AhdsrParameters) {
self.parameters = parameters;
}
pub fn set_attack(&mut self, attack: f32) {
let _ = self
.parameters
.set_attack_time(std::time::Duration::from_secs_f32(attack));
}
pub fn set_hold(&mut self, hold: f32) {
let _ = self
.parameters
.set_hold_time(std::time::Duration::from_secs_f32(hold));
}
pub fn set_decay(&mut self, decay: f32) {
let _ = self
.parameters
.set_decay_time(std::time::Duration::from_secs_f32(decay));
}
pub fn set_sustain(&mut self, sustain: f32) {
let _ = self.parameters.set_sustain_level(sustain);
}
pub fn set_release(&mut self, release: f32) {
let _ = self
.parameters
.set_release_time(std::time::Duration::from_secs_f32(release));
}
}
impl ModulationProcessor for AhdsrModulationProcessor {
fn reset(&mut self) {
self.envelope.reset();
}
fn is_active(&self) -> bool {
self.envelope.stage() != AhdsrStage::Idle
}
fn process(&mut self, output: &mut [f32]) {
self.envelope.process(&self.parameters, output);
}
}
#[derive(Debug, Clone)]
pub struct VelocityModulationProcessor {
velocity: f32,
}
impl VelocityModulationProcessor {
pub fn new(velocity: f32) -> Self {
debug_assert!(
(0.0..=1.0).contains(&velocity),
"Velocity must be in range [0.0, 1.0]"
);
Self { velocity }
}
#[allow(unused)]
pub fn velocity(&self) -> f32 {
self.velocity
}
pub fn set_velocity(&mut self, velocity: f32) {
debug_assert!(
(0.0..=1.0).contains(&velocity),
"Velocity must be in range [0.0, 1.0]"
);
self.velocity = velocity;
}
}
impl ModulationProcessor for VelocityModulationProcessor {
fn reset(&mut self) {
}
fn is_active(&self) -> bool {
true }
fn process(&mut self, output: &mut [f32]) {
output.fill(self.velocity);
}
}
#[derive(Debug, Clone)]
pub struct KeytrackingModulationProcessor {
note_pitch: f32, }
impl KeytrackingModulationProcessor {
pub fn new(midi_note: f32) -> Self {
debug_assert!(
(0.0..=127.0).contains(&midi_note),
"MIDI note must be in range [0.0, 127.0]"
);
let note_pitch = midi_note / 127.0;
Self { note_pitch }
}
#[allow(unused)]
pub fn note_pitch(&self) -> f32 {
self.note_pitch
}
pub fn set_midi_note(&mut self, midi_note: f32) {
debug_assert!(
(0.0..=127.0).contains(&midi_note),
"MIDI note must be in range [0.0, 127.0]"
);
self.note_pitch = midi_note / 127.0;
}
}
impl ModulationProcessor for KeytrackingModulationProcessor {
fn reset(&mut self) {
}
fn is_active(&self) -> bool {
true }
fn process(&mut self, output: &mut [f32]) {
output.fill(self.note_pitch);
}
}
#[derive(Debug, Clone)]
pub struct ModulationProcessorTarget {
pub parameter_id: FourCC,
pub amount: f32,
pub bipolar: bool,
}
impl ModulationProcessorTarget {
pub fn new(parameter_id: FourCC, amount: f32, bipolar: bool) -> Self {
Self {
parameter_id,
amount,
bipolar,
}
}
}