use crate::vectree::VecTree;
use std::sync::Arc;
pub mod decoder;
pub mod encoder;
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct SynthDef {
name: String,
graph: VecTree<Scalar>,
params: Parameters,
}
impl SynthDef {
pub fn new<F, T>(name: impl Into<String>, ugen_fn: F) -> SynthDef
where
F: FnOnce(&mut Parameters) -> T,
T: Input,
{
let mut params = Parameters::empty();
let graph = ugen_fn(&mut params).into_value().0;
SynthDef {
name: name.into(),
graph,
params,
}
}
pub fn name(&self) -> &str {
&self.name
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub(crate) struct UGenSpec<I> {
name: String,
rate: Rate,
signal_range: SignalRange,
special_index: i16,
inputs: Vec<I>,
outputs: Vec<Rate>,
}
impl<I> UGenSpec<I> {
pub fn new(name: &'static str, rate: Rate) -> UGenSpec<I> {
UGenSpec {
name: name.to_owned(),
rate,
signal_range: SignalRange::Bipolar,
special_index: 0,
inputs: Vec::new(),
outputs: vec![rate],
}
}
pub fn signal_range(mut self, signal_range: SignalRange) -> Self {
self.signal_range = signal_range;
self
}
pub fn special_index(mut self, special_index: i16) -> Self {
self.special_index = special_index;
self
}
pub fn inputs(mut self, inputs: impl IntoIterator<Item = I>) -> Self {
self.inputs.extend(inputs);
self
}
pub fn input(mut self, input: I) -> Self {
self.inputs.push(input);
self
}
pub fn outputs(mut self, outputs: impl IntoIterator<Item = Rate>) -> Self {
self.outputs = outputs.into_iter().collect();
self
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
pub(crate) enum Rate {
Scalar = 0,
Control = 1,
Audio = 2,
}
impl From<Rate> for i8 {
fn from(rate: Rate) -> Self {
rate as i8
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum DoneAction {
None = 0,
PauseSelf = 1,
FreeSelf = 2,
FreeSelfAndPrev = 3,
FreeSelfAndNext = 4,
FreeSelfAndFreeAllInPrev = 5,
FreeSelfAndFreeAllInNext = 6,
FreeSelfToHead = 7,
FreeSelfToTail = 8,
FreeSelfPausePrev = 9,
FreeSelfPauseNext = 10,
FreeSelfAndDeepFreePrev = 11,
FreeSelfAndDeepFreeNext = 12,
FreeAllInGroup = 13,
FreeGroup = 14,
FreeSelfResumeNext = 15,
}
impl Default for DoneAction {
fn default() -> DoneAction {
DoneAction::None
}
}
impl Input for DoneAction {
fn into_value(self) -> Value {
(self as i32).into_value()
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub(crate) enum Scalar {
Const(f32),
Parameter(Parameter),
Ugen {
output_index: i32,
ugen_spec: Arc<UGenSpec<Scalar>>,
},
}
impl Scalar {
fn rate(&self) -> Rate {
match self {
Self::Const(_) => Rate::Scalar,
Self::Parameter(_) => Rate::Control,
Self::Ugen {
ugen_spec,
output_index,
} => ugen_spec.outputs[*output_index as usize],
}
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Parameters {
initial_values: Vec<f32>,
names: Vec<(String, usize)>,
}
impl Parameters {
fn empty() -> Parameters {
Parameters {
initial_values: Vec::new(),
names: Vec::new(),
}
}
pub fn named(&mut self, name: impl Into<String>, initial_value: f32) -> Parameter {
let index = self.initial_values.len();
self.initial_values.push(initial_value);
self.names.push((name.into(), index));
Parameter { index }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Parameter {
index: usize,
}
impl Input for Parameter {
fn into_value(self) -> Value {
Value(VecTree::Leaf(Scalar::Parameter(self)))
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Value(pub(crate) VecTree<Scalar>);
impl Value {
pub fn unwrap_stereo(self) -> (Value, Value) {
match self.0 {
VecTree::Leaf(_) => panic!("called `VecTree::unwrap_stereo` on a `Scalar` value"),
VecTree::Branch(mut branch) => {
if branch.len() != 2 {
panic!(
"called `VecTree::unwrap_stereo` on a signal with {} channels",
branch.len()
);
}
let b = branch.pop().unwrap();
let a = branch.pop().unwrap();
(Value(a), Value(b))
}
}
}
}
impl Input for Value {
fn into_value(self) -> Value {
self
}
}
impl Input for f32 {
fn into_value(self) -> Value {
Value(VecTree::Leaf(Scalar::Const(self)))
}
}
impl Input for i32 {
fn into_value(self) -> Value {
Value(VecTree::Leaf(Scalar::Const(self as f32)))
}
}
impl Input for usize {
fn into_value(self) -> Value {
Value(VecTree::Leaf(Scalar::Const(self as f32)))
}
}
fn bin_op_ugen(special_index: i16, lhs: Value, rhs: Value) -> Value {
let inputs = vec![UGenInput::Simple(lhs), UGenInput::Simple(rhs)];
expand_inputs_with(inputs, &mut |inputs: Vec<Scalar>| {
let rate = input_rate(&inputs);
VecTree::Leaf(Scalar::Ugen {
output_index: 0,
ugen_spec: Arc::new(
UGenSpec::new("BinaryOpUGen", rate)
.special_index(special_index)
.inputs(inputs),
),
})
})
}
fn mul_add(value: impl Input, mul: impl Input, add: impl Input) -> Value {
let inputs = vec![
UGenInput::Simple(value.into_value()),
UGenInput::Simple(mul.into_value()),
UGenInput::Simple(add.into_value()),
];
expand_inputs_with(inputs, &mut |inputs: Vec<Scalar>| {
let rate = input_rate(&inputs);
VecTree::Leaf(Scalar::Ugen {
output_index: 0,
ugen_spec: Arc::new(UGenSpec::new("MulAdd", rate).inputs(inputs)),
})
})
}
fn unary_op_ugen(special_index: i16, value: Value) -> Value {
let inputs = vec![UGenInput::Simple(value)];
expand_inputs_with(inputs, &mut |inputs: Vec<Scalar>| {
let rate = input_rate(&inputs);
VecTree::Leaf(Scalar::Ugen {
output_index: 0,
ugen_spec: Arc::new(
UGenSpec::new("UnaryOpUGen", rate)
.special_index(special_index)
.inputs(inputs),
),
})
})
}
fn input_rate(inputs: &[Scalar]) -> Rate {
inputs
.iter()
.map(|input| input.rate())
.max()
.unwrap_or(Rate::Scalar)
}
pub trait Input: Sized {
fn into_value(self) -> Value;
fn add(self, rhs: impl Input) -> Value {
bin_op_ugen(0, self.into_value(), rhs.into_value())
}
fn sub(self, rhs: impl Input) -> Value {
bin_op_ugen(1, self.into_value(), rhs.into_value())
}
fn mul(self, rhs: impl Input) -> Value {
bin_op_ugen(2, self.into_value(), rhs.into_value())
}
fn div(self, rhs: impl Input) -> Value {
bin_op_ugen(3, self.into_value(), rhs.into_value())
}
fn idiv(self, rhs: impl Input) -> Value {
bin_op_ugen(4, self.into_value(), rhs.into_value())
}
fn modulo(self, divisor: impl Input) -> Value {
bin_op_ugen(5, self.into_value(), divisor.into_value())
}
fn madd(self, mul: impl Input, add: impl Input) -> Value {
mul_add(self, mul, add)
}
fn midicps(self) -> Value {
unary_op_ugen(17, self.into_value())
}
fn cpsmidi(self) -> Value {
unary_op_ugen(18, self.into_value())
}
fn range(self, lo: impl Input, hi: impl Input) -> Value {
let value = self.into_value();
let lo = lo.into_value();
let hi = hi.into_value();
let is_unipolar = value.clone().0.into_iter().all(|scalar| {
matches!(
scalar,
Scalar::Ugen { ugen_spec, .. } if ugen_spec.signal_range == SignalRange::Unipolar
)
});
let mul;
let add;
if is_unipolar {
mul = hi.sub(lo.clone());
add = lo;
} else {
mul = hi.sub(lo.clone()).mul(0.5);
add = mul.clone().add(lo);
}
value.madd(mul, add)
}
}
impl<T> Input for Vec<T>
where
T: Input,
{
fn into_value(self) -> Value {
Value(VecTree::Branch(
self.into_iter().map(|value| value.into_value().0).collect(),
))
}
}
#[derive(Debug, PartialEq, Clone)]
pub(crate) enum UGenInput {
Simple(Value),
Multi(Value),
}
impl UGenInput {
fn expand(self) -> Vec<VecTree<Scalar>> {
match self {
UGenInput::Simple(Value(value)) => vec![value],
UGenInput::Multi(Value(value)) => match value {
VecTree::Leaf(expanded_value) => vec![VecTree::Leaf(expanded_value)],
VecTree::Branch(xs) => xs,
},
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub(crate) enum SignalRange {
Unipolar,
Bipolar,
}
fn mutlichannel_expand<I, F, U, A, B>(inputs: I, expand_one: F) -> VecTree<Vec<B>>
where
I: IntoIterator<Item = A>,
F: Fn(A) -> U,
U: IntoIterator<Item = VecTree<B>>,
B: Clone,
{
let expanded_inputs = inputs.into_iter().flat_map(expand_one).collect::<Vec<_>>();
let dimensions = VecTree::space(&expanded_inputs);
transmute_trees(&expanded_inputs, &dimensions, &mut vec![])
}
fn transmute_trees<T>(
input_trees: &[VecTree<T>],
dimensions: &[usize],
path: &mut Vec<usize>,
) -> VecTree<Vec<T>>
where
T: Clone,
{
match dimensions {
[] => {
let xs = input_trees
.iter()
.map(|tree| tree.get_path(path).unwrap().clone())
.collect();
VecTree::Leaf(xs)
}
[size, dimensions @ ..] => {
let mut trees = vec![];
for i in 0..*size {
path.push(i);
trees.push(transmute_trees(input_trees, dimensions, path));
path.pop();
}
VecTree::Branch(trees)
}
}
}
fn expand_inputs_with<F>(inputs: Vec<UGenInput>, f: &mut F) -> Value
where
F: FnMut(Vec<Scalar>) -> VecTree<Scalar>,
{
Value(mutlichannel_expand(inputs, UGenInput::expand).flat_map(f))
}
impl Input for UGenSpec<UGenInput> {
fn into_value(self) -> Value {
let UGenSpec {
name,
rate,
signal_range,
special_index,
inputs,
outputs,
} = self;
expand_inputs_with(inputs, &mut |inputs| {
let ugen_spec = Arc::new(UGenSpec {
name: name.clone(),
rate,
signal_range,
special_index,
inputs,
outputs: outputs.clone(),
});
if outputs.len() <= 1 {
VecTree::Leaf(Scalar::Ugen {
output_index: 0,
ugen_spec,
})
} else {
VecTree::Branch(
(0..outputs.len())
.into_iter()
.map(|output_index| {
VecTree::Leaf(Scalar::Ugen {
output_index: output_index as i32,
ugen_spec: ugen_spec.clone(),
})
})
.collect::<Vec<_>>(),
)
}
})
}
}