use playr_dsp::fx::{BusSetting, DelayModel, DelayParam, ReverbModel, ReverbParam};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Division {
Whole,
Half,
Quarter,
Eighth,
DottedEighth,
Sixteenth,
}
impl Division {
pub const ALL: [Division; 6] = [
Division::Whole,
Division::Half,
Division::Quarter,
Division::Eighth,
Division::DottedEighth,
Division::Sixteenth,
];
pub fn name(self) -> &'static str {
match self {
Division::Whole => "1/1",
Division::Half => "1/2",
Division::Quarter => "1/4",
Division::Eighth => "1/8",
Division::DottedEighth => "3/16",
Division::Sixteenth => "1/16",
}
}
pub fn fraction(self) -> f64 {
match self {
Division::Whole => 1.0,
Division::Half => 0.5,
Division::Quarter => 0.25,
Division::Eighth => 0.125,
Division::DottedEighth => 0.1875,
Division::Sixteenth => 0.0625,
}
}
}
pub const DELAY_MODELS: [(&str, DelayModel); 3] = [
("clean", DelayModel::Clean),
("ping-pong", DelayModel::PingPong),
("tape", DelayModel::Tape),
];
pub const REVERB_MODELS: [(&str, ReverbModel); 4] = [
("freeverb", ReverbModel::Freeverb),
("zita", ReverbModel::Zita),
("jp", ReverbModel::Jp),
("plate", ReverbModel::Plate),
];
pub fn model_name<M: PartialEq>(table: &[(&'static str, M)], model: M) -> &'static str {
table.iter().find(|m| m.1 == model).expect("every model").0
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FxSetting {
DelayModel(DelayModel),
Time(f32),
Sync(Option<Division>),
Feedback(f32),
Tone(f32),
Wow(f32),
DelayReturn(f32),
ReverbModel(ReverbModel),
Size(f32),
Decay(f32),
Damp(f32),
ReverbReturn(f32),
Print(f32),
}
impl FxSetting {
pub fn bus(self) -> Option<BusSetting> {
Some(match self {
FxSetting::DelayModel(m) => BusSetting::DelayModel(m),
FxSetting::Time(ms) => BusSetting::Delay(DelayParam::Time, ms / 1000.0),
FxSetting::Feedback(v) => BusSetting::Delay(DelayParam::Feedback, v),
FxSetting::Tone(hz) => BusSetting::Delay(DelayParam::Tone, hz),
FxSetting::Wow(v) => BusSetting::Delay(DelayParam::Wow, v),
FxSetting::DelayReturn(v) => BusSetting::DelayReturn(v),
FxSetting::ReverbModel(m) => BusSetting::ReverbModel(m),
FxSetting::Size(v) => BusSetting::Reverb(ReverbParam::Size, v),
FxSetting::Decay(v) => BusSetting::Reverb(ReverbParam::Decay, v),
FxSetting::Damp(v) => BusSetting::Reverb(ReverbParam::Damp, v),
FxSetting::ReverbReturn(v) => BusSetting::ReverbReturn(v),
FxSetting::Sync(_) | FxSetting::Print(_) => return None,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct FxState {
pub delay_model: DelayModel,
pub time: f32,
pub sync: Option<Division>,
pub feedback: f32,
pub tone: f32,
pub wow: f32,
pub delay_return: f32,
pub reverb_model: ReverbModel,
pub size: f32,
pub decay: f32,
pub damp: f32,
pub reverb_return: f32,
pub print: f32,
}
impl Default for FxState {
fn default() -> Self {
let mut fx = FxState {
delay_model: DelayModel::DEFAULT,
time: 0.0,
sync: None,
feedback: 0.0,
tone: 0.0,
wow: 0.0,
delay_return: 1.0,
reverb_model: ReverbModel::DEFAULT,
size: 0.0,
decay: 0.0,
damp: 0.0,
reverb_return: 1.0,
print: 0.0,
};
for (p, v) in playr_looper::DELAY_DEFAULTS {
fx.apply(BusSetting::Delay(p, v));
}
for (p, v) in playr_looper::REVERB_DEFAULTS {
fx.apply(BusSetting::Reverb(p, v));
}
fx
}
}
impl FxState {
pub fn apply(&mut self, s: BusSetting) {
match s {
BusSetting::DelayModel(m) => self.delay_model = m,
BusSetting::Delay(DelayParam::Time, x) => self.time = x * 1000.0,
BusSetting::Delay(DelayParam::Feedback, x) => self.feedback = x,
BusSetting::Delay(DelayParam::Tone, x) => self.tone = x,
BusSetting::Delay(DelayParam::Wow, x) => self.wow = x,
BusSetting::DelayReturn(x) => self.delay_return = x,
BusSetting::ReverbModel(m) => self.reverb_model = m,
BusSetting::Reverb(ReverbParam::Size, x) => self.size = x,
BusSetting::Reverb(ReverbParam::Decay, x) => self.decay = x,
BusSetting::Reverb(ReverbParam::Damp, x) => self.damp = x,
BusSetting::ReverbReturn(x) => self.reverb_return = x,
}
}
pub fn settings(&self) -> [BusSetting; 11] {
[
BusSetting::DelayModel(self.delay_model),
BusSetting::Delay(DelayParam::Time, self.time / 1000.0),
BusSetting::Delay(DelayParam::Feedback, self.feedback),
BusSetting::Delay(DelayParam::Tone, self.tone),
BusSetting::Delay(DelayParam::Wow, self.wow),
BusSetting::DelayReturn(self.delay_return),
BusSetting::ReverbModel(self.reverb_model),
BusSetting::Reverb(ReverbParam::Size, self.size),
BusSetting::Reverb(ReverbParam::Decay, self.decay),
BusSetting::Reverb(ReverbParam::Damp, self.damp),
BusSetting::ReverbReturn(self.reverb_return),
]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FxField {
DelayModel,
Time,
Sync,
Feedback,
Tone,
Wow,
DelayReturn,
ReverbModel,
Size,
Decay,
Damp,
ReverbReturn,
}
pub fn idle(fx: &FxState, fed: [bool; 2], field: FxField) -> Option<crate::tape::Idle> {
use crate::tape::Idle;
use FxField as F;
let quiet = |b: usize| (!fed[b]).then_some(Idle::NoFxSend);
match field {
F::DelayModel | F::Time | F::Sync | F::Feedback | F::Tone | F::DelayReturn => quiet(0),
F::Wow => quiet(0).or((fx.delay_model != DelayModel::Tape).then_some(Idle::Model)),
F::ReverbModel | F::Damp | F::ReverbReturn => quiet(1),
F::Size => quiet(1).or(
matches!(fx.reverb_model, ReverbModel::Zita | ReverbModel::Plate)
.then_some(Idle::Model),
),
F::Decay => quiet(1).or((fx.reverb_model == ReverbModel::Freeverb).then_some(Idle::Model)),
}
}