use serde::{Deserialize, Serialize};
use crate::dsl::{Adsr, Node};
use crate::patch::Patch;
use super::note::Note;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum PitchMap {
Param(String),
Transpose {
reference: Note,
},
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum PlayMode {
#[default]
Poly,
Mono {
legato: bool,
},
}
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
pub struct Modulation {
#[serde(default)]
pub vibrato_rate: f32,
#[serde(default)]
pub vibrato_cents: f32,
#[serde(default)]
pub tremolo_rate: f32,
#[serde(default)]
pub tremolo_depth: f32,
#[serde(default)]
pub filter_rate: f32,
#[serde(default)]
pub filter_octaves: f32,
}
impl Modulation {
pub(super) fn is_active(&self) -> bool {
(self.vibrato_cents > 0.0 && self.vibrato_rate > 0.0)
|| (self.tremolo_depth > 0.0 && self.tremolo_rate > 0.0)
|| (self.filter_octaves > 0.0 && self.filter_rate > 0.0)
}
}
#[non_exhaustive]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct InstrumentDesign {
pub patch: Patch,
pub amp: Adsr,
pub pitch: PitchMap,
pub velocity_param: Option<String>,
pub max_voices: usize,
pub master: Vec<Node>,
#[serde(default)]
pub mode: PlayMode,
#[serde(default)]
pub glide_secs: f32,
#[serde(default = "one")]
pub unison: usize,
#[serde(default)]
pub detune_cents: f32,
#[serde(default)]
pub unison_width: f32,
#[serde(default)]
pub modulation: Modulation,
}
fn one() -> usize {
1
}
impl InstrumentDesign {
pub fn new(patch: Patch) -> Self {
let has_pitch = patch.params.iter().any(|p| p.name == "pitch");
InstrumentDesign {
pitch: if has_pitch {
PitchMap::Param("pitch".into())
} else {
PitchMap::Transpose {
reference: Note::C4,
}
},
amp: Adsr {
a: 0.005,
d: 0.08,
s: 0.7,
r: 0.12,
punch: 0.0,
},
velocity_param: None,
max_voices: 16,
master: Vec::new(),
mode: PlayMode::Poly,
glide_secs: 0.0,
unison: 1,
detune_cents: 0.0,
unison_width: 0.0,
modulation: Modulation::default(),
patch,
}
}
pub fn with_master(mut self, master: Vec<Node>) -> Self {
self.master = master;
self
}
pub fn with_amp(mut self, amp: Adsr) -> Self {
self.amp = amp;
self
}
pub fn with_pitch(mut self, pitch: PitchMap) -> Self {
self.pitch = pitch;
self
}
pub fn with_velocity_param(mut self, name: impl Into<String>) -> Self {
self.velocity_param = Some(name.into());
self
}
pub fn with_max_voices(mut self, max: usize) -> Self {
self.max_voices = max.max(1);
self
}
pub fn with_mode(mut self, mode: PlayMode) -> Self {
self.mode = mode;
self
}
pub fn with_glide(mut self, secs: f32) -> Self {
self.glide_secs = secs.max(0.0);
self
}
pub fn with_unison(mut self, count: usize, cents: f32, width: f32) -> Self {
self.unison = count.max(1);
self.detune_cents = cents.max(0.0);
self.unison_width = width.clamp(0.0, 1.0);
self
}
pub fn with_vibrato(mut self, rate: f32, cents: f32) -> Self {
self.modulation.vibrato_rate = rate;
self.modulation.vibrato_cents = cents.max(0.0);
self
}
pub fn with_tremolo(mut self, rate: f32, depth: f32) -> Self {
self.modulation.tremolo_rate = rate;
self.modulation.tremolo_depth = depth.clamp(0.0, 1.0);
self
}
pub fn with_wobble(mut self, rate: f32, octaves: f32) -> Self {
self.modulation.filter_rate = rate;
self.modulation.filter_octaves = octaves.max(0.0);
self
}
}