use rill_core::traits::{ParameterId, PortId};
use std::sync::Arc;
#[derive(Debug, Clone)]
pub enum Transform {
Linear,
Exponential,
Logarithmic,
Inverted,
Scale { scale: f32, offset: f32 },
Threshold { level: f32, hysteresis: f32 },
Smooth { coefficient: f32 },
Rms { window_size: usize },
Peak { decay: f32 },
Envelope { attack: f32, release: f32 },
Frequency { min_freq: f32, max_freq: f32 },
Custom(Arc<dyn Fn(f32) -> f32 + Send + Sync>),
}
impl Transform {
pub fn apply(&self, x: f32) -> f32 {
let x = x.clamp(0.0, 1.0);
match self {
Transform::Linear => x,
Transform::Exponential => x * x,
Transform::Logarithmic => {
if x <= 0.0 { 0.0 } else { (1.0 + 9.0 * x).log10() }
}
Transform::Inverted => 1.0 - x,
Transform::Scale { scale, offset } => x * scale + offset,
Transform::Threshold { level, hysteresis } => {
static mut STATE: bool = false;
unsafe {
if x > *level + hysteresis {
STATE = true;
1.0
} else if x < *level - hysteresis {
STATE = false;
0.0
} else if STATE {
1.0
} else {
0.0
}
}
}
Transform::Smooth { coefficient } => {
static mut LAST: f32 = 0.0;
unsafe {
LAST = LAST * (1.0 - coefficient) + x * coefficient;
LAST
}
}
_ => x, }
}
}
#[derive(Debug, Clone)]
pub struct MappingRule {
pub input_name: String,
pub input_channel: usize,
pub transform: Transform,
pub output_name: String,
pub target_port: Option<PortId>,
pub target_parameter: Option<ParameterId>,
pub output_range: (f32, f32),
}
impl MappingRule {
pub fn new(input_name: impl Into<String>, output_name: impl Into<String>) -> Self {
Self {
input_name: input_name.into(),
input_channel: 0,
transform: Transform::Linear,
output_name: output_name.into(),
target_port: None,
target_parameter: None,
output_range: (0.0, 1.0),
}
}
pub fn with_transform(mut self, transform: Transform) -> Self {
self.transform = transform;
self
}
pub fn with_range(mut self, min: f32, max: f32) -> Self {
self.output_range = (min, max);
self
}
pub fn with_channel(mut self, channel: usize) -> Self {
self.input_channel = channel;
self
}
pub fn with_target(mut self, port: PortId, parameter: ParameterId) -> Self {
self.target_port = Some(port);
self.target_parameter = Some(parameter);
self
}
pub fn apply(&self, x: f32) -> f32 {
let transformed = self.transform.apply(x);
self.output_range.0 + transformed * (self.output_range.1 - self.output_range.0)
}
}