skeleton & stubs
This commit is contained in:
278
crates/params/src/lib.rs
Normal file
278
crates/params/src/lib.rs
Normal file
@@ -0,0 +1,278 @@
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[repr(usize)]
|
||||
#[allow(dead_code)]
|
||||
pub enum ParamId {
|
||||
// Master
|
||||
MasterVolume = 0,
|
||||
MasterPan,
|
||||
|
||||
// Oscillator 1
|
||||
Osc1Volume,
|
||||
Osc1Pan,
|
||||
Osc1Pitch,
|
||||
Osc1Fine,
|
||||
Osc1WavePos,
|
||||
Osc1UnisonVoices,
|
||||
Osc1UnisonDetune,
|
||||
Osc1UnisonSpread,
|
||||
|
||||
// Oscillator 2
|
||||
Osc2Volume,
|
||||
Osc2Pan,
|
||||
Osc2Pitch,
|
||||
Osc2Fine,
|
||||
Osc2WavePos,
|
||||
Osc2UnisonVoices,
|
||||
Osc2UnisonDetune,
|
||||
Osc2UnisonSpread,
|
||||
|
||||
// Oscillator 3
|
||||
Osc3Volume,
|
||||
Osc3Pan,
|
||||
Osc3Pitch,
|
||||
Osc3Fine,
|
||||
Osc3WavePos,
|
||||
Osc3UnisonVoices,
|
||||
Osc3UnisonDetune,
|
||||
Osc3UnisonSpread,
|
||||
|
||||
// Envelope 1 (amplitude)
|
||||
Env1Delay,
|
||||
Env1Attack,
|
||||
Env1Hold,
|
||||
Env1Decay,
|
||||
Env1Sustain,
|
||||
Env1Release,
|
||||
|
||||
// Envelope 2
|
||||
Env2Delay,
|
||||
Env2Attack,
|
||||
Env2Hold,
|
||||
Env2Decay,
|
||||
Env2Sustain,
|
||||
Env2Release,
|
||||
|
||||
// Envelope 3
|
||||
Env3Delay,
|
||||
Env3Attack,
|
||||
Env3Hold,
|
||||
Env3Decay,
|
||||
Env3Sustain,
|
||||
Env3Release,
|
||||
|
||||
// LFO 1–4
|
||||
Lfo1Rate,
|
||||
Lfo1Depth,
|
||||
Lfo1Phase,
|
||||
Lfo2Rate,
|
||||
Lfo2Depth,
|
||||
Lfo2Phase,
|
||||
Lfo3Rate,
|
||||
Lfo3Depth,
|
||||
Lfo3Phase,
|
||||
Lfo4Rate,
|
||||
Lfo4Depth,
|
||||
Lfo4Phase,
|
||||
|
||||
// Filter 1
|
||||
Filter1Cutoff,
|
||||
Filter1Resonance,
|
||||
Filter1Drive,
|
||||
Filter1Keytrack,
|
||||
|
||||
// Filter 2
|
||||
Filter2Cutoff,
|
||||
Filter2Resonance,
|
||||
Filter2Drive,
|
||||
Filter2Keytrack,
|
||||
|
||||
// FX — Chorus
|
||||
ChorusRate,
|
||||
ChorusDepth,
|
||||
ChorusMix,
|
||||
|
||||
// FX — Reverb
|
||||
ReverbSize,
|
||||
ReverbDamping,
|
||||
ReverbMix,
|
||||
|
||||
// FX — Delay
|
||||
DelayTime,
|
||||
DelayFeedback,
|
||||
DelayMix,
|
||||
|
||||
// FX — Distortion
|
||||
DistortionDrive,
|
||||
DistortionMix,
|
||||
|
||||
// FX — EQ
|
||||
EqLowGain,
|
||||
EqMidFreq,
|
||||
EqMidGain,
|
||||
EqHighGain,
|
||||
|
||||
// Macros
|
||||
Macro1,
|
||||
Macro2,
|
||||
Macro3,
|
||||
Macro4,
|
||||
Macro5,
|
||||
Macro6,
|
||||
Macro7,
|
||||
Macro8,
|
||||
|
||||
Count,
|
||||
}
|
||||
|
||||
pub const PARAM_COUNT: usize = ParamId::Count as usize;
|
||||
|
||||
pub fn default_value(id: ParamId) -> f32 {
|
||||
use ParamId::*;
|
||||
match id {
|
||||
MasterVolume => 0.8,
|
||||
MasterPan => 0.5,
|
||||
|
||||
Osc1Volume => 0.8,
|
||||
Osc2Volume | Osc3Volume => 0.0, // off by default
|
||||
Osc1Pan | Osc2Pan | Osc3Pan => 0.5,
|
||||
Osc1Pitch | Osc2Pitch | Osc3Pitch => 0.5,
|
||||
Osc1Fine | Osc2Fine | Osc3Fine => 0.5,
|
||||
|
||||
Env1Attack | Env2Attack | Env3Attack => 0.02,
|
||||
Env1Decay | Env2Decay | Env3Decay => 0.30,
|
||||
Env1Sustain | Env2Sustain | Env3Sustain => 0.70,
|
||||
Env1Release | Env2Release | Env3Release => 0.35,
|
||||
|
||||
Filter1Cutoff | Filter2Cutoff => 1.0,
|
||||
Filter1Keytrack | Filter2Keytrack => 0.0,
|
||||
|
||||
Lfo1Rate | Lfo2Rate | Lfo3Rate | Lfo4Rate => 0.3,
|
||||
|
||||
_ => 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ParamStore {
|
||||
data: Arc<[AtomicU32]>,
|
||||
}
|
||||
|
||||
impl ParamStore {
|
||||
pub fn new() -> Self {
|
||||
let data: Arc<[AtomicU32]> = (0..PARAM_COUNT)
|
||||
.map(|i| {
|
||||
let id: ParamId = unsafe { std::mem::transmute(i) };
|
||||
AtomicU32::new(default_value(id).to_bits())
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.into();
|
||||
Self { data }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get(&self, id: ParamId) -> f32 {
|
||||
f32::from_bits(self.data[id as usize].load(Ordering::Relaxed))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set(&self, id: ParamId, value: f32) {
|
||||
debug_assert!((0.0..=1.0).contains(&value), "param out of range: {value}");
|
||||
self.data[id as usize].store(value.to_bits(), Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub fn reset_to_defaults(&self) {
|
||||
for i in 0..PARAM_COUNT {
|
||||
let id: ParamId = unsafe { std::mem::transmute(i) };
|
||||
self.data[i].store(default_value(id).to_bits(), Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn snapshot(&self) -> Vec<f32> {
|
||||
(0..PARAM_COUNT)
|
||||
.map(|i| f32::from_bits(self.data[i].load(Ordering::Relaxed)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn restore(&self, values: &[f32]) {
|
||||
assert_eq!(values.len(), PARAM_COUNT, "snapshot length mismatch");
|
||||
for (i, &v) in values.iter().enumerate() {
|
||||
self.data[i].store(v.to_bits(), Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ParamStore {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ParamMeta {
|
||||
pub name: &'static str,
|
||||
pub label: &'static str,
|
||||
pub steps: Option<u32>,
|
||||
}
|
||||
|
||||
pub fn param_meta(id: ParamId) -> ParamMeta {
|
||||
use ParamId::*;
|
||||
match id {
|
||||
MasterVolume => ParamMeta {
|
||||
name: "Master Volume",
|
||||
label: "%",
|
||||
steps: None,
|
||||
},
|
||||
MasterPan => ParamMeta {
|
||||
name: "Master Pan",
|
||||
label: "",
|
||||
steps: None,
|
||||
},
|
||||
Osc1Pitch => ParamMeta {
|
||||
name: "Osc1 Pitch",
|
||||
label: "st",
|
||||
steps: Some(96),
|
||||
},
|
||||
Filter1Cutoff => ParamMeta {
|
||||
name: "Filter1 Cutoff",
|
||||
label: "Hz",
|
||||
steps: None,
|
||||
},
|
||||
Filter1Resonance => ParamMeta {
|
||||
name: "Filter1 Res",
|
||||
label: "",
|
||||
steps: None,
|
||||
},
|
||||
Env1Attack => ParamMeta {
|
||||
name: "Env1 Attack",
|
||||
label: "s",
|
||||
steps: None,
|
||||
},
|
||||
Env1Decay => ParamMeta {
|
||||
name: "Env1 Decay",
|
||||
label: "s",
|
||||
steps: None,
|
||||
},
|
||||
Env1Sustain => ParamMeta {
|
||||
name: "Env1 Sustain",
|
||||
label: "%",
|
||||
steps: None,
|
||||
},
|
||||
Env1Release => ParamMeta {
|
||||
name: "Env1 Release",
|
||||
label: "s",
|
||||
steps: None,
|
||||
},
|
||||
Macro1 => ParamMeta {
|
||||
name: "Macro 1",
|
||||
label: "",
|
||||
steps: None,
|
||||
},
|
||||
_ => ParamMeta {
|
||||
name: "?",
|
||||
label: "",
|
||||
steps: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user