Added TDD test for blocklang
This commit is contained in:
parent
f5f242041a
commit
9b0f93c92b
3 changed files with 129 additions and 2 deletions
|
@ -10,6 +10,7 @@ pub use crate::nodes::MinMaxMonitorSamples;
|
|||
use crate::nodes::{NodeConfigurator, NodeGraphOrdering, NodeProg, MAX_ALLOCATED_NODES};
|
||||
pub use crate::CellDir;
|
||||
use crate::ScopeHandle;
|
||||
use crate::blocklang::BlockFun;
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
|
@ -578,20 +579,37 @@ impl Matrix {
|
|||
self.config.filtered_out_fb_for(ni, out)
|
||||
}
|
||||
|
||||
/// Retrieve the oscilloscope handle for the scope index `scope`.
|
||||
pub fn get_pattern_data(&self, tracker_id: usize) -> Option<Arc<Mutex<PatternData>>> {
|
||||
self.config.get_pattern_data(tracker_id)
|
||||
}
|
||||
|
||||
/// Retrieve a handle to the tracker pattern data of the tracker `tracker_id`.
|
||||
pub fn get_scope_handle(&self, scope: usize) -> Option<Arc<ScopeHandle>> {
|
||||
self.config.get_scope_handle(scope)
|
||||
}
|
||||
|
||||
/// Checks if pattern data updates need to be sent to the
|
||||
/// DSP thread.
|
||||
/// Checks if there are any updates to send for the pattern data that belongs to the
|
||||
/// tracker `tracker_id`. Call this repeatedly, eg. once per frame in a GUI, in case the user
|
||||
/// modified the pattern data. It will make sure that the modifications are sent to the
|
||||
/// audio thread.
|
||||
pub fn check_pattern_data(&mut self, tracker_id: usize) {
|
||||
self.config.check_pattern_data(tracker_id)
|
||||
}
|
||||
|
||||
/// Checks the block function for the id `id`. If the block function did change,
|
||||
/// updates are then sent to the audio thread.
|
||||
/// See also [get_block_function].
|
||||
pub fn check_block_function(&mut self, id: usize) {
|
||||
self.config.check_block_function(id)
|
||||
}
|
||||
|
||||
/// Retrieve a handle to the block function `id`. In case you modify the block function,
|
||||
/// make sure to call [check_block_function].
|
||||
pub fn get_block_function(&mut self, id: usize) -> Option<Arc<Mutex<BlockFun>>> {
|
||||
self.config.get_block_function(id)
|
||||
}
|
||||
|
||||
/// Saves the state of the hexagonal grid layout.
|
||||
/// This is usually used together with [Matrix::check]
|
||||
/// and [Matrix::restore_matrix] to try if changes on
|
||||
|
|
|
@ -6,6 +6,8 @@ use super::{
|
|||
FeedbackFilter, GraphMessage, NodeOp, NodeProg, MAX_ALLOCATED_NODES, MAX_AVAIL_CODE_ENGINES,
|
||||
MAX_AVAIL_TRACKERS, MAX_INPUTS, MAX_SCOPES, UNUSED_MONITOR_IDX,
|
||||
};
|
||||
use crate::blocklang::*;
|
||||
use crate::blocklang_def;
|
||||
use crate::dsp::tracker::{PatternData, Tracker};
|
||||
use crate::dsp::{node_factory, Node, NodeId, NodeInfo, ParamId, SAtom};
|
||||
use crate::monitor::{new_monitor_processor, MinMaxMonitorSamples, Monitor, MON_SIG_CNT};
|
||||
|
@ -185,6 +187,10 @@ pub struct NodeConfigurator {
|
|||
/// Holding the WBlockDSP code engine backends:
|
||||
#[cfg(feature = "synfx-dsp-jit")]
|
||||
pub(crate) code_engines: Vec<CodeEngine>,
|
||||
/// Holds the block functions that are JIT compiled to DSP code
|
||||
/// for the `Code` nodes. The code is then sent via the [CodeEngine]
|
||||
/// in [check_block_function].
|
||||
pub(crate) block_functions: Vec<(u64, Arc<Mutex<BlockFun>>)>,
|
||||
/// The shared parts of the [NodeConfigurator]
|
||||
/// and the [crate::nodes::NodeExecutor].
|
||||
pub(crate) shared: SharedNodeConf,
|
||||
|
@ -274,6 +280,12 @@ impl NodeConfigurator {
|
|||
let mut scopes = vec![];
|
||||
scopes.resize_with(MAX_SCOPES, || ScopeHandle::new_shared());
|
||||
|
||||
let lang = blocklang_def::setup_hxdsp_block_language();
|
||||
let mut block_functions = vec![];
|
||||
block_functions.resize_with(MAX_AVAIL_CODE_ENGINES, || {
|
||||
(0, Arc::new(Mutex::new(BlockFun::new(lang.clone()))))
|
||||
});
|
||||
|
||||
(
|
||||
NodeConfigurator {
|
||||
nodes,
|
||||
|
@ -292,6 +304,7 @@ impl NodeConfigurator {
|
|||
trackers: vec![Tracker::new(); MAX_AVAIL_TRACKERS],
|
||||
#[cfg(feature = "synfx-dsp-jit")]
|
||||
code_engines: vec![CodeEngine::new(); MAX_AVAIL_CODE_ENGINES],
|
||||
block_functions,
|
||||
scopes,
|
||||
},
|
||||
shared_exec,
|
||||
|
@ -652,10 +665,12 @@ impl NodeConfigurator {
|
|||
}
|
||||
}
|
||||
|
||||
/// Retrieve the oscilloscope handle for the scope index `scope`.
|
||||
pub fn get_scope_handle(&self, scope: usize) -> Option<Arc<ScopeHandle>> {
|
||||
self.scopes.get(scope).cloned()
|
||||
}
|
||||
|
||||
/// Retrieve a handle to the tracker pattern data of the tracker `tracker_id`.
|
||||
pub fn get_pattern_data(&self, tracker_id: usize) -> Option<Arc<Mutex<PatternData>>> {
|
||||
if tracker_id >= self.trackers.len() {
|
||||
return None;
|
||||
|
@ -664,6 +679,10 @@ impl NodeConfigurator {
|
|||
Some(self.trackers[tracker_id].data())
|
||||
}
|
||||
|
||||
/// Checks if there are any updates to send for the pattern data that belongs to the
|
||||
/// tracker `tracker_id`. Call this repeatedly, eg. once per frame in a GUI, in case the user
|
||||
/// modified the pattern data. It will make sure that the modifications are sent to the
|
||||
/// audio thread.
|
||||
pub fn check_pattern_data(&mut self, tracker_id: usize) {
|
||||
if tracker_id >= self.trackers.len() {
|
||||
return;
|
||||
|
@ -672,6 +691,41 @@ impl NodeConfigurator {
|
|||
self.trackers[tracker_id].send_one_update();
|
||||
}
|
||||
|
||||
/// Checks the block function for the id `id`. If the block function did change,
|
||||
/// updates are then sent to the audio thread.
|
||||
/// See also [get_block_function].
|
||||
pub fn check_block_function(&mut self, id: usize) {
|
||||
if let Some((generation, block_fun)) = self.block_functions.get_mut(id) {
|
||||
if let Ok(block_fun) = block_fun.lock() {
|
||||
if *generation != block_fun.generation() {
|
||||
*generation = block_fun.generation();
|
||||
// let ast = block_compiler::compile(block_fun);
|
||||
if let Some(cod) = self.code_engines.get_mut(id) {
|
||||
use synfx_dsp_jit::build::*;
|
||||
cod.upload(stmts(&[
|
||||
assign(
|
||||
"*phase",
|
||||
op_add(var("*phase"), op_mul(literal(440.0), var("israte"))),
|
||||
),
|
||||
_if(
|
||||
op_gt(var("*phase"), literal(1.0)),
|
||||
assign("*phase", op_sub(var("*phase"), literal(1.0))),
|
||||
None,
|
||||
),
|
||||
var("*phase"),
|
||||
]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve a handle to the block function `id`. In case you modify the block function,
|
||||
/// make sure to call [check_block_function].
|
||||
pub fn get_block_function(&mut self, id: usize) -> Option<Arc<Mutex<BlockFun>>> {
|
||||
self.block_functions.get(id).map(|pair| pair.1.clone())
|
||||
}
|
||||
|
||||
pub fn delete_nodes(&mut self) {
|
||||
self.node2idx.clear();
|
||||
self.nodes.fill_with(|| (NodeInfo::from_node_id(NodeId::Nop), None));
|
||||
|
|
55
tests/blocklang.rs
Normal file
55
tests/blocklang.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Copyright (c) 2022 Weird Constructor <weirdconstructor@gmail.com>
|
||||
// This file is a part of HexoDSP. Released under GPL-3.0-or-later.
|
||||
// See README.md and COPYING for details.
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
|
||||
#[test]
|
||||
fn check_blocklang_1() {
|
||||
let (node_conf, mut node_exec) = new_node_engine();
|
||||
let mut matrix = Matrix::new(node_conf, 3, 3);
|
||||
|
||||
let mut chain = MatrixCellChain::new(CellDir::B);
|
||||
chain
|
||||
.node_out("code", "sig1")
|
||||
.set_denorm("in1", 0.5)
|
||||
.set_denorm("in2", -0.6)
|
||||
.node_inp("out", "ch1")
|
||||
.place(&mut matrix, 0, 0)
|
||||
.unwrap();
|
||||
matrix.sync().unwrap();
|
||||
|
||||
let code = NodeId::Code(0);
|
||||
|
||||
let block_fun = matrix.get_block_function(0).expect("block fun exists");
|
||||
{
|
||||
let mut block_fun = block_fun.lock().expect("matrix lock");
|
||||
|
||||
block_fun.instanciate_at(0, 0, 0, "get", Some("in1".to_string()));
|
||||
block_fun.instanciate_at(0, 0, 1, "get", Some("in1".to_string()));
|
||||
block_fun.instanciate_at(0, 1, 0, "+", None);
|
||||
block_fun.instanciate_at(0, 0, 1, "set", Some("&sig1".to_string()));
|
||||
}
|
||||
|
||||
matrix.check_block_function(0);
|
||||
|
||||
let res = run_for_ms(&mut node_exec, 25.0);
|
||||
assert_decimated_feq!(
|
||||
res.0,
|
||||
50,
|
||||
vec![
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
]
|
||||
);
|
||||
}
|
Loading…
Reference in a new issue