Improved documentation of MatrixCellChain
This commit is contained in:
parent
eff41e7ad5
commit
ed1ac581ce
5 changed files with 66 additions and 69 deletions
|
@ -1,6 +1,28 @@
|
||||||
// Copyright (c) 2021-2022 Weird Constructor <weirdconstructor@gmail.com>
|
// Copyright (c) 2021-2022 Weird Constructor <weirdconstructor@gmail.com>
|
||||||
// This file is a part of HexoDSP. Released under GPL-3.0-or-later.
|
// This file is a part of HexoDSP. Released under GPL-3.0-or-later.
|
||||||
// See README.md and COPYING for details.
|
// See README.md and COPYING for details.
|
||||||
|
/*! Defines an API for easy DSP chain building with the hexagonal [crate::Matrix].
|
||||||
|
|
||||||
|
The [crate::MatrixCellChain] abstractions allows very easy placement of DSP signal chains:
|
||||||
|
|
||||||
|
```
|
||||||
|
use hexodsp::*;
|
||||||
|
let mut chain = MatrixCellChain::new(CellDir::BR);
|
||||||
|
chain.node_out("sin", "sig")
|
||||||
|
.set_denorm("freq", 220.0)
|
||||||
|
.node_io("amp", "inp", "sig")
|
||||||
|
.set_denorm("att", 0.5)
|
||||||
|
.node_inp("out", "ch1");
|
||||||
|
|
||||||
|
// use crate::nodes::new_node_engine;
|
||||||
|
let (node_conf, _node_exec) = new_node_engine();
|
||||||
|
let mut matrix = Matrix::new(node_conf, 7, 7);
|
||||||
|
|
||||||
|
chain.place(&mut matrix, 2, 2).expect("no error in this case");
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
use crate::{Cell, CellDir, Matrix, NodeId, ParamId, SAtom};
|
use crate::{Cell, CellDir, Matrix, NodeId, ParamId, SAtom};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
@ -12,16 +34,16 @@ struct MatrixChainLink {
|
||||||
params: Vec<(ParamId, SAtom)>,
|
params: Vec<(ParamId, SAtom)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A DSP chain builder for the [hexodsp::Matrix].
|
/// A DSP chain builder for the [crate::Matrix].
|
||||||
///
|
///
|
||||||
/// This is an extremely easy API to create and place new DSP chains into the [hexodsp::Matrix].
|
/// This is an extremely easy API to create and place new DSP chains into the [crate::Matrix].
|
||||||
/// It can be used by frontends to place DSP chains on user request or it can be used
|
/// It can be used by frontends to place DSP chains on user request or it can be used
|
||||||
/// by test cases to quickly fill the hexagonal Matrix.
|
/// by test cases to quickly fill the hexagonal Matrix.
|
||||||
///
|
///
|
||||||
///```
|
///```
|
||||||
/// use hexodsp::*;
|
/// use hexodsp::*;
|
||||||
/// let mut chain = MatrixCellChain::new(CellDir::BR);
|
/// let mut chain = MatrixCellChain::new(CellDir::BR);
|
||||||
/// chain.node_out("sin")
|
/// chain.node_out("sin", "sig")
|
||||||
/// .set_denorm("freq", 220.0)
|
/// .set_denorm("freq", 220.0)
|
||||||
/// .node_io("amp", "inp", "sig")
|
/// .node_io("amp", "inp", "sig")
|
||||||
/// .set_denorm("att", 0.5)
|
/// .set_denorm("att", 0.5)
|
||||||
|
@ -42,6 +64,7 @@ pub struct MatrixCellChain {
|
||||||
param_idx: usize,
|
param_idx: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Error type for the [crate::MatrixCellChain].
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ChainError {
|
pub enum ChainError {
|
||||||
UnknownOutput(NodeId, String),
|
UnknownOutput(NodeId, String),
|
||||||
|
@ -122,14 +145,14 @@ impl MatrixCellChain {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Utility function for creating [hexodsp::Cell] for this chain.
|
/// Utility function for creating [crate::Cell] for this chain.
|
||||||
pub fn spawn_cell_from_node_id_name(&mut self, node_id: &str) -> Cell {
|
pub fn spawn_cell_from_node_id_name(&mut self, node_id: &str) -> Cell {
|
||||||
let node_id = NodeId::from_str(node_id);
|
let node_id = NodeId::from_str(node_id);
|
||||||
|
|
||||||
Cell::empty(node_id)
|
Cell::empty(node_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Utility function to add a pre-built [hexodsp::Cell] as next link.
|
/// Utility function to add a pre-built [crate::Cell] as next link.
|
||||||
///
|
///
|
||||||
/// This also sets the current parameter cell.
|
/// This also sets the current parameter cell.
|
||||||
pub fn add_link(&mut self, cell: Cell) {
|
pub fn add_link(&mut self, cell: Cell) {
|
||||||
|
|
|
@ -366,12 +366,13 @@ The start of your `tests/node_*.rs` file usually should look like this:
|
||||||
let (node_conf, mut node_exec) = new_node_engine();
|
let (node_conf, mut node_exec) = new_node_engine();
|
||||||
let mut matrix = Matrix::new(node_conf, 3, 3);
|
let mut matrix = Matrix::new(node_conf, 3, 3);
|
||||||
|
|
||||||
let ad = NodeId::Ad(0);
|
let mut chain = MatrixCellChain::new(CellDir::B);
|
||||||
let out = NodeId::Out(0);
|
chain.node_out("ad", "sig")
|
||||||
matrix.place(0, 0, Cell::empty(ad).out(None, None, ad.out("sig")));
|
.node_inp("out", "ch1")
|
||||||
matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None));
|
.place(&mut matrix, 0, 0).unwrap();
|
||||||
matrix.sync().unwrap();
|
matrix.sync().unwrap();
|
||||||
|
|
||||||
|
let ad = NodeId::Ad(0);
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -393,81 +394,50 @@ The two parameters to _new_ are the width and height of the hex grid.
|
||||||
let mut matrix = Matrix::new(node_conf, 3, 3);
|
let mut matrix = Matrix::new(node_conf, 3, 3);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Next step is to create a DSP chain of nodes and place that onto the hexagonal matrix.
|
||||||
|
Luckily a simpler API has been created with the [crate::MatrixCellChain], that lets
|
||||||
|
you build DSP chains on the fly using only names of the nodes and the corresponding
|
||||||
|
input/output ports:
|
||||||
|
|
||||||
|
```ignore
|
||||||
|
// Create a new cell chain that points in to the given direction (CellDir::B => to bottom).
|
||||||
|
let mut chain = MatrixCellChain::new(CellDir::B);
|
||||||
|
chain.node_out("ad", "sig") // Add a Node::Ad(0) cell, with the "sig" output set
|
||||||
|
.node_inp("out", "ch1") // Add a Node::Out(0) cell, with the "ch1" input set
|
||||||
|
.place(&mut matrix, 0, 0).unwrap();
|
||||||
|
```
|
||||||
|
|
||||||
|
After placing the new cells, we need to synchronize it with the audio backend:
|
||||||
|
|
||||||
|
```ignore
|
||||||
|
matrix.sync().unwrap();
|
||||||
|
```
|
||||||
|
|
||||||
|
The `sync` is necessary to update the DSP graph.
|
||||||
|
|
||||||
Next you usually want to define short variable names for the [NodeId] that refer to the DSP
|
Next you usually want to define short variable names for the [NodeId] that refer to the DSP
|
||||||
node instances:
|
node instances:
|
||||||
|
|
||||||
```ignore
|
```ignore
|
||||||
let ad = NodeId::Ad(0);
|
let ad = NodeId::Ad(0);
|
||||||
let out = NodeId::Out(0);
|
|
||||||
```
|
|
||||||
|
|
||||||
You can have multiple instances for a node. The number in the parenthesis are
|
|
||||||
the instance index of that node.
|
|
||||||
|
|
||||||
Next you want to layout the nodes adjacent to each other on the hexagonal grid.
|
|
||||||
This is a bit more tricky than with a rectangular grid.
|
|
||||||
|
|
||||||
```ignore
|
|
||||||
matrix.place(0, 0, Cell::empty(ad).out(None, None, ad.out("sig")));
|
|
||||||
matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None));
|
|
||||||
matrix.sync().unwrap();
|
|
||||||
```
|
|
||||||
|
|
||||||
The `sync` is necessary to update the DSP graph.
|
|
||||||
When doing this, keep the following grid layout in mind:
|
|
||||||
|
|
||||||
```text
|
|
||||||
_____ _____
|
|
||||||
/ \ / \
|
|
||||||
/ 0,0 \_____/ 2,0 \_____
|
|
||||||
\ / \ / \
|
|
||||||
\_____/ 1,0 \_____/ 3,0 \
|
|
||||||
/ \ / \ /
|
|
||||||
/ 0,1 \_____/ 2,1 \_____/
|
|
||||||
\ / \ / \
|
|
||||||
\_____/ 1,1 \_____/ 3,1 \
|
|
||||||
/ \ / \ /
|
|
||||||
/ 0,2 \_____/ 2,2 \_____/
|
|
||||||
\ / \ /
|
|
||||||
\_____/ 1,2 \_____/
|
|
||||||
\ /
|
|
||||||
\_____/
|
|
||||||
```
|
|
||||||
|
|
||||||
Defining the outputs of a cell is done like this:
|
|
||||||
|
|
||||||
```ignore
|
|
||||||
Cell::empty(ad).out(None, None, ad.out("sig"))
|
|
||||||
```
|
|
||||||
|
|
||||||
[crate::Cell::empty] takes a [NodeId] as first argument. The [crate::Cell]
|
|
||||||
structure then allows you to specify the output ports using the [crate::Cell::out]
|
|
||||||
function. The 3 arguments of that function are for the 3 edges of that hex tile:
|
|
||||||
|
|
||||||
```ignore
|
|
||||||
// TopRight BottomRight Bottom
|
|
||||||
Cell::empty(ad).out(None, None, ad.out("sig"))
|
|
||||||
```
|
|
||||||
|
|
||||||
[crate::Cell::input] works the same way, but the 3 arguments refer to the 3 input
|
|
||||||
edges of a hex tile:
|
|
||||||
|
|
||||||
```ignore
|
|
||||||
// Top TopLeft BottomLeft
|
|
||||||
Cell::empty(out).input(out.inp("ch1"), None, None)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The [NodeId] interface offers you functions to get the input parameter index from
|
The [NodeId] interface offers you functions to get the input parameter index from
|
||||||
a name like `out.inp("ch1")` or the output port index from a name: `ad.out("sig")`.
|
a name like `out.inp("ch1")` or the output port index from a name: `ad.out("sig")`.
|
||||||
|
You can have multiple instances for a node. The number in the parenthesis are
|
||||||
|
the instance index of that node.
|
||||||
|
|
||||||
After you have setup everything for the test, you usually want to modify a paramter
|
After you have setup everything for the test, you usually want to modify a paramter
|
||||||
and look at the values the graph returns.
|
and look at the values the graph returns.
|
||||||
|
|
||||||
|
|
||||||
```ignore
|
```ignore
|
||||||
#[test]
|
#[test]
|
||||||
fn check_node_ad_1() {
|
fn check_node_ad_1() {
|
||||||
|
// ...
|
||||||
// matrix setup code above
|
// matrix setup code above
|
||||||
|
// ...
|
||||||
|
|
||||||
|
let ad = NodeId::Ad(0);
|
||||||
|
|
||||||
// Fetch parameter id:
|
// Fetch parameter id:
|
||||||
let trig_p = ad.inp_param("trig").unwrap();
|
let trig_p = ad.inp_param("trig").unwrap();
|
||||||
|
|
|
@ -295,6 +295,7 @@ pub use matrix_repr::load_patch_from_file;
|
||||||
pub use matrix_repr::save_patch_to_file;
|
pub use matrix_repr::save_patch_to_file;
|
||||||
pub use nodes::{new_node_engine, NodeConfigurator, NodeExecutor};
|
pub use nodes::{new_node_engine, NodeConfigurator, NodeExecutor};
|
||||||
pub use sample_lib::{SampleLibrary, SampleLoadError};
|
pub use sample_lib::{SampleLibrary, SampleLoadError};
|
||||||
|
pub use chain_builder::MatrixCellChain;
|
||||||
|
|
||||||
pub struct Context<'a, 'b, 'c, 'd> {
|
pub struct Context<'a, 'b, 'c, 'd> {
|
||||||
pub nframes: usize,
|
pub nframes: usize,
|
||||||
|
|
|
@ -6,6 +6,7 @@ pub use hexodsp::dsp::*;
|
||||||
pub use hexodsp::matrix::*;
|
pub use hexodsp::matrix::*;
|
||||||
pub use hexodsp::nodes::new_node_engine;
|
pub use hexodsp::nodes::new_node_engine;
|
||||||
pub use hexodsp::NodeExecutor;
|
pub use hexodsp::NodeExecutor;
|
||||||
|
pub use hexodsp::MatrixCellChain;
|
||||||
|
|
||||||
use hound;
|
use hound;
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,10 @@ fn check_node_ad_1() {
|
||||||
let (node_conf, mut node_exec) = new_node_engine();
|
let (node_conf, mut node_exec) = new_node_engine();
|
||||||
let mut matrix = Matrix::new(node_conf, 3, 3);
|
let mut matrix = Matrix::new(node_conf, 3, 3);
|
||||||
|
|
||||||
let mut chain = hexodsp::chain_builder::MatrixCellChain::new(CellDir::B);
|
let mut chain = MatrixCellChain::new(CellDir::B);
|
||||||
chain.node_out("ad", "sig").node_inp("out", "ch1").place(&mut matrix, 0, 0).unwrap();
|
chain.node_out("ad", "sig")
|
||||||
|
.node_inp("out", "ch1")
|
||||||
|
.place(&mut matrix, 0, 0).unwrap();
|
||||||
matrix.sync().unwrap();
|
matrix.sync().unwrap();
|
||||||
|
|
||||||
let ad = NodeId::Ad(0);
|
let ad = NodeId::Ad(0);
|
||||||
|
|
Loading…
Reference in a new issue