use super::{Parameters, Rate, Scalar, SignalRange, SynthDef, UGenSpec};
use std::io::Write;
use std::sync::Arc;
pub fn encode_synth_defs(synth_defs: impl IntoIterator<Item = SynthDef>) -> Vec<u8> {
let expanded_synths = synth_defs
.into_iter()
.map(|synthdef| {
(
synthdef.name,
synthdef.graph.into_iter().collect::<Vec<_>>(),
synthdef.params,
)
})
.collect::<Vec<_>>();
let graphs = expanded_synths
.iter()
.map(|(name, expanded_inputs, params)| SynthDefGraph::new(name, &expanded_inputs, params))
.collect();
let mut buffer = Vec::new();
encode_graphs(graphs, &mut buffer);
buffer
}
struct SynthDefGraph<'a> {
name: String,
constants: Vec<Const>,
initial_parameter_values: &'a [f32],
parameter_names: &'a [(String, usize)],
ugens: Vec<SynthDefUgen<'a>>,
variant_specs: Vec<VariantSpec<'a>>,
}
impl<'a> SynthDefGraph<'a> {
fn new(name: impl Into<String>, inputs: &'a [Scalar], params: &'a Parameters) -> Self {
let mut file = SynthDefGraph {
name: name.into(),
constants: Vec::new(),
initial_parameter_values: ¶ms.initial_values,
parameter_names: ¶ms.names,
ugens: Vec::new(),
variant_specs: Vec::new(),
};
if !params.initial_values.is_empty() {
file.ugens.push(SynthDefUgen {
source: Arc::new(UGenSpec {
name: "Control".to_owned(),
rate: Rate::Audio,
signal_range: SignalRange::Bipolar,
special_index: 0,
inputs: vec![],
outputs: vec![Rate::Control; params.initial_values.len()],
}),
spec: UgenSpecRef {
name: "Control",
rate: Rate::Control.into(),
special_index: 0,
input_specs: vec![],
output_specs: vec![Rate::Control.into(); params.initial_values.len()],
},
})
}
for value in inputs.iter() {
file.encode(value);
}
file
}
fn encode(&mut self, input: &'a Scalar) -> (i32, i32) {
match input {
Scalar::Const(n) => {
let constant = Const(*n);
let index = self
.constants
.iter()
.position(|x| x == &constant)
.unwrap_or_else(|| {
self.constants.push(constant);
self.constants.len() - 1
});
(-1, index as i32)
}
Scalar::Parameter(ref parameter) => {
(0, parameter.index as i32)
}
Scalar::Ugen {
output_index,
ugen_spec,
} => {
let index = self
.ugens
.iter()
.position(|u| Arc::ptr_eq(&u.source, ugen_spec))
.unwrap_or_else(|| {
let input_specs = ugen_spec
.inputs
.iter()
.map(|input| self.encode(input))
.collect();
self.ugens.push(SynthDefUgen {
source: ugen_spec.clone(),
spec: UgenSpecRef {
name: &ugen_spec.name,
rate: ugen_spec.rate.into(),
special_index: ugen_spec.special_index,
input_specs,
output_specs: ugen_spec
.outputs
.iter()
.map(|&rate| rate.into())
.collect(),
},
});
self.ugens.len() - 1
});
(index as i32, *output_index)
}
}
}
}
#[derive(PartialEq)]
struct Const(f32);
#[derive(Debug)]
struct SynthDefUgen<'a> {
source: Arc<UGenSpec<Scalar>>,
spec: UgenSpecRef<'a>,
}
#[derive(Debug, PartialEq)]
struct UgenSpecRef<'a> {
name: &'a str,
rate: i8,
special_index: i16,
input_specs: Vec<(i32, i32)>,
output_specs: Vec<i8>,
}
#[derive(Debug)]
struct VariantSpec<'a> {
name: &'a str,
parameter_values: Vec<f32>,
}
fn encode_graphs(graphs: Vec<SynthDefGraph>, out: &mut Vec<u8>) {
let header: i32 = 0x53436766; write_i32(out, header);
let file_version: i32 = 2;
write_i32(out, file_version);
write_i16(out, graphs.len() as i16);
for graph in graphs {
write_pstring(out, &graph.name);
write_i32(out, graph.constants.len() as i32);
for constant in graph.constants {
write_f32(out, constant.0);
}
write_i32(out, graph.initial_parameter_values.len() as i32);
for initial_value in graph.initial_parameter_values.iter() {
write_f32(out, *initial_value);
}
write_i32(out, graph.parameter_names.len() as i32);
for (parameter_name, parameter_index) in graph.parameter_names.iter() {
write_pstring(out, ¶meter_name);
write_i32(out, *parameter_index as i32);
}
write_i32(out, graph.ugens.len() as i32);
for ugen_spec in graph.ugens.into_iter().map(|u| u.spec) {
write_pstring(out, ugen_spec.name);
write_i8(out, ugen_spec.rate);
write_i32(out, ugen_spec.input_specs.len() as i32);
write_i32(out, ugen_spec.output_specs.len() as i32);
write_i16(out, ugen_spec.special_index);
for (i, j) in ugen_spec.input_specs {
write_i32(out, i);
write_i32(out, j);
}
for output_spec in ugen_spec.output_specs {
write_i8(out, output_spec);
}
}
write_i16(out, graph.variant_specs.len() as i16);
for variant_spec in graph.variant_specs {
write_pstring(out, variant_spec.name);
for parameter_value in variant_spec.parameter_values {
write_f32(out, parameter_value);
}
}
}
}
fn write_i32(w: &mut Vec<u8>, n: i32) {
w.write_all(&n.to_be_bytes()).unwrap();
}
fn write_i16(w: &mut Vec<u8>, n: i16) {
w.write_all(&n.to_be_bytes()).unwrap();
}
fn write_i8(w: &mut Vec<u8>, n: i8) {
w.write_all(&n.to_be_bytes()).unwrap();
}
fn write_f32(w: &mut Vec<u8>, n: f32) {
w.write_all(&n.to_be_bytes()).unwrap();
}
fn write_pstring(w: &mut Vec<u8>, s: &str) {
w.write_all(&[s.len() as u8]).unwrap();
w.write_all(s.as_bytes()).unwrap();
}