use crate::{
synthdef::{Input, Scalar, Value},
vectree::VecTree,
};
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Env {
loop_node: Option<usize>,
release_node: Option<usize>,
levels: Vec<Value>,
times: Vec<Value>,
curve: CurveInput,
}
impl Env {
pub fn adsr() -> Env {
Env::default()
.levels(vec![0.0, 1.0, 0.5, 0.0])
.times(vec![0.01, 0.3, 1.0])
.curve(-4)
.release_node(2)
}
pub fn levels<I, T>(mut self, levels: I) -> Env
where
I: IntoIterator<Item = T>,
T: Input,
{
self.levels = levels.into_iter().map(Input::into_value).collect();
self
}
pub fn times<I, T>(mut self, times: I) -> Env
where
I: IntoIterator<Item = T>,
T: Input,
{
self.times = times.into_iter().map(Input::into_value).collect();
self
}
pub fn curve(mut self, curve: impl Into<CurveInput>) -> Env {
self.curve = curve.into();
self
}
pub fn loop_node(mut self, index: usize) -> Env {
self.loop_node.replace(index);
self
}
pub fn release_node(mut self, index: usize) -> Env {
self.release_node.replace(index);
self
}
pub(crate) fn into_values(self) -> Vec<Value> {
if self.levels.is_empty() {
panic!("no levels set on envelope")
}
if self.levels.len() > 1 && self.times.is_empty() {
panic!("multiple levels set on envelope, but no times were set")
}
let size = self.times.len();
let mut values = Vec::with_capacity((size + 1) * 4);
let mut levels = self.levels.into_iter();
values.push(levels.next().unwrap());
values.push((size as i32).into_value());
values.push(node_index_to_value(self.release_node));
values.push(node_index_to_value(self.loop_node));
let curves = match self.curve.0 {
VecTree::Leaf(curve) => vec![VecTree::Leaf(curve)],
VecTree::Branch(xs) => xs,
};
let curve_shapes = curves
.clone()
.into_iter()
.map(|tree| Value(tree.map(ExpandedCurve::shape)));
let curve_values = curves
.into_iter()
.map(|tree| Value(tree.map(|curve| curve.value())));
for (((level, time), curve_shape), curve_value) in levels
.into_iter()
.zip(self.times.into_iter().cycle())
.zip(curve_shapes.cycle())
.zip(curve_values.cycle())
{
values.push(level);
values.push(time);
values.push(curve_shape);
values.push(curve_value);
}
values
}
}
impl Default for Env {
fn default() -> Env {
Env {
loop_node: None,
release_node: None,
levels: vec![0.into_value(), 1.into_value(), 0.into_value()],
times: vec![1.into_value(), 1.into_value()],
curve: CurveInput::from(Curve::default()),
}
}
}
fn node_index_to_value(index: Option<usize>) -> Value {
index
.map(|index| index as f32)
.unwrap_or(-99.0)
.into_value()
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Curve {
Step,
Hold,
Linear,
Exponential,
Sine,
Welch,
Squared,
Cubed,
Curve(Value),
}
impl Default for Curve {
fn default() -> Curve {
Curve::Linear
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct CurveInput(VecTree<ExpandedCurve>);
impl<T> From<Vec<T>> for CurveInput
where
T: Into<CurveInput>,
{
fn from(inputs: Vec<T>) -> CurveInput {
CurveInput(VecTree::Branch(
inputs.into_iter().map(|input| input.into().0).collect(),
))
}
}
impl From<Curve> for CurveInput {
fn from(curve: Curve) -> CurveInput {
CurveInput(match curve {
Curve::Step => VecTree::Leaf(ExpandedCurve::Step),
Curve::Linear => VecTree::Leaf(ExpandedCurve::Linear),
Curve::Exponential => VecTree::Leaf(ExpandedCurve::Exponential),
Curve::Sine => VecTree::Leaf(ExpandedCurve::Sine),
Curve::Welch => VecTree::Leaf(ExpandedCurve::Welch),
Curve::Curve(value) => value.0.map(ExpandedCurve::Curve),
Curve::Squared => VecTree::Leaf(ExpandedCurve::Squared),
Curve::Cubed => VecTree::Leaf(ExpandedCurve::Cubed),
Curve::Hold => VecTree::Leaf(ExpandedCurve::Hold),
})
}
}
impl From<f32> for CurveInput {
fn from(curve: f32) -> CurveInput {
Curve::Curve(curve.into_value()).into()
}
}
impl From<i32> for CurveInput {
fn from(curve: i32) -> CurveInput {
Curve::Curve(curve.into_value()).into()
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
enum ExpandedCurve {
Step,
Linear,
Exponential,
Sine,
Welch,
Curve(Scalar),
Squared,
Cubed,
Hold,
}
impl ExpandedCurve {
fn shape(self) -> Scalar {
Scalar::Const(match self {
ExpandedCurve::Step => 0.0,
ExpandedCurve::Linear => 1.0,
ExpandedCurve::Exponential => 2.0,
ExpandedCurve::Sine => 3.0,
ExpandedCurve::Welch => 4.0,
ExpandedCurve::Curve(_) => 5.0,
ExpandedCurve::Squared => 6.0,
ExpandedCurve::Cubed => 7.0,
ExpandedCurve::Hold => 8.0,
})
}
fn value(self) -> Scalar {
match self {
ExpandedCurve::Step => Scalar::Const(0.0),
ExpandedCurve::Linear => Scalar::Const(0.0),
ExpandedCurve::Exponential => Scalar::Const(0.0),
ExpandedCurve::Sine => Scalar::Const(0.0),
ExpandedCurve::Welch => Scalar::Const(0.0),
ExpandedCurve::Curve(scalar) => scalar,
ExpandedCurve::Squared => Scalar::Const(0.0),
ExpandedCurve::Cubed => Scalar::Const(0.0),
ExpandedCurve::Hold => Scalar::Const(0.0),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_value_should_match_sclang() {
let expected = vec![0, 2, -99, -99, 1, 1, 1, 0, 0, 1, 1, 0]
.into_iter()
.map(|x| x.into_value())
.collect::<Vec<_>>();
assert_eq!(expected, Env::default().into_values());
}
#[test]
fn adsr_default_should_match_sclang() {
let expected = vec![
0.0, 3.0, 2.0, -99.0, 1.0, 0.01, 5.0, -4.0, 0.5, 0.3, 5.0, -4.0, 0.0, 1.0, 5.0, -4.0,
]
.into_iter()
.map(|x| x.into_value())
.collect::<Vec<_>>();
assert_eq!(expected, Env::adsr().into_values());
}
}