HexoDSP/src/matrix_repr.rs

869 lines
30 KiB
Rust
Raw Normal View History

// Copyright (c) 2021 Weird Constructor <weirdconstructor@gmail.com>
2021-08-04 01:58:43 +00:00
// This file is a part of HexoDSP. Released under GPL-3.0-or-later.
// See README.md and COPYING for details.
use crate::dsp::{NodeId, ParamId, SAtom};
2022-07-17 09:58:28 +00:00
use serde_json::{json, Value};
#[derive(Debug, Clone, Copy)]
pub struct CellRepr {
pub node_id: NodeId,
2022-07-17 09:58:28 +00:00
pub x: usize,
pub y: usize,
pub inp: [i16; 3],
pub out: [i16; 3],
}
2022-07-17 09:58:28 +00:00
fn deserialize_node_id(v: &Value, i1: usize, i2: usize) -> Result<NodeId, MatrixDeserError> {
let nid = NodeId::from_str(v[i1].as_str().unwrap_or("???"));
if nid == NodeId::Nop {
2022-07-17 09:58:28 +00:00
return Err(MatrixDeserError::UnknownNode(v[i1].as_str().unwrap_or("???").to_string()));
}
Ok(nid.to_instance(v[i2].as_i64().unwrap_or(0) as usize))
}
fn inp2idx(node_id: NodeId, v: &Value) -> i16 {
let inp = v.as_i64().unwrap_or(-2) as i16;
2022-07-17 09:58:28 +00:00
if inp > -2 {
inp
} else {
v.as_str().map(|s| node_id.inp(s).map(|i| i as i16).unwrap_or(-1)).unwrap_or(-1)
}
}
fn out2idx(node_id: NodeId, v: &Value) -> i16 {
let out = v.as_i64().unwrap_or(-2) as i16;
2022-07-17 09:58:28 +00:00
if out > -2 {
out
} else {
v.as_str().map(|s| node_id.out(s).map(|i| i as i16).unwrap_or(-1)).unwrap_or(-1)
}
}
fn inp_idx2value(node_id: NodeId, idx: i16) -> Value {
if idx == -1 {
json!(-1)
} else {
2022-07-17 09:58:28 +00:00
node_id.inp_name_by_idx(idx as u8).map(|n| json!(n)).unwrap_or_else(|| json!(-1))
}
}
fn out_idx2value(node_id: NodeId, idx: i16) -> Value {
if idx == -1 {
json!(-1)
} else {
2022-07-17 09:58:28 +00:00
node_id.out_name_by_idx(idx as u8).map(|n| json!(n)).unwrap_or_else(|| json!(-1))
}
}
impl CellRepr {
pub fn serialize(&self) -> Value {
json!([
self.node_id.name(),
self.node_id.instance(),
self.x,
self.y,
2022-07-17 09:58:28 +00:00
[
inp_idx2value(self.node_id, self.inp[0]),
inp_idx2value(self.node_id, self.inp[1]),
inp_idx2value(self.node_id, self.inp[2])
],
[
out_idx2value(self.node_id, self.out[0]),
out_idx2value(self.node_id, self.out[1]),
out_idx2value(self.node_id, self.out[2])
],
])
}
pub fn deserialize(v: &Value) -> Result<Self, MatrixDeserError> {
let node_id = deserialize_node_id(v, 0, 1)?;
Ok(Self {
node_id,
2022-07-17 09:58:28 +00:00
x: v[2].as_i64().unwrap_or(0) as usize,
y: v[3].as_i64().unwrap_or(0) as usize,
inp: [
inp2idx(node_id, &v[4][0]),
inp2idx(node_id, &v[4][1]),
2022-07-17 09:58:28 +00:00
inp2idx(node_id, &v[4][2]),
],
out: [
out2idx(node_id, &v[5][0]),
out2idx(node_id, &v[5][1]),
2022-07-17 09:58:28 +00:00
out2idx(node_id, &v[5][2]),
],
})
}
}
2022-07-17 09:58:28 +00:00
use crate::dsp::tracker::{MAX_COLS, MAX_PATTERN_LEN};
#[derive(Debug, Clone)]
pub struct PatternRepr {
pub col_types: [u8; MAX_COLS],
2022-07-17 09:58:28 +00:00
pub data: Vec<Vec<i32>>,
pub rows: usize,
pub edit_step: usize,
2022-07-17 09:58:28 +00:00
pub cursor: (usize, usize),
}
impl PatternRepr {
fn serialize(&self) -> Value {
let mut ret = json!({
"rows": self.rows,
"edit_step": self.edit_step,
"cursor_row": self.cursor.0,
"cursor_col": self.cursor.1,
});
let mut cts = json!([]);
if let Value::Array(cts) = &mut cts {
for ct in self.col_types.iter() {
cts.push(json!(*ct as i64));
}
}
ret["col_types"] = cts;
let mut data = json!([]);
if let Value::Array(data) = &mut data {
for row in self.data.iter() {
let mut out_col = json!([]);
if let Value::Array(out_col) = &mut out_col {
for col in row.iter() {
out_col.push(json!(*col as i64));
}
}
data.push(out_col);
}
}
ret["data"] = data;
ret
}
fn deserialize(v: &Value) -> Result<Self, MatrixDeserError> {
let mut col_types = [0; MAX_COLS];
let cts = &v["col_types"];
if let Value::Array(cts) = cts {
for (i, ct) in cts.iter().enumerate() {
col_types[i] = ct.as_i64().unwrap_or(0) as u8;
}
}
let mut data = vec![vec![-1; MAX_COLS]; MAX_PATTERN_LEN];
let dt = &v["data"];
if let Value::Array(dt) = dt {
for (row_idx, row) in dt.iter().enumerate() {
if let Value::Array(row) = row {
for (col_idx, c) in row.iter().enumerate() {
data[row_idx][col_idx] = c.as_i64().unwrap_or(-1) as i32;
}
}
}
}
Ok(Self {
col_types,
data,
2022-07-17 09:58:28 +00:00
rows: v["rows"].as_i64().unwrap_or(0) as usize,
edit_step: v["edit_step"].as_i64().unwrap_or(0) as usize,
cursor: (
v["cursor_row"].as_i64().unwrap_or(0) as usize,
2022-07-17 09:58:28 +00:00
v["cursor_col"].as_i64().unwrap_or(0) as usize,
),
})
}
}
#[derive(Debug, Clone)]
pub struct MatrixRepr {
2022-07-17 09:58:28 +00:00
pub cells: Vec<CellRepr>,
pub params: Vec<(ParamId, f32, Option<f32>)>,
pub atoms: Vec<(ParamId, SAtom)>,
pub patterns: Vec<Option<PatternRepr>>,
pub properties: Vec<(String, SAtom)>,
2022-07-17 09:58:28 +00:00
pub version: i64,
}
#[derive(Debug, Clone)]
pub enum MatrixDeserError {
BadVersion,
UnknownNode(String),
UnknownParamId(String),
Deserialization(String),
IO(String),
InvalidAtom(String),
MatrixError(crate::matrix::MatrixError),
}
impl From<crate::matrix::MatrixError> for MatrixDeserError {
fn from(err: crate::matrix::MatrixError) -> Self {
MatrixDeserError::MatrixError(err)
}
}
impl From<serde_json::Error> for MatrixDeserError {
fn from(err: serde_json::Error) -> MatrixDeserError {
MatrixDeserError::Deserialization(format!("{}", err))
}
}
impl From<std::str::Utf8Error> for MatrixDeserError {
fn from(err: std::str::Utf8Error) -> MatrixDeserError {
MatrixDeserError::Deserialization(format!("{}", err))
}
}
impl From<std::io::Error> for MatrixDeserError {
fn from(err: std::io::Error) -> MatrixDeserError {
MatrixDeserError::IO(format!("{}", err))
}
}
fn deserialize_atom(v: &Value) -> Result<SAtom, MatrixDeserError> {
match v[0].as_str().unwrap_or("?") {
"i" => {
2022-07-17 09:58:28 +00:00
if let Some(v) = v[1].as_i64() {
Ok(SAtom::setting(v))
} else {
Err(MatrixDeserError::InvalidAtom(v.to_string()))
}
}
"p" => {
2022-07-17 09:58:28 +00:00
if let Some(v) = v[1].as_f64() {
Ok(SAtom::param(v as f32))
} else {
Err(MatrixDeserError::InvalidAtom(v.to_string()))
}
}
"s" => {
2022-07-17 09:58:28 +00:00
if let Some(v) = v[1].as_str() {
Ok(SAtom::str(v))
} else {
Err(MatrixDeserError::InvalidAtom(v.to_string()))
}
}
"as" => {
2022-07-17 09:58:28 +00:00
if let Some(v) = v[1].as_str() {
Ok(SAtom::audio_unloaded(v))
} else {
Err(MatrixDeserError::InvalidAtom(v.to_string()))
}
}
"ms" => {
2022-07-17 09:58:28 +00:00
let mut buf: [f32; 8] = [0.0; 8];
for i in 0..8 {
if let Some(v) = v[i + 1].as_f64() {
buf[i] = v as f32;
} else {
return Err(MatrixDeserError::InvalidAtom(v.to_string()));
}
}
Ok(SAtom::micro(&buf))
2022-07-17 09:58:28 +00:00
}
_ => Err(MatrixDeserError::InvalidAtom(v.to_string())),
}
}
fn serialize_atom(atom: &SAtom) -> Value {
match atom {
2022-07-17 09:58:28 +00:00
SAtom::MicroSample(s) => json!(["ms", s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7],]),
SAtom::Str(s) => json!(["s", s]),
SAtom::AudioSample((s, _)) => json!(["as", s]),
2022-07-17 09:58:28 +00:00
SAtom::Setting(i) => json!(["i", i]),
SAtom::Param(p) => json!(["p", p]),
}
}
impl MatrixRepr {
pub fn empty() -> Self {
2022-07-17 09:58:28 +00:00
let cells = vec![];
let params = vec![];
let atoms = vec![];
let patterns = vec![];
let properties = vec![];
2022-07-17 09:58:28 +00:00
Self { cells, params, atoms, patterns, properties, version: 2 }
}
pub fn write_to_file(&mut self, filepath: &str) -> std::io::Result<()> {
use std::fs::OpenOptions;
2022-07-17 09:58:28 +00:00
use std::io::prelude::*;
let tmp_filepath = format!("{}~", filepath);
let mut ser = self.serialize();
ser.push('\n');
let mut file =
2022-07-17 09:58:28 +00:00
OpenOptions::new().create(true).write(true).truncate(true).open(&tmp_filepath)?;
file.write_all(ser.as_bytes())?;
std::fs::rename(&tmp_filepath, &filepath)?;
Ok(())
}
pub fn read_from_file(filepath: &str) -> Result<MatrixRepr, MatrixDeserError> {
use std::fs::OpenOptions;
2022-07-17 09:58:28 +00:00
use std::io::prelude::*;
2022-07-17 09:58:28 +00:00
let mut file = OpenOptions::new().write(false).create(false).read(true).open(&filepath)?;
2022-07-17 09:58:28 +00:00
let mut contents: Vec<u8> = Vec::new();
file.read_to_end(&mut contents)?;
let s = std::str::from_utf8(&contents)?;
MatrixRepr::deserialize(s)
}
pub fn deserialize(s: &str) -> Result<MatrixRepr, MatrixDeserError> {
2022-07-17 09:58:28 +00:00
let v: Value = serde_json::from_str(s)?;
let mut m = MatrixRepr::empty();
if let Some(version) = v.get("VERSION") {
2022-07-17 09:58:28 +00:00
let version: i64 = version.as_i64().unwrap_or(0);
if version > 2 {
return Err(MatrixDeserError::BadVersion);
}
m.version = version;
}
let cells = &v["cells"];
if let Value::Array(cells) = cells {
for c in cells.iter() {
m.cells.push(CellRepr::deserialize(c)?);
}
}
let params = &v["params"];
if let Value::Array(params) = params {
for v in params.iter() {
let node_id = deserialize_node_id(&v, 0, 1)?;
let param_id = node_id.inp_param(v[2].as_str().unwrap_or(""));
if let Some(param_id) = param_id {
2022-07-17 09:58:28 +00:00
m.params.push((
param_id,
v[3].as_f64().unwrap_or(0.0) as f32,
v[4].as_f64().map(|v| v as f32),
));
} else {
2022-07-17 09:58:28 +00:00
return Err(MatrixDeserError::UnknownParamId(v.to_string()));
}
}
}
let atoms = &v["atoms"];
if let Value::Array(atoms) = atoms {
for v in atoms.iter() {
let node_id = deserialize_node_id(&v, 0, 1)?;
let param_id = node_id.inp_param(v[2].as_str().unwrap_or(""));
if let Some(param_id) = param_id {
m.atoms.push((param_id, deserialize_atom(&v[3])?))
2022-07-17 09:58:28 +00:00
//d// } else {
//d// return Err(
//d// MatrixDeserError::UnknownParamId(v.to_string()));
}
}
}
let props = &v["props"];
if let Value::Array(props) = props {
for v in props.iter() {
let key = v[0].as_str().unwrap_or("");
2022-07-17 09:58:28 +00:00
m.properties.push((key.to_string(), deserialize_atom(&v[1])?));
}
}
let patterns = &v["patterns"];
if let Value::Array(patterns) = patterns {
for p in patterns.iter() {
2022-07-17 09:58:28 +00:00
m.patterns.push(if p.is_object() {
Some(PatternRepr::deserialize(&p)?)
} else {
None
});
}
}
Ok(m)
}
pub fn serialize(&mut self) -> String {
let mut v = json!({
"VERSION": self.version,
});
self.properties.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
self.params.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
self.atoms.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
let mut params = json!([]);
if let Value::Array(params) = &mut params {
for (p, v, ma) in self.params.iter() {
2022-07-17 09:58:28 +00:00
let mut param_v = json!([p.node_id().name(), p.node_id().instance(), p.name(), v,]);
if let Value::Array(param_v) = &mut param_v {
if let Some(ma) = ma {
param_v.push(json!(ma));
}
}
params.push(param_v);
}
}
v["params"] = params;
let mut atoms = json!([]);
if let Value::Array(atoms) = &mut atoms {
for (p, v) in self.atoms.iter() {
2022-07-17 09:58:28 +00:00
atoms.push(json!([
p.node_id().name(),
p.node_id().instance(),
p.name(),
serialize_atom(v),
]));
}
}
v["atoms"] = atoms;
let mut props = json!([]);
if let Value::Array(props) = &mut props {
for (k, v) in self.properties.iter() {
props.push(json!([k, serialize_atom(v)]));
}
}
v["props"] = props;
let mut cells = json!([]);
if let Value::Array(cells) = &mut cells {
for cell in self.cells.iter() {
cells.push(cell.serialize());
}
}
v["cells"] = cells;
let mut patterns = json!([]);
if let Value::Array(patterns) = &mut patterns {
for p in self.patterns.iter() {
2022-07-17 09:58:28 +00:00
patterns.push(if let Some(p) = p { p.serialize() } else { Value::Null });
}
}
v["patterns"] = patterns;
v.to_string()
}
}
2022-07-17 09:58:28 +00:00
pub fn load_patch_from_file(
matrix: &mut crate::matrix::Matrix,
filepath: &str,
) -> Result<(), MatrixDeserError> {
let mr = MatrixRepr::read_from_file(filepath)?;
matrix.from_repr(&mr)?;
Ok(())
}
2022-07-17 09:58:28 +00:00
pub fn save_patch_to_file(
matrix: &mut crate::matrix::Matrix,
filepath: &str,
) -> std::io::Result<()> {
let mut mr = matrix.to_repr();
mr.write_to_file(filepath)
}
#[cfg(test)]
mod tests {
use super::*;
2022-07-17 09:58:28 +00:00
use crate::matrix::{Cell, Matrix};
#[test]
fn check_empty_repr_serialization() {
let mut matrix_repr = MatrixRepr::empty();
let s = matrix_repr.serialize();
2022-07-17 09:58:28 +00:00
assert_eq!(
s,
"{\"VERSION\":2,\"atoms\":[],\"cells\":[],\"params\":[],\"patterns\":[],\"props\":[]}"
);
assert!(MatrixRepr::deserialize(&s).is_ok());
}
#[test]
fn check_repr_serialization() {
use crate::nodes::new_node_engine;
let (node_conf, mut _node_exec) = new_node_engine();
let mut matrix = Matrix::new(node_conf, 3, 3);
let sin = NodeId::Sin(2);
2022-07-17 09:58:28 +00:00
matrix.place(0, 0, Cell::empty(sin).out(None, Some(0), None));
matrix.place(
1,
0,
Cell::empty(NodeId::Out(0)).input(None, Some(0), None).out(None, None, Some(0)),
);
matrix.sync().unwrap();
let freq_param = sin.inp_param("freq").unwrap();
matrix.set_param(freq_param, SAtom::param(-0.1));
let mut mr = matrix.to_repr();
let s = mr.serialize();
assert_eq!(s,
"{\"VERSION\":2,\"atoms\":[[\"out\",0,\"mono\",[\"i\",0]]],\"cells\":[[\"sin\",2,0,0,[-1,-1,-1],[-1,\"sig\",-1]],[\"out\",0,1,0,[-1,\"ch1\",-1],[-1,-1,-1]]],\"params\":[[\"out\",0,\"ch1\",0.0],[\"out\",0,\"ch2\",0.0],[\"sin\",0,\"det\",0.0],[\"sin\",1,\"det\",0.0],[\"sin\",2,\"det\",0.0],[\"sin\",0,\"freq\",440.0],[\"sin\",1,\"freq\",440.0],[\"sin\",2,\"freq\",220.0],[\"out\",0,\"gain\",1.0]],\"patterns\":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],\"props\":[]}");
let mut mr2 = MatrixRepr::deserialize(&s).unwrap();
let s2 = mr2.serialize();
assert_eq!(s, s2);
}
#[test]
fn check_atom_repr() {
let v = serialize_atom(&SAtom::str("foo"));
assert_eq!(v.to_string(), "[\"s\",\"foo\"]");
let s = serialize_atom(&deserialize_atom(&v).unwrap()).to_string();
assert_eq!(s, v.to_string());
let v = serialize_atom(&SAtom::setting(1337));
assert_eq!(v.to_string(), "[\"i\",1337]");
let s = serialize_atom(&deserialize_atom(&v).unwrap()).to_string();
assert_eq!(s, v.to_string());
let v = serialize_atom(&SAtom::param(1.0));
assert_eq!(v.to_string(), "[\"p\",1.0]");
let s = serialize_atom(&deserialize_atom(&v).unwrap()).to_string();
assert_eq!(s, v.to_string());
2022-07-17 09:58:28 +00:00
let v = serialize_atom(&SAtom::micro(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]));
assert_eq!(v.to_string(), "[\"ms\",1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]");
let s = serialize_atom(&deserialize_atom(&v).unwrap()).to_string();
assert_eq!(s, v.to_string());
2022-07-17 09:58:28 +00:00
let v = serialize_atom(&SAtom::audio(
"lol.wav",
std::sync::Arc::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]),
));
assert_eq!(v.to_string(), "[\"as\",\"lol.wav\"]");
let s = serialize_atom(&deserialize_atom(&v).unwrap()).to_string();
assert_eq!(s, v.to_string());
}
#[test]
fn check_cell_repr() {
2022-07-17 09:58:28 +00:00
let cell = Cell::empty(NodeId::Out(2)).input(Some(2), Some(0), Some(1)).out(
Some(11),
Some(4),
Some(1),
);
let cr = cell.to_repr();
let s = cr.serialize().to_string();
2022-07-17 09:58:28 +00:00
let v: Value = serde_json::from_str(&s).unwrap();
let cr2 = CellRepr::deserialize(&v).unwrap();
let s2 = cr2.serialize().to_string();
assert_eq!(s, s2);
}
#[test]
fn check_file_repr() {
let orig_serial = {
use crate::nodes::new_node_engine;
let (node_conf, mut _node_exec) = new_node_engine();
let mut matrix = Matrix::new(node_conf, 3, 3);
let sin = NodeId::Sin(2);
2022-07-17 09:58:28 +00:00
matrix.place(0, 0, Cell::empty(sin).out(None, Some(0), None));
matrix.place(
1,
0,
Cell::empty(NodeId::Out(0)).input(None, Some(0), None).out(None, None, Some(0)),
);
matrix.sync().unwrap();
let freq_param = sin.inp_param("freq").unwrap();
matrix.set_param(freq_param, SAtom::param(-0.1));
let mut mr = matrix.to_repr();
let s2 = mr.serialize().to_string();
2022-07-17 09:58:28 +00:00
save_patch_to_file(&mut matrix, "hexosynth_test_patch.hxy").unwrap();
s2
};
{
use crate::nodes::new_node_engine;
let (node_conf, mut _node_exec) = new_node_engine();
let mut matrix = Matrix::new(node_conf, 3, 3);
2022-07-17 09:58:28 +00:00
load_patch_from_file(&mut matrix, "hexosynth_test_patch.hxy").unwrap();
let mut mr = matrix.to_repr();
let s = mr.serialize().to_string();
assert_eq!(s, orig_serial);
}
}
#[test]
fn check_matrix_track_repr() {
use crate::dsp::tracker::UIPatternModel;
let orig_serial = {
use crate::nodes::new_node_engine;
let (node_conf, mut _node_exec) = new_node_engine();
let mut matrix = Matrix::new(node_conf, 3, 3);
let ts = NodeId::TSeq(0);
2022-07-17 09:58:28 +00:00
matrix.place(0, 0, Cell::empty(ts).out(None, Some(0), None));
matrix.sync().unwrap();
{
let pat_ref = matrix.get_pattern_data(0).unwrap();
let mut pat = pat_ref.lock().unwrap();
for col in 0..MAX_COLS {
pat.set_col_note_type(col);
for v in 1..(MAX_PATTERN_LEN + 1) {
pat.set_cell_value(v - 1, col, v as u16);
}
pat.set_cursor(16, 3);
pat.set_edit_step(5);
pat.set_rows(133);
}
}
let mut mr = matrix.to_repr();
let s2 = mr.serialize().to_string();
2022-07-17 09:58:28 +00:00
save_patch_to_file(&mut matrix, "hexosynth_test_patch_2.hxy").unwrap();
s2
};
{
use crate::nodes::new_node_engine;
let (node_conf, mut _node_exec) = new_node_engine();
let mut matrix = Matrix::new(node_conf, 3, 3);
2022-07-17 09:58:28 +00:00
load_patch_from_file(&mut matrix, "hexosynth_test_patch_2.hxy").unwrap();
let mut mr = matrix.to_repr();
let s = mr.serialize().to_string();
assert_eq!(s, orig_serial);
let pat_ref = matrix.get_pattern_data(0).unwrap();
let mut pat = pat_ref.lock().unwrap();
for col in 0..MAX_COLS {
assert!(pat.is_col_note(col));
for v in 1..(MAX_PATTERN_LEN + 1) {
assert_eq!(pat.get_cell_value(v - 1, col), v as u16);
}
assert_eq!(pat.get_cursor(), (16, 3));
assert_eq!(pat.get_edit_step(), 5);
assert_eq!(pat.rows(), 133);
}
}
}
2021-07-10 15:36:20 +00:00
#[test]
fn check_matrix_repr_version_1_load() {
use crate::nodes::new_node_engine;
let s =
"{\"VERSION\":1,\"atoms\":[[\"out\",0,\"mono\",[\"i\",0]]],\"cells\":[[\"sin\",2,0,0,[-1,-1,-1],[-1,\"sig\",-1]],[\"out\",0,1,0,[-1,\"ch1\",-1],[-1,-1,-1]]],\"params\":[[\"out\",0,\"ch1\",0.0],[\"out\",0,\"ch2\",0.0],[\"sin\",0,\"det\",0.0],[\"sin\",1,\"det\",0.0],[\"sin\",2,\"det\",0.0],[\"sin\",0,\"freq\",0.0],[\"sin\",1,\"freq\",0.0],[\"sin\",2,\"freq\",-0.10000000149011612],[\"out\",0,\"gain\",0.5]],\"patterns\":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],\"props\":[]}";
{
let (node_conf, mut _node_exec) = new_node_engine();
let mut matrix = Matrix::new(node_conf, 3, 3);
let mr = MatrixRepr::deserialize(&s).unwrap();
matrix.from_repr(&mr).unwrap();
let mut v = std::collections::HashMap::new();
2022-07-04 03:14:53 +00:00
matrix.for_each_atom(|unique_idx, param_id, atom, _modamt| {
v.insert(
format!("{}_{}", unique_idx, param_id.name().to_string()),
2022-07-17 09:58:28 +00:00
param_id.denorm(atom.f()),
);
});
assert_eq!(*v.get("0_freq").unwrap(), 440.0);
assert_eq!(*v.get("1_freq").unwrap(), 440.0);
assert_eq!(*v.get("2_freq").unwrap(), 220.0);
assert_eq!(*v.get("0_det").unwrap(), 0.0);
}
}
#[test]
fn check_matrix_repr_version_2_load() {
use crate::nodes::new_node_engine;
let s =
"{\"VERSION\":2,\"atoms\":[[\"out\",0,\"mono\",[\"i\",0]]],\"cells\":[[\"sin\",2,0,0,[-1,-1,-1],[-1,\"sig\",-1]],[\"out\",0,1,0,[-1,\"ch1\",-1],[-1,-1,-1]]],\"params\":[[\"out\",0,\"ch1\",0.0],[\"out\",0,\"ch2\",0.0],[\"sin\",0,\"det\",0.0],[\"sin\",1,\"det\",0.0],[\"sin\",2,\"det\",0.0],[\"sin\",0,\"freq\",440.0],[\"sin\",1,\"freq\",441.0],[\"sin\",2,\"freq\",220.0],[\"out\",0,\"gain\",0.5]],\"patterns\":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],\"props\":[]}";
{
let (node_conf, mut _node_exec) = new_node_engine();
let mut matrix = Matrix::new(node_conf, 3, 3);
let mr = MatrixRepr::deserialize(&s).unwrap();
matrix.from_repr(&mr).unwrap();
let mut v = std::collections::HashMap::new();
2022-07-04 03:14:53 +00:00
matrix.for_each_atom(|unique_idx, param_id, atom, _modamt| {
v.insert(
format!("{}_{}", unique_idx, param_id.name().to_string()),
2022-07-17 09:58:28 +00:00
param_id.denorm(atom.f()),
);
});
assert_eq!(*v.get("0_freq").unwrap(), 440.0);
assert_eq!(*v.get("1_freq").unwrap(), 441.0);
assert_eq!(*v.get("2_freq").unwrap(), 220.0);
assert_eq!(*v.get("0_det").unwrap(), 0.0);
}
}
2021-07-10 15:36:20 +00:00
#[test]
fn check_matrix_repr_mod_amt_1() {
use crate::nodes::new_node_engine;
let s = {
2021-07-10 15:36:20 +00:00
let (node_conf, mut _node_exec) = new_node_engine();
let mut matrix = Matrix::new(node_conf, 3, 3);
let sin = NodeId::Sin(0);
2022-07-17 09:58:28 +00:00
matrix.place(0, 0, Cell::empty(sin).out(None, Some(0), None));
matrix.place(
1,
0,
Cell::empty(NodeId::Out(0)).input(None, Some(0), None).out(None, None, Some(0)),
);
matrix.set_param_modamt(sin.inp_param("det").unwrap(), Some(-0.6)).unwrap();
2021-07-10 15:36:20 +00:00
matrix.sync().unwrap();
2022-07-17 09:58:28 +00:00
matrix.set_param_modamt(sin.inp_param("freq").unwrap(), Some(0.6)).unwrap();
2021-07-10 15:36:20 +00:00
let mut mr = matrix.to_repr();
mr.serialize().to_string()
2021-07-10 15:36:20 +00:00
};
{
let (node_conf, mut _node_exec) = new_node_engine();
let mut matrix = Matrix::new(node_conf, 3, 3);
let mr = MatrixRepr::deserialize(&s).unwrap();
2021-07-10 15:36:20 +00:00
matrix.from_repr(&mr).unwrap();
let mut v = std::collections::HashMap::new();
matrix.for_each_atom(|_unique_idx, param_id, _atom, modamt| {
v.insert(param_id.name().to_string(), modamt);
});
assert_eq!(*v.get("freq").unwrap(), Some(0.6));
assert_eq!(*v.get("det").unwrap(), Some(-0.6));
}
}
#[test]
fn check_matrix_repr_properties() {
use crate::nodes::new_node_engine;
let s = {
let (node_conf, mut _node_exec) = new_node_engine();
let mut matrix = Matrix::new(node_conf, 3, 3);
matrix.set_prop("test", SAtom::setting(31337));
let mut mr = matrix.to_repr();
mr.serialize().to_string()
};
{
let (node_conf, mut _node_exec) = new_node_engine();
let mut matrix = Matrix::new(node_conf, 3, 3);
let mr = MatrixRepr::deserialize(&s).unwrap();
matrix.from_repr(&mr).unwrap();
assert_eq!(matrix.get_prop("test").unwrap().i(), 31337);
}
}
#[test]
fn check_matrix_repr_old_format2new() {
2022-07-17 09:58:28 +00:00
let old_format = "{\"VERSION\":1,\"atoms\":[[\"out\",0,\"mono\",[\"i\",0]]],\
\"cells\":[[\"sin\",2,0,0,[-1,-1,-1],[-1,0,-1]],[\"out\",0,1,0,\
[-1,0,-1],[-1,-1,0]]],\"params\":[[\"out\",0,\"ch1\",0.0],\
[\"out\",0,\"ch2\",0.0],[\"sin\",0,\"det\",0.0],[\"sin\",1,\
\"det\",0.0],[\"sin\",2,\"det\",0.0],[\"sin\",0,\"freq\",0.0],\
[\"sin\",1,\"freq\",0.0],[\"sin\",2,\"freq\",\
-0.10000000149011612],[\"out\",0,\"gain\",0.5]],\"patterns\":\
[null,null,null,null,null,null,null,null,null,null,null,null,\
null,null,null,null,null,null,null,null,null,null,null,null,\
null,null,null,null,null,null,null,null,null,null,null,null,\
null,null,null,null,null,null,null,null,null,null,null,null,\
null,null,null,null,null,null,null,null,null,null,null,null,\
null,null,null,null,null,null,null,null,null,null,null,null,\
null,null,null,null,null,null,null,null,null,null,null,null,\
null,null,null,null,null,null,null,null,null,null,null,null,\
null,null,null,null,null,null,null,null,null,null,null,null,\
null,null,null,null,null,null,null,null,null,null,null,null,\
null,null,null,null,null,null,null,null],\"props\":[]}";
let mut mr = MatrixRepr::deserialize(old_format).unwrap();
let new_format = mr.serialize().to_string();
assert_eq!(new_format,
"{\"VERSION\":1,\"atoms\":[[\"out\",0,\"mono\",[\"i\",0]]],\"cells\":[[\"sin\",2,0,\
0,[-1,-1,-1],[-1,\"sig\",-1]],[\"out\",0,1,0,[-1,\"ch1\",-1],[-1,-1,-1]]],\"params\":[[\"o\
ut\",0,\"ch1\",0.0],[\"out\",0,\"ch2\",0.0],[\"sin\",0,\"det\",0.0],[\"sin\",1,\"det\",0.0],\
[\"sin\",2,\"det\",0.0],[\"sin\",0,\"freq\",0.0],[\"sin\",1,\"freq\",0.0],[\"sin\",2,\"freq\
\",-0.10000000149011612],[\"out\",0,\"gain\",0.5]],\"patterns\":[null,null,null,null,null,nul\
l,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,\
null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,nu\
ll,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null\
,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,n\
ull,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,nul\
l,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,\
null,null,null,null,null,null,null,null,null,null,null,null],\"props\":[]}");
}
}