#[repr(u16)]
#[derive(Clone, Copy, Default)]
pub enum ModSrc {
#[default]
Velocity,
Aftertouch,
ModWheel,
Env1,
Env2,
Lfo1,
Lfo2,
}
impl ModSrc {
pub const ELEM: [ModSrc; Self::numel()] = [
ModSrc::Velocity,
ModSrc::Aftertouch,
ModSrc::ModWheel,
ModSrc::Env1,
ModSrc::Env2,
ModSrc::Lfo1,
ModSrc::Lfo2,
];
pub const fn elements() -> &'static [ModSrc] {
&Self::ELEM
}
pub const fn min() -> Self {
Self::Velocity
}
pub const fn max() -> Self {
Self::Lfo2
}
pub const fn numel() -> usize {
1 + Self::max() as usize - Self::min() as usize
}
pub const fn to_str(&self) -> &'static str {
match self {
Self::Velocity => "Velocity",
Self::Aftertouch => "Aftertouch",
Self::ModWheel => "Mod Wheel",
Self::Env1 => "Envelope 1",
Self::Env2 => "Envelope 2",
Self::Lfo1 => "LFO 1",
Self::Lfo2 => "LFO 2",
}
}
}
#[repr(u16)]
#[derive(Clone, Copy, PartialEq, Default)]
pub enum ModDest {
#[default]
Null,
Osc1Course,
Osc1Fine,
Osc1Shape,
Osc1Sin,
Osc1Sq,
Osc1Tri,
Osc1Saw,
Osc2Course,
Osc2Fine,
Osc2Shape,
Osc2Sin,
Osc2Sq,
Osc2Tri,
Osc2Saw,
RingOsc1,
RingOsc2,
RingMod,
FiltCutoff,
FiltRes,
FiltEnv,
FiltKbd,
FiltVel,
FiltLow,
FiltBand,
FiltHigh,
EnvFiltA,
EnvFiltD,
EnvFiltS,
EnvFiltR,
EnvAmpA,
EnvAmpD,
EnvAmpS,
EnvAmpR,
Lfo2Rate,
Lfo2Depth,
Env2A,
Env2D,
Env2S,
Env2R,
}
impl ModDest {
pub const fn remove_secondary_invalid_dest(self) -> Self {
match self {
Self::Lfo2Rate => Self::Null,
Self::Lfo2Depth => Self::Null,
Self::Env2A => Self::Null,
Self::Env2D => Self::Null,
Self::Env2S => Self::Null,
Self::Env2R => Self::Null,
val => val,
}
}
pub const fn to_str(&self) -> &'static str {
match self {
Self::Null => "NONE",
Self::Osc1Course => "Osc1Course",
Self::Osc1Fine => "Osc1Fine",
Self::Osc1Shape => "Osc1Shape",
Self::Osc1Sin => "Osc1Sin",
Self::Osc1Sq => "Osc1Sq",
Self::Osc1Tri => "Osc1Tri",
Self::Osc1Saw => "Osc1Saw",
Self::Osc2Course => "Osc2Course",
Self::Osc2Fine => "Osc2Fine",
Self::Osc2Shape => "Osc2Shape",
Self::Osc2Sin => "Osc2Sin",
Self::Osc2Sq => "Osc2Sq",
Self::Osc2Tri => "Osc2Tri",
Self::Osc2Saw => "Osc2Saw",
Self::RingOsc1 => "RingOsc1",
Self::RingOsc2 => "RingOsc2",
Self::RingMod => "RingMod",
Self::FiltCutoff => "FiltCutoff",
Self::FiltRes => "FiltRes",
Self::FiltEnv => "FiltEnv",
Self::FiltKbd => "FiltKbd",
Self::FiltVel => "FiltVel",
Self::FiltLow => "FiltLow",
Self::FiltBand => "FiltBand",
Self::FiltHigh => "FiltHigh",
Self::EnvFiltA => "EnvFiltA",
Self::EnvFiltD => "EnvFiltD",
Self::EnvFiltS => "EnvFiltS",
Self::EnvFiltR => "EnvFiltR",
Self::EnvAmpA => "EnvAmpA",
Self::EnvAmpD => "EnvAmpD",
Self::EnvAmpS => "EnvAmpS",
Self::EnvAmpR => "EnvAmpR",
Self::Lfo2Rate => "Lfo2Rate",
Self::Lfo2Depth => "Lfo2Depth",
Self::Env2A => "Env2A",
Self::Env2D => "Env2D",
Self::Env2S => "Env2S",
Self::Env2R => "Env2R",
}
}
pub const fn min() -> Self {
Self::Null
}
pub const fn max() -> Self {
Self::Env2R
}
pub const fn numel() -> usize {
Self::max() as usize + 1
}
pub const fn max_secondary() -> Self {
Self::EnvAmpR
}
pub fn elements() -> impl core::iter::Iterator<Item = ModDest> {
Self::elements_secondary_if(false)
}
pub fn elements_secondary() -> impl core::iter::Iterator<Item = ModDest> {
Self::elements_secondary_if(true)
}
pub fn elements_secondary_if(sec: bool) -> impl core::iter::Iterator<Item = ModDest> {
let max = if sec {
Self::max_secondary()
} else {
Self::max()
};
((Self::min() as u16)..=(max as u16)).map(|x| unsafe { core::mem::transmute(x) })
}
}
impl TryFrom<u16> for ModDest {
type Error = &'static str;
fn try_from(value: u16) -> Result<Self, Self::Error> {
if value >= Self::min() as u16 && value <= Self::max() as u16 {
unsafe { Ok(core::mem::transmute(value)) }
} else {
Err("ModDest out of bounds")
}
}
}
impl TryFrom<&str> for ModDest {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
Self::elements()
.find(|elem| value == elem.to_str())
.ok_or("ModDest::try_from::<&str> parse failure")
}
}
pub struct OscModDest {
pub course: ModDest,
pub fine: ModDest,
pub shape: ModDest,
pub sin: ModDest,
pub sq: ModDest,
pub tri: ModDest,
pub saw: ModDest,
}
pub const OSC1_MOD_DEST: OscModDest = OscModDest {
course: ModDest::Osc1Course,
fine: ModDest::Osc1Fine,
shape: ModDest::Osc1Shape,
sin: ModDest::Osc1Sin,
sq: ModDest::Osc1Sq,
tri: ModDest::Osc1Tri,
saw: ModDest::Osc1Saw,
};
pub const OSC2_MOD_DEST: OscModDest = OscModDest {
course: ModDest::Osc2Course,
fine: ModDest::Osc2Fine,
shape: ModDest::Osc2Shape,
sin: ModDest::Osc2Sin,
sq: ModDest::Osc2Sq,
tri: ModDest::Osc2Tri,
saw: ModDest::Osc2Saw,
};
pub struct EnvModDest {
pub attack: ModDest,
pub decay: ModDest,
pub sustain: ModDest,
pub release: ModDest,
}
pub const ENV_AMP_MOD_DEST: EnvModDest = EnvModDest {
attack: ModDest::EnvAmpA,
decay: ModDest::EnvAmpD,
sustain: ModDest::EnvAmpS,
release: ModDest::EnvAmpR,
};
pub const ENV_FILT_MOD_DEST: EnvModDest = EnvModDest {
attack: ModDest::EnvFiltA,
decay: ModDest::EnvFiltD,
sustain: ModDest::EnvFiltS,
release: ModDest::EnvFiltR,
};