use crate::core::Normal;
use crate::core::param::NormalParam;
use std::fmt::Debug;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct FloatRange {
min: f32,
max: f32,
}
impl FloatRange {
pub const NORMAL: Self = Self { min: 0.0, max: 1.0 };
pub const NORMAL_BIPOLAR: Self = Self {
min: -1.0,
max: 1.0,
};
pub const fn new(min: f32, max: f32) -> Self {
assert!(max >= min);
Self { min, max }
}
pub const fn min(&self) -> f32 {
self.min
}
pub const fn max(&self) -> f32 {
self.max
}
pub fn span(&self) -> f32 {
self.max - self.min
}
pub fn clamp(&self, value: f32) -> f32 {
if value <= self.min {
self.min
} else if value >= self.max {
self.max
} else {
value
}
}
pub fn param(&self, value: f32, default: f32) -> NormalParam {
NormalParam {
normal: self.map(value),
default: self.map(default),
..Default::default()
}
}
pub fn default_param(&self) -> NormalParam {
NormalParam {
normal: self.map(0.0),
default: self.map(0.0),
..Default::default()
}
}
pub fn map(&self, value: f32) -> Normal {
let span = self.span();
if span == 0.0 {
Normal::MIN
} else {
let value = self.clamp(value);
Normal::new((value - self.min) / self.span())
}
}
pub fn unmap_to_value(&self, normal: Normal) -> f32 {
(normal.as_f32() * self.span()) + self.min
}
}
impl Default for FloatRange {
fn default() -> Self {
FloatRange::new(0.0, 1.0)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct IntRange {
min: i32,
max: i32,
}
impl IntRange {
pub const fn new(min: i32, max: i32) -> Self {
assert!(max >= min);
Self { min, max }
}
pub const fn min(&self) -> i32 {
self.min
}
pub const fn max(&self) -> i32 {
self.max
}
pub const fn span(&self) -> i32 {
self.max - self.min
}
pub const fn span_f32(&self) -> f32 {
(self.max - self.min) as f32
}
pub fn clamp(&self, value: i32) -> i32 {
if value <= self.min {
self.min
} else if value >= self.max {
self.max
} else {
value
}
}
pub fn param(&self, value: i32, default: i32) -> NormalParam {
NormalParam {
normal: self.map(value),
default: self.map(default),
..Default::default()
}
}
pub fn default_param(&self) -> NormalParam {
NormalParam {
normal: self.map(0),
default: self.map(0),
..Default::default()
}
}
pub fn snap(&self, normal: Normal) -> Normal {
let value_int = self.unmap_to_value(normal);
self.map(value_int)
}
pub fn map(&self, value: i32) -> Normal {
let span = self.span_f32();
if span == 0.0 {
Normal::MIN
} else {
let value = self.clamp(value);
Normal::new((value - self.min) as f32 / self.span_f32())
}
}
pub fn unmap_to_value(&self, normal: Normal) -> i32 {
(normal.as_f32() * self.span_f32()).round() as i32 + self.min
}
}
impl Default for IntRange {
fn default() -> Self {
IntRange::new(0, 100)
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct DBRange {
min: f32,
max: f32,
skew_factor: f32,
zero_position: Normal,
}
impl DBRange {
pub const DEFAULT_SKEW_FACTOR: f32 = 1.38;
pub const NEG_3_TO_3: Self = Self::new(-6.0, 6.0, Normal::CENTER, Self::DEFAULT_SKEW_FACTOR);
pub const NEG_6_TO_6: Self = Self::new(-6.0, 6.0, Normal::CENTER, Self::DEFAULT_SKEW_FACTOR);
pub const NEG_12_TO_12: Self =
Self::new(-12.0, 12.0, Normal::CENTER, Self::DEFAULT_SKEW_FACTOR);
pub const NEG_24_TO_24: Self =
Self::new(-24.0, 24.0, Normal::CENTER, Self::DEFAULT_SKEW_FACTOR);
pub const fn new(min: f32, max: f32, zero_position: Normal, skew_factor: f32) -> Self {
assert!(max >= min, "max must be >= min");
assert!(max >= 0.0, "max must be >= 0.0");
assert!(min <= 0.0, "min must be <= 0.0");
assert!(skew_factor >= 1.0, "skew_factor must be >= 1.0");
Self {
min,
max,
skew_factor,
zero_position,
}
}
pub fn clamp(&self, value: f32) -> f32 {
if value <= self.min {
self.min
} else if value >= self.max {
self.max
} else {
value
}
}
pub fn param(&self, value: f32, default: f32) -> NormalParam {
NormalParam {
normal: self.map_db(value),
default: self.map_db(default),
..Default::default()
}
}
pub fn default_param(&self) -> NormalParam {
NormalParam {
normal: self.map_db(0.0),
default: self.map_db(0.0),
..Default::default()
}
}
pub fn map_db(&self, value: f32) -> Normal {
let value = self.clamp(value);
if value == 0.0 || self.min == self.max {
self.zero_position
} else if value < 0.0 {
if self.min >= 0.0 {
return Normal::MIN;
}
let min_recip = if self.min == 0.0 {
0.0
} else {
self.min.recip()
};
let neg_normal = value * min_recip;
let log_normal = 1.0 - neg_normal.abs().powf(self.skew_factor.recip());
Normal::new(log_normal * self.zero_position.as_f32())
} else {
if self.max <= 0.0 {
return Normal::MAX;
}
let max_recip = if self.max == 0.0 {
0.0
} else {
self.max.recip()
};
let pos_normal = value * max_recip;
let log_normal = pos_normal.abs().powf(self.skew_factor.recip());
Normal::new(
(log_normal * (1.0 - self.zero_position.as_f32())) + self.zero_position.as_f32(),
)
}
}
pub fn unmap_to_db(&self, normal: Normal) -> f32 {
if normal == self.zero_position || self.min == self.max {
0.0
} else if normal < self.zero_position {
if self.min >= 0.0 {
return self.min;
}
let zero_pos_recip = if self.zero_position.as_f32() == 0.0 {
0.0
} else {
1.0 / self.zero_position.as_f32()
};
let neg_normal = 1.0 - (normal.as_f32() * zero_pos_recip);
let log_normal = 1.0 - neg_normal.abs().powf(self.skew_factor);
(1.0 - log_normal) * self.min
} else {
if self.zero_position.as_f32() == 1.0 || self.max <= 0.0 {
return self.max;
}
let one_min_zero_pos_recip = if self.zero_position.as_f32() == 0.0 {
0.0
} else {
1.0 / (1.0 - self.zero_position.as_f32())
};
let pos_normal =
(normal.as_f32() - self.zero_position.as_f32()) * one_min_zero_pos_recip;
let log_normal = pos_normal.abs().powf(self.skew_factor);
log_normal * self.max
}
}
}
impl Default for DBRange {
fn default() -> Self {
DBRange::NEG_12_TO_12
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct FreqRange {
min: f32,
max: f32,
}
impl FreqRange {
pub const HZ_20_TO_20K: Self = Self::new(20.0, 20_000.0);
pub const fn new(min: f32, max: f32) -> Self {
assert!(max >= min);
assert!(min > 0.0);
assert!(max > 0.0);
Self { min, max }
}
pub fn clamp(&self, value: f32) -> f32 {
if value <= self.min {
self.min
} else if value >= self.max {
self.max
} else {
value
}
}
pub fn param(&self, value: f32, default: f32) -> NormalParam {
NormalParam {
normal: self.map_freq(value),
default: self.map_freq(default),
..Default::default()
}
}
pub fn default_param(&self) -> NormalParam {
NormalParam {
normal: self.map_freq(20_480.0),
default: self.map_freq(20_480.0),
..Default::default()
}
}
pub fn map_freq(&self, value: f32) -> Normal {
if self.min == self.max {
Normal::MIN
} else {
let value = self.clamp(value);
let spectrum_normal = octave_spectrum_map_to_normal(value);
let min_spectrum_normal = octave_spectrum_map_to_normal(self.min);
let max_spectrum_normal = octave_spectrum_map_to_normal(self.max);
let spectrum_normal_span = max_spectrum_normal.as_f32() - min_spectrum_normal.as_f32();
Normal::new(
(spectrum_normal.as_f32() - min_spectrum_normal.as_f32()) / spectrum_normal_span,
)
}
}
pub fn unmap_to_freq(&self, normal: Normal) -> f32 {
if self.min == self.max {
self.min
} else {
let min_spectrum_normal = octave_spectrum_map_to_normal(self.min);
let max_spectrum_normal = octave_spectrum_map_to_normal(self.max);
let spectrum_normal_span = max_spectrum_normal.as_f32() - min_spectrum_normal.as_f32();
let spectrum_normal =
Normal::new(normal.as_f32() * spectrum_normal_span + min_spectrum_normal.as_f32());
octave_normal_to_spectrum(spectrum_normal)
}
}
}
impl Default for FreqRange {
fn default() -> Self {
FreqRange::HZ_20_TO_20K
}
}
#[inline]
fn octave_normal_to_spectrum(value: Normal) -> f32 {
40.0 * 2.0_f32.powf((10.0 * value.as_f32()) - 1.0)
}
#[inline]
fn octave_spectrum_map_to_normal(freq: f32) -> Normal {
Normal::new(((freq / 40.0).log2() + 1.0) * 0.1)
}