Refactored WBlockDSP into it's own sub module and removed the old wblockdsp.rs

This commit is contained in:
Weird Constructor 2022-08-06 09:28:30 +02:00
parent 4c5d832036
commit 87104ded31
13 changed files with 119 additions and 398 deletions

View file

@ -5,7 +5,7 @@
use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom};
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
#[cfg(feature = "synfx-dsp-jit")] #[cfg(feature = "synfx-dsp-jit")]
use crate::wblockdsp::CodeEngineBackend; use synfx_dsp_jit::engine::CodeEngineBackend;
//use crate::dsp::MAX_BLOCK_SIZE; //use crate::dsp::MAX_BLOCK_SIZE;

View file

@ -321,11 +321,7 @@ pub mod monitor;
pub mod nodes; pub mod nodes;
pub mod sample_lib; pub mod sample_lib;
pub mod scope_handle; pub mod scope_handle;
#[cfg(feature="synfx-dsp-jit")]
pub mod wblockdsp; pub mod wblockdsp;
pub mod blocklang;
pub mod blocklang_def;
mod block_compiler;
mod util; mod util;
pub use cell_dir::CellDir; pub use cell_dir::CellDir;

View file

@ -10,8 +10,7 @@ pub use crate::nodes::MinMaxMonitorSamples;
use crate::nodes::{NodeConfigurator, NodeGraphOrdering, NodeProg, MAX_ALLOCATED_NODES}; use crate::nodes::{NodeConfigurator, NodeGraphOrdering, NodeProg, MAX_ALLOCATED_NODES};
pub use crate::CellDir; pub use crate::CellDir;
use crate::ScopeHandle; use crate::ScopeHandle;
use crate::blocklang::{BlockFun, BlockFunSnapshot}; use crate::wblockdsp::{BlockFun, BlockFunSnapshot, BlkJITCompileError};
use crate::block_compiler::BlkJITCompileError;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
@ -600,13 +599,13 @@ impl Matrix {
/// Checks the block function for the id `id`. If the block function did change, /// Checks the block function for the id `id`. If the block function did change,
/// updates are then sent to the audio thread. /// updates are then sent to the audio thread.
/// See also [get_block_function]. /// See also [Matrix::get_block_function].
pub fn check_block_function(&mut self, id: usize) -> Result<(), BlkJITCompileError> { pub fn check_block_function(&mut self, id: usize) -> Result<(), BlkJITCompileError> {
self.config.check_block_function(id) self.config.check_block_function(id)
} }
/// Retrieve a handle to the block function `id`. In case you modify the block function, /// Retrieve a handle to the block function `id`. In case you modify the block function,
/// make sure to call [check_block_function]. /// make sure to call [Matrix::check_block_function].
pub fn get_block_function(&self, id: usize) -> Option<Arc<Mutex<BlockFun>>> { pub fn get_block_function(&self, id: usize) -> Option<Arc<Mutex<BlockFun>>> {
self.config.get_block_function(id) self.config.get_block_function(id)
} }

View file

@ -4,7 +4,7 @@
use crate::dsp::{NodeId, ParamId, SAtom}; use crate::dsp::{NodeId, ParamId, SAtom};
use serde_json::{json, Value}; use serde_json::{json, Value};
use crate::blocklang::BlockFunSnapshot; use crate::wblockdsp::BlockFunSnapshot;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct CellRepr { pub struct CellRepr {

View file

@ -6,15 +6,13 @@ use super::{
FeedbackFilter, GraphMessage, NodeOp, NodeProg, MAX_ALLOCATED_NODES, MAX_AVAIL_CODE_ENGINES, FeedbackFilter, GraphMessage, NodeOp, NodeProg, MAX_ALLOCATED_NODES, MAX_AVAIL_CODE_ENGINES,
MAX_AVAIL_TRACKERS, MAX_INPUTS, MAX_SCOPES, UNUSED_MONITOR_IDX, MAX_AVAIL_TRACKERS, MAX_INPUTS, MAX_SCOPES, UNUSED_MONITOR_IDX,
}; };
use crate::block_compiler::{BlkJITCompileError, Block2JITCompiler}; use crate::wblockdsp::*;
use crate::blocklang::*;
use crate::blocklang_def;
use crate::dsp::tracker::{PatternData, Tracker}; use crate::dsp::tracker::{PatternData, Tracker};
use crate::dsp::{node_factory, Node, NodeId, NodeInfo, ParamId, SAtom}; use crate::dsp::{node_factory, Node, NodeId, NodeInfo, ParamId, SAtom};
use crate::monitor::{new_monitor_processor, MinMaxMonitorSamples, Monitor, MON_SIG_CNT}; use crate::monitor::{new_monitor_processor, MinMaxMonitorSamples, Monitor, MON_SIG_CNT};
use crate::nodes::drop_thread::DropThread; use crate::nodes::drop_thread::DropThread;
#[cfg(feature = "synfx-dsp-jit")] #[cfg(feature = "synfx-dsp-jit")]
use crate::wblockdsp::CodeEngine; use synfx_dsp_jit::engine::CodeEngine;
use crate::SampleLibrary; use crate::SampleLibrary;
use crate::ScopeHandle; use crate::ScopeHandle;
@ -190,7 +188,7 @@ pub struct NodeConfigurator {
pub(crate) code_engines: Vec<CodeEngine>, pub(crate) code_engines: Vec<CodeEngine>,
/// Holds the block functions that are JIT compiled to DSP code /// Holds the block functions that are JIT compiled to DSP code
/// for the `Code` nodes. The code is then sent via the [CodeEngine] /// for the `Code` nodes. The code is then sent via the [CodeEngine]
/// in [check_block_function]. /// in [NodeConfigurator::check_block_function].
#[cfg(feature = "synfx-dsp-jit")] #[cfg(feature = "synfx-dsp-jit")]
pub(crate) block_functions: Vec<(u64, Arc<Mutex<BlockFun>>)>, pub(crate) block_functions: Vec<(u64, Arc<Mutex<BlockFun>>)>,
/// The shared parts of the [NodeConfigurator] /// The shared parts of the [NodeConfigurator]
@ -284,9 +282,9 @@ impl NodeConfigurator {
#[cfg(feature = "synfx-dsp-jit")] #[cfg(feature = "synfx-dsp-jit")]
let (code_engines, block_functions) = { let (code_engines, block_functions) = {
let code_engines = vec![CodeEngine::new(); MAX_AVAIL_CODE_ENGINES]; let code_engines = vec![CodeEngine::new_stdlib(); MAX_AVAIL_CODE_ENGINES];
let lang = blocklang_def::setup_hxdsp_block_language(code_engines[0].get_lib()); let lang = setup_hxdsp_block_language(code_engines[0].get_lib());
let mut block_functions = vec![]; let mut block_functions = vec![];
block_functions.resize_with(MAX_AVAIL_CODE_ENGINES, || { block_functions.resize_with(MAX_AVAIL_CODE_ENGINES, || {
(0, Arc::new(Mutex::new(BlockFun::new(lang.clone())))) (0, Arc::new(Mutex::new(BlockFun::new(lang.clone()))))
@ -703,7 +701,7 @@ impl NodeConfigurator {
/// Checks the block function for the id `id`. If the block function did change, /// Checks the block function for the id `id`. If the block function did change,
/// updates are then sent to the audio thread. /// updates are then sent to the audio thread.
/// See also [get_block_function]. /// See also [NodeConfigurator::get_block_function].
pub fn check_block_function(&mut self, id: usize) -> Result<(), BlkJITCompileError> { pub fn check_block_function(&mut self, id: usize) -> Result<(), BlkJITCompileError> {
#[cfg(feature = "synfx-dsp-jit")] #[cfg(feature = "synfx-dsp-jit")]
if let Some((generation, block_fun)) = self.block_functions.get_mut(id) { if let Some((generation, block_fun)) = self.block_functions.get_mut(id) {
@ -727,7 +725,7 @@ impl NodeConfigurator {
} }
/// Retrieve a handle to the block function `id`. In case you modify the block function, /// Retrieve a handle to the block function `id`. In case you modify the block function,
/// make sure to call [check_block_function]. /// make sure to call [NodeConfigurator::check_block_function].
pub fn get_block_function(&self, id: usize) -> Option<Arc<Mutex<BlockFun>>> { pub fn get_block_function(&self, id: usize) -> Option<Arc<Mutex<BlockFun>>> {
#[cfg(feature = "synfx-dsp-jit")] #[cfg(feature = "synfx-dsp-jit")]
{ {

View file

@ -1,152 +0,0 @@
// 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.
use synfx_dsp_jit::*;
use ringbuf::{Consumer, Producer, RingBuffer};
use std::cell::RefCell;
use std::rc::Rc;
const MAX_RINGBUF_SIZE: usize = 128;
enum CodeUpdateMsg {
UpdateFun(Box<DSPFunction>),
}
enum CodeReturnMsg {
DestroyFun(Box<DSPFunction>),
}
pub struct CodeEngine {
dsp_ctx: Rc<RefCell<DSPNodeContext>>,
lib: Rc<RefCell<DSPNodeTypeLibrary>>,
update_prod: Producer<CodeUpdateMsg>,
return_cons: Consumer<CodeReturnMsg>,
}
impl Clone for CodeEngine {
fn clone(&self) -> Self {
CodeEngine::new()
}
}
impl CodeEngine {
pub fn new() -> Self {
let rb = RingBuffer::new(MAX_RINGBUF_SIZE);
let (update_prod, _update_cons) = rb.split();
let rb = RingBuffer::new(MAX_RINGBUF_SIZE);
let (_return_prod, return_cons) = rb.split();
let lib = get_standard_library();
Self { lib, dsp_ctx: DSPNodeContext::new_ref(), update_prod, return_cons }
}
pub fn get_lib(&self) -> Rc<RefCell<DSPNodeTypeLibrary>> {
self.lib.clone()
}
pub fn upload(&mut self, ast: Box<ASTNode>) -> Result<(), JITCompileError> {
let jit = JIT::new(self.lib.clone(), self.dsp_ctx.clone());
let fun = jit.compile(ASTFun::new(ast))?;
let _ = self.update_prod.push(CodeUpdateMsg::UpdateFun(fun));
Ok(())
}
pub fn cleanup(&self, fun: Box<DSPFunction>) {
self.dsp_ctx.borrow_mut().cleanup_dsp_fun_after_user(fun);
}
pub fn query_returns(&mut self) {
while let Some(msg) = self.return_cons.pop() {
match msg {
CodeReturnMsg::DestroyFun(fun) => {
self.cleanup(fun);
}
}
}
}
pub fn get_backend(&mut self) -> CodeEngineBackend {
let rb = RingBuffer::new(MAX_RINGBUF_SIZE);
let (update_prod, update_cons) = rb.split();
let rb = RingBuffer::new(MAX_RINGBUF_SIZE);
let (return_prod, return_cons) = rb.split();
self.update_prod = update_prod;
self.return_cons = return_cons;
let function = get_nop_function(self.lib.clone(), self.dsp_ctx.clone());
CodeEngineBackend::new(function, update_cons, return_prod)
}
}
impl Drop for CodeEngine {
fn drop(&mut self) {
self.dsp_ctx.borrow_mut().free();
}
}
pub struct CodeEngineBackend {
sample_rate: f32,
function: Box<DSPFunction>,
update_cons: Consumer<CodeUpdateMsg>,
return_prod: Producer<CodeReturnMsg>,
}
impl CodeEngineBackend {
fn new(
function: Box<DSPFunction>,
update_cons: Consumer<CodeUpdateMsg>,
return_prod: Producer<CodeReturnMsg>,
) -> Self {
Self { sample_rate: 0.0, function, update_cons, return_prod }
}
#[inline]
pub fn process(
&mut self,
in1: f32,
in2: f32,
a: f32,
b: f32,
d: f32,
g: f32,
) -> (f32, f32, f32) {
let mut s1 = 0.0_f64;
let mut s2 = 0.0_f64;
let res = self
.function
.exec(in1 as f64, in2 as f64, a as f64, b as f64, d as f64, g as f64, &mut s1, &mut s2);
(s1 as f32, s2 as f32, res as f32)
}
pub fn swap_fun(&mut self, srate: f32, mut fun: Box<DSPFunction>) -> Box<DSPFunction> {
std::mem::swap(&mut self.function, &mut fun);
self.function.init(srate as f64, Some(&fun));
fun
}
pub fn set_sample_rate(&mut self, srate: f32) {
self.sample_rate = srate;
self.function.set_sample_rate(srate as f64);
}
pub fn clear(&mut self) {
self.function.reset();
}
pub fn process_updates(&mut self) {
while let Some(msg) = self.update_cons.pop() {
match msg {
CodeUpdateMsg::UpdateFun(mut fun) => {
std::mem::swap(&mut self.function, &mut fun);
self.function.init(self.sample_rate as f64, Some(&fun));
let _ = self.return_prod.push(CodeReturnMsg::DestroyFun(fun));
}
}
}
}
}

View file

@ -6,7 +6,7 @@ use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use crate::blocklang::*; use super::language::*;
#[cfg(feature = "synfx-dsp-jit")] #[cfg(feature = "synfx-dsp-jit")]
use synfx_dsp_jit::{ASTNode, JITCompileError}; use synfx_dsp_jit::{ASTNode, JITCompileError};
@ -18,6 +18,8 @@ struct JASTNode {
nodes: Vec<(String, String, ASTNodeRef)>, nodes: Vec<(String, String, ASTNodeRef)>,
} }
/// The WBlockDSP Abstract Syntax Tree. It is generated by [BlockFun::generate_tree]
/// in [Block2JITCompiler::compile].
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ASTNodeRef(Rc<RefCell<JASTNode>>); pub struct ASTNodeRef(Rc<RefCell<JASTNode>>);
@ -37,18 +39,26 @@ impl BlockASTNode for ASTNodeRef {
} }
impl ASTNodeRef { impl ASTNodeRef {
/// Returns the first child AST node.
pub fn first_child_ref(&self) -> Option<ASTNodeRef> { pub fn first_child_ref(&self) -> Option<ASTNodeRef> {
self.0.borrow().nodes.get(0).map(|n| n.2.clone()) self.0.borrow().nodes.get(0).map(|n| n.2.clone())
} }
/// Returns the first child, including input/output info.
pub fn first_child(&self) -> Option<(String, String, ASTNodeRef)> { pub fn first_child(&self) -> Option<(String, String, ASTNodeRef)> {
self.0.borrow().nodes.get(0).cloned() self.0.borrow().nodes.get(0).cloned()
} }
/// Returns the nth child, including input/output info.
pub fn nth_child(&self, i: usize) -> Option<(String, String, ASTNodeRef)> { pub fn nth_child(&self, i: usize) -> Option<(String, String, ASTNodeRef)> {
self.0.borrow().nodes.get(i).cloned() self.0.borrow().nodes.get(i).cloned()
} }
/// Generates a recursive tree dump output.
///
///```ignore
/// println!("{}", node.walk_dump("", "", 0));
///```
pub fn walk_dump(&self, input: &str, output: &str, indent: usize) -> String { pub fn walk_dump(&self, input: &str, output: &str, indent: usize) -> String {
let indent_str = " ".repeat(indent + 1); let indent_str = " ".repeat(indent + 1);
@ -528,17 +538,21 @@ mod test {
}; };
} }
fn put_n(bf: &mut BlockFun, a: usize, x: i64, y: i64, s: &str) {
bf.instanciate_at(a, x, y, s, None).expect("no put error");
}
fn put_v(bf: &mut BlockFun, a: usize, x: i64, y: i64, s: &str, v: &str) {
bf.instanciate_at(a, x, y, s, Some(v.to_string())).expect("no put error");
}
use synfx_dsp_jit::{get_standard_library, ASTFun, DSPFunction, DSPNodeContext, JIT}; use synfx_dsp_jit::{get_standard_library, ASTFun, DSPFunction, DSPNodeContext, JIT};
fn new_jit_fun<F: FnMut(&mut BlockFun)>( fn new_jit_fun<F: FnMut(&mut BlockFun)>(
mut f: F, mut f: F,
) -> (Rc<RefCell<DSPNodeContext>>, Box<DSPFunction>) { ) -> (Rc<RefCell<DSPNodeContext>>, Box<DSPFunction>) {
use crate::block_compiler::{BlkJITCompileError, Block2JITCompiler};
use crate::blocklang::BlockFun;
use crate::blocklang_def;
let lib = get_standard_library(); let lib = get_standard_library();
let lang = blocklang_def::setup_hxdsp_block_language(lib.clone()); let lang = crate::wblockdsp::setup_hxdsp_block_language(lib.clone());
let mut bf = BlockFun::new(lang.clone()); let mut bf = BlockFun::new(lang.clone());
f(&mut bf); f(&mut bf);
@ -557,11 +571,11 @@ mod test {
#[test] #[test]
fn check_blocklang_sig1() { fn check_blocklang_sig1() {
let (ctx, mut fun) = new_jit_fun(|bf| { let (ctx, mut fun) = new_jit_fun(|bf| {
bf.instanciate_at(0, 0, 1, "value", Some("0.3".to_string())).unwrap(); put_v(bf, 0, 0, 1, "value", "0.3");
bf.instanciate_at(0, 1, 1, "set", Some("&sig1".to_string())).unwrap(); put_v(bf, 0, 1, 1, "set", "&sig1");
bf.instanciate_at(0, 0, 2, "value", Some("-0.3".to_string())).unwrap(); put_v(bf, 0, 0, 2, "value", "-0.3");
bf.instanciate_at(0, 1, 2, "set", Some("&sig2".to_string())).unwrap(); put_v(bf, 0, 1, 2, "set", "&sig2");
bf.instanciate_at(0, 0, 3, "value", Some("-1.3".to_string())).unwrap(); put_v(bf, 0, 0, 3, "value", "-1.3");
}); });
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0); let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0);
@ -576,31 +590,31 @@ mod test {
#[test] #[test]
fn check_blocklang_accum_shift() { fn check_blocklang_accum_shift() {
let (ctx, mut fun) = new_jit_fun(|bf| { let (ctx, mut fun) = new_jit_fun(|bf| {
bf.instanciate_at(0, 1, 1, "accum", None); put_n(bf, 0, 1, 1, "accum");
bf.shift_port(0, 1, 1, 1, false); bf.shift_port(0, 1, 1, 1, false);
bf.instanciate_at(0, 0, 2, "value", Some("0.01".to_string())); put_v(bf, 0, 0, 2, "value", "0.01");
bf.instanciate_at(0, 0, 1, "get", Some("*reset".to_string())); put_v(bf, 0, 0, 1, "get", "*reset");
}); });
fun.exec_2in_2out(0.0, 0.0); fun.exec_2in_2out(0.0, 0.0);
fun.exec_2in_2out(0.0, 0.0); fun.exec_2in_2out(0.0, 0.0);
fun.exec_2in_2out(0.0, 0.0); fun.exec_2in_2out(0.0, 0.0);
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0); let (_s1, _s2, ret) = fun.exec_2in_2out(0.0, 0.0);
assert_float_eq!(ret, 0.04); assert_float_eq!(ret, 0.04);
let reset_idx = ctx.borrow().get_persistent_variable_index_by_name("*reset").unwrap(); let reset_idx = ctx.borrow().get_persistent_variable_index_by_name("*reset").unwrap();
fun.access_persistent_var(reset_idx).map(|reset| *reset = 1.0); fun.access_persistent_var(reset_idx).map(|reset| *reset = 1.0);
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0); let (_s1, _s2, ret) = fun.exec_2in_2out(0.0, 0.0);
assert_float_eq!(ret, 0.0); assert_float_eq!(ret, 0.0);
fun.access_persistent_var(reset_idx).map(|reset| *reset = 0.0); fun.access_persistent_var(reset_idx).map(|reset| *reset = 0.0);
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0); fun.exec_2in_2out(0.0, 0.0);
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0); fun.exec_2in_2out(0.0, 0.0);
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0); fun.exec_2in_2out(0.0, 0.0);
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0); fun.exec_2in_2out(0.0, 0.0);
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0); let (_s1, _s2, ret) = fun.exec_2in_2out(0.0, 0.0);
assert_float_eq!(ret, 0.05); assert_float_eq!(ret, 0.05);
ctx.borrow_mut().free(); ctx.borrow_mut().free();
@ -610,64 +624,64 @@ mod test {
fn check_blocklang_arithmetics() { fn check_blocklang_arithmetics() {
// Check + and * // Check + and *
let (ctx, mut fun) = new_jit_fun(|bf| { let (ctx, mut fun) = new_jit_fun(|bf| {
bf.instanciate_at(0, 0, 1, "value", Some("0.50".to_string())); put_v(bf, 0, 0, 1, "value", "0.50");
bf.instanciate_at(0, 0, 2, "value", Some("0.01".to_string())); put_v(bf, 0, 0, 2, "value", "0.01");
bf.instanciate_at(0, 1, 1, "+", None); put_n(bf, 0, 1, 1, "+");
bf.shift_port(0, 1, 1, 1, true); bf.shift_port(0, 1, 1, 1, true);
bf.instanciate_at(0, 1, 3, "value", Some("2.0".to_string())); put_v(bf, 0, 1, 3, "value", "2.0");
bf.instanciate_at(0, 2, 2, "*", None); put_n(bf, 0, 2, 2, "*");
}); });
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0); let (_s1, _s2, ret) = fun.exec_2in_2out(0.0, 0.0);
assert_float_eq!(ret, 1.02); assert_float_eq!(ret, 1.02);
ctx.borrow_mut().free(); ctx.borrow_mut().free();
// Check - and / // Check - and /
let (ctx, mut fun) = new_jit_fun(|bf| { let (ctx, mut fun) = new_jit_fun(|bf| {
bf.instanciate_at(0, 0, 1, "value", Some("0.50".to_string())); put_v(bf, 0, 0, 1, "value", "0.50");
bf.instanciate_at(0, 0, 2, "value", Some("0.01".to_string())); put_v(bf, 0, 0, 2, "value", "0.01");
bf.instanciate_at(0, 1, 1, "-", None); put_n(bf, 0, 1, 1, "-");
bf.shift_port(0, 1, 1, 1, true); bf.shift_port(0, 1, 1, 1, true);
bf.instanciate_at(0, 1, 3, "value", Some("2.0".to_string())); put_v(bf, 0, 1, 3, "value", "2.0");
bf.instanciate_at(0, 2, 2, "/", None); put_n(bf, 0, 2, 2, "/");
}); });
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0); let (_s1, _s2, ret) = fun.exec_2in_2out(0.0, 0.0);
assert_float_eq!(ret, (0.5 - 0.01) / 2.0); assert_float_eq!(ret, (0.5 - 0.01) / 2.0);
ctx.borrow_mut().free(); ctx.borrow_mut().free();
// Check swapping inputs of "-" // Check swapping inputs of "-"
let (ctx, mut fun) = new_jit_fun(|bf| { let (ctx, mut fun) = new_jit_fun(|bf| {
bf.instanciate_at(0, 0, 1, "value", Some("0.50".to_string())); put_v(bf, 0, 0, 1, "value", "0.50");
bf.instanciate_at(0, 0, 2, "value", Some("0.01".to_string())); put_v(bf, 0, 0, 2, "value", "0.01");
bf.instanciate_at(0, 1, 1, "-", None); put_n(bf, 0, 1, 1, "-");
bf.shift_port(0, 1, 1, 1, false); bf.shift_port(0, 1, 1, 1, false);
}); });
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0); let (_s1, _s2, ret) = fun.exec_2in_2out(0.0, 0.0);
assert_float_eq!(ret, 0.01 - 0.5); assert_float_eq!(ret, 0.01 - 0.5);
ctx.borrow_mut().free(); ctx.borrow_mut().free();
// Check swapping inputs of "/" // Check swapping inputs of "/"
let (ctx, mut fun) = new_jit_fun(|bf| { let (ctx, mut fun) = new_jit_fun(|bf| {
bf.instanciate_at(0, 0, 1, "value", Some("0.50".to_string())); put_v(bf, 0, 0, 1, "value", "0.50");
bf.instanciate_at(0, 0, 2, "value", Some("0.01".to_string())); put_v(bf, 0, 0, 2, "value", "0.01");
bf.instanciate_at(0, 1, 1, "/", None); put_n(bf, 0, 1, 1, "/");
bf.shift_port(0, 1, 1, 1, false); bf.shift_port(0, 1, 1, 1, false);
}); });
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0); let (_s1, _s2, ret) = fun.exec_2in_2out(0.0, 0.0);
assert_float_eq!(ret, 0.01 / 0.5); assert_float_eq!(ret, 0.01 / 0.5);
ctx.borrow_mut().free(); ctx.borrow_mut().free();
// Check division of 0.0 // Check division of 0.0
let (ctx, mut fun) = new_jit_fun(|bf| { let (ctx, mut fun) = new_jit_fun(|bf| {
bf.instanciate_at(0, 0, 1, "value", Some("0.50".to_string())); put_v(bf, 0, 0, 1, "value", "0.50");
bf.instanciate_at(0, 0, 2, "value", Some("0.0".to_string())); put_v(bf, 0, 0, 2, "value", "0.0");
bf.instanciate_at(0, 1, 1, "/", None); put_n(bf, 0, 1, 1, "/");
}); });
let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0); let (_s1, _s2, ret) = fun.exec_2in_2out(0.0, 0.0);
assert_float_eq!(ret, 0.5 / 0.0); assert_float_eq!(ret, 0.5 / 0.0);
ctx.borrow_mut().free(); ctx.borrow_mut().free();
} }
@ -676,10 +690,10 @@ mod test {
fn check_blocklang_divrem() { fn check_blocklang_divrem() {
// &sig1 on second output: // &sig1 on second output:
let (ctx, mut fun) = new_jit_fun(|bf| { let (ctx, mut fun) = new_jit_fun(|bf| {
bf.instanciate_at(0, 0, 1, "value", Some("0.3".to_string())).unwrap(); put_v(bf, 0, 0, 1, "value", "0.3");
bf.instanciate_at(0, 0, 2, "value", Some("-0.4".to_string())).unwrap(); put_v(bf, 0, 0, 2, "value", "-0.4");
bf.instanciate_at(0, 1, 1, "/%", None); put_n(bf, 0, 1, 1, "/%");
bf.instanciate_at(0, 2, 2, "set", Some("&sig1".to_string())).unwrap(); put_v(bf, 0, 2, 2, "set", "&sig1");
}); });
let (s1, _, ret) = fun.exec_2in_2out(0.0, 0.0); let (s1, _, ret) = fun.exec_2in_2out(0.0, 0.0);
@ -690,10 +704,10 @@ mod test {
// &sig1 on first output: // &sig1 on first output:
let (ctx, mut fun) = new_jit_fun(|bf| { let (ctx, mut fun) = new_jit_fun(|bf| {
bf.instanciate_at(0, 0, 1, "value", Some("0.3".to_string())).unwrap(); put_v(bf, 0, 0, 1, "value", "0.3");
bf.instanciate_at(0, 0, 2, "value", Some("-0.4".to_string())).unwrap(); put_v(bf, 0, 0, 2, "value", "-0.4");
bf.instanciate_at(0, 1, 1, "/%", None); put_n(bf, 0, 1, 1, "/%");
bf.instanciate_at(0, 2, 1, "set", Some("&sig1".to_string())).unwrap(); put_v(bf, 0, 2, 1, "set", "&sig1");
}); });
let (s1, _, ret) = fun.exec_2in_2out(0.0, 0.0); let (s1, _, ret) = fun.exec_2in_2out(0.0, 0.0);
@ -704,10 +718,10 @@ mod test {
// &sig1 on second output, but swapped outputs: // &sig1 on second output, but swapped outputs:
let (ctx, mut fun) = new_jit_fun(|bf| { let (ctx, mut fun) = new_jit_fun(|bf| {
bf.instanciate_at(0, 0, 1, "value", Some("0.3".to_string())).unwrap(); put_v(bf, 0, 0, 1, "value", "0.3");
bf.instanciate_at(0, 0, 2, "value", Some("-0.4".to_string())).unwrap(); put_v(bf, 0, 0, 2, "value", "-0.4");
bf.instanciate_at(0, 1, 1, "/%", None); put_n(bf, 0, 1, 1, "/%");
bf.instanciate_at(0, 2, 2, "set", Some("&sig1".to_string())).unwrap(); put_v(bf, 0, 2, 2, "set", "&sig1");
bf.shift_port(0, 1, 1, 0, true); bf.shift_port(0, 1, 1, 0, true);
}); });
@ -719,10 +733,10 @@ mod test {
// &sig1 on first output, but swapped outputs: // &sig1 on first output, but swapped outputs:
let (ctx, mut fun) = new_jit_fun(|bf| { let (ctx, mut fun) = new_jit_fun(|bf| {
bf.instanciate_at(0, 0, 1, "value", Some("0.3".to_string())).unwrap(); put_v(bf, 0, 0, 1, "value", "0.3");
bf.instanciate_at(0, 0, 2, "value", Some("-0.4".to_string())).unwrap(); put_v(bf, 0, 0, 2, "value", "-0.4");
bf.instanciate_at(0, 1, 1, "/%", None); put_n(bf, 0, 1, 1, "/%");
bf.instanciate_at(0, 2, 1, "set", Some("&sig1".to_string())).unwrap(); put_v(bf, 0, 2, 1, "set", "&sig1");
bf.shift_port(0, 1, 1, 0, true); bf.shift_port(0, 1, 1, 0, true);
}); });
@ -734,10 +748,10 @@ mod test {
// &sig1 on first output, but swapped inputs: // &sig1 on first output, but swapped inputs:
let (ctx, mut fun) = new_jit_fun(|bf| { let (ctx, mut fun) = new_jit_fun(|bf| {
bf.instanciate_at(0, 0, 1, "value", Some("0.3".to_string())).unwrap(); put_v(bf, 0, 0, 1, "value", "0.3");
bf.instanciate_at(0, 0, 2, "value", Some("-0.4".to_string())).unwrap(); put_v(bf, 0, 0, 2, "value", "-0.4");
bf.instanciate_at(0, 1, 1, "/%", None); put_n(bf, 0, 1, 1, "/%");
bf.instanciate_at(0, 2, 1, "set", Some("&sig1".to_string())).unwrap(); put_v(bf, 0, 2, 1, "set", "&sig1");
bf.shift_port(0, 1, 1, 0, false); bf.shift_port(0, 1, 1, 0, false);
}); });
@ -749,10 +763,10 @@ mod test {
// &sig1 on first output, but swapped inputs and outputs: // &sig1 on first output, but swapped inputs and outputs:
let (ctx, mut fun) = new_jit_fun(|bf| { let (ctx, mut fun) = new_jit_fun(|bf| {
bf.instanciate_at(0, 0, 1, "value", Some("0.3".to_string())).unwrap(); put_v(bf, 0, 0, 1, "value", "0.3");
bf.instanciate_at(0, 0, 2, "value", Some("-0.4".to_string())).unwrap(); put_v(bf, 0, 0, 2, "value", "-0.4");
bf.instanciate_at(0, 1, 1, "/%", None); put_n(bf, 0, 1, 1, "/%");
bf.instanciate_at(0, 2, 1, "set", Some("&sig1".to_string())).unwrap(); put_v(bf, 0, 2, 1, "set", "&sig1");
bf.shift_port(0, 1, 1, 0, false); bf.shift_port(0, 1, 1, 0, false);
bf.shift_port(0, 1, 1, 0, true); bf.shift_port(0, 1, 1, 0, true);
}); });

View file

@ -2,32 +2,22 @@
// 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.
use crate::blocklang::{BlockLanguage, BlockType, BlockUserInput}; use crate::wblockdsp::{BlockLanguage, BlockType, BlockUserInput};
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
#[cfg(feature = "synfx-dsp-jit")] #[cfg(feature = "synfx-dsp-jit")]
use synfx_dsp_jit::DSPNodeTypeLibrary; use synfx_dsp_jit::DSPNodeTypeLibrary;
/** WBlockDSP language definition and standard library of nodes.
Most of the nodes are taken from the [synfx_dsp_jit] crate standard library.
*/
#[cfg(feature = "synfx-dsp-jit")] #[cfg(feature = "synfx-dsp-jit")]
pub fn setup_hxdsp_block_language( pub fn setup_hxdsp_block_language(
dsp_lib: Rc<RefCell<DSPNodeTypeLibrary>>, dsp_lib: Rc<RefCell<DSPNodeTypeLibrary>>,
) -> Rc<RefCell<BlockLanguage>> { ) -> Rc<RefCell<BlockLanguage>> {
let mut lang = BlockLanguage::new(); let mut lang = BlockLanguage::new();
// lang.define(BlockType {
// category: "source".to_string(),
// name: "phse".to_string(),
// rows: 1,
// inputs: vec![Some("f".to_string())],
// outputs: vec![Some("".to_string())],
// area_count: 0,
// user_input: BlockUserInput::None,
// description:
// "A phasor, returns a saw tooth wave to scan through things or use as modulator."
// .to_string(),
// color: 2,
// });
//
lang.define(BlockType { lang.define(BlockType {
category: "literals".to_string(), category: "literals".to_string(),
name: "zero".to_string(), name: "zero".to_string(),
@ -200,18 +190,6 @@ pub fn setup_hxdsp_block_language(
// color: 8, // color: 8,
// }); // });
// lang.define(BlockType {
// category: "arithmetics".to_string(),
// name: "/%".to_string(),
// rows: 2,
// inputs: vec![Some("a".to_string()), Some("b".to_string())],
// outputs: vec![Some("div".to_string()), Some("rem".to_string())],
// area_count: 0,
// user_input: BlockUserInput::None,
// description: "Computes the integer division and remainder of a / b".to_string(),
// color: 8,
// });
for fun_name in &["+", "-", "*", "/"] { for fun_name in &["+", "-", "*", "/"] {
lang.define(BlockType { lang.define(BlockType {
category: "arithmetics".to_string(), category: "arithmetics".to_string(),

View file

@ -1818,7 +1818,7 @@ mod test {
#[test] #[test]
fn check_blockfun_serialize_empty() { fn check_blockfun_serialize_empty() {
let dsp_lib = synfx_dsp_jit::get_standard_library(); let dsp_lib = synfx_dsp_jit::get_standard_library();
let lang = crate::blocklang_def::setup_hxdsp_block_language(dsp_lib); let lang = crate::wblockdsp::setup_hxdsp_block_language(dsp_lib);
let mut bf = BlockFun::new(lang.clone()); let mut bf = BlockFun::new(lang.clone());
let sn = bf.save_snapshot(); let sn = bf.save_snapshot();
@ -1834,10 +1834,10 @@ mod test {
#[test] #[test]
fn check_blockfun_serialize_1() { fn check_blockfun_serialize_1() {
let dsp_lib = synfx_dsp_jit::get_standard_library(); let dsp_lib = synfx_dsp_jit::get_standard_library();
let lang = crate::blocklang_def::setup_hxdsp_block_language(dsp_lib); let lang = crate::wblockdsp::setup_hxdsp_block_language(dsp_lib);
let mut bf = BlockFun::new(lang.clone()); let mut bf = BlockFun::new(lang.clone());
bf.instanciate_at(0, 0, 0, "+", None); bf.instanciate_at(0, 0, 0, "+", None).unwrap();
let sn = bf.save_snapshot(); let sn = bf.save_snapshot();
let serialized = sn.serialize().to_string(); let serialized = sn.serialize().to_string();

15
src/wblockdsp/mod.rs Normal file
View file

@ -0,0 +1,15 @@
// 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.
/*! Contains the implementation of the visual DSP programming language named WBlockDSP.
*/
mod definition;
mod language;
mod compiler;
pub use definition::*;
pub use language::*;
pub use compiler::*;

View file

@ -1,86 +0,0 @@
// 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_dir_1() {
// use hexodsp::block_compiler::{BlkJITCompileError, Block2JITCompiler};
// use hexodsp::blocklang::BlockFun;
// use hexodsp::blocklang_def;
//
// let lang = blocklang_def::setup_hxdsp_block_language();
// let mut bf = BlockFun::new(lang.clone());
// block_fun.instanciate_at(0, 0, 1, "value", Some("0.3".to_string()));
// block_fun.instanciate_at(0, 1, 1, "set", Some("&sig1".to_string()));
//
// let mut compiler = Block2JITCompiler::new(block_fun.block_language());
// let ast = compiler.compile(&block_fun)?;
// let lib = synfx_dsp_jit::get_standard_library();
// let ctx = synfx_dsp_jit::DSPNodeContext::new_ref();
// let jit = JIT::new(lib, dsp_ctx.clone());
// let fun = jit.compile(ASTFun::new(ast))?;
//
// fun.init(44100.0, None);
//
// let (s1, s2, ret) = fun.exec_2in_2out(0.0, 0.0);
//
// ctx.borrow_mut().free();
//}
//
//// XXX: Test case with 3 outputs, where the first output writes a value used
//// by the computation after the first but before the third output.
//
// 0.3 ->3 set a
// => -> + set b
// get a
// => -> - set a
// get b
// get a +
// get b
//*/
//
////#[test]
////fn check_blocklang_2() {
//// let (mut matrix, mut node_exec) = setup();
////
//// 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, "value", Some("0.3".to_string()));
//// block_fun.instanciate_at(0, 1, 0, "+", None);
//// block_fun.instanciate_at(0, 2, 0, "set", Some("&sig1".to_string()));
////
//// block_fun.instanciate_at(0, 3, 0, "get", Some("in1".to_string()));
//// block_fun.instanciate_at(0, 3, 1, "get", Some("in2".to_string()));
//// block_fun.instanciate_at(0, 4, 0, "-", None);
//// block_fun.instanciate_at(0, 5, 0, "->3", None);
////
//// block_fun.instanciate_at(0, 3, 5, "get", Some("in1".to_string()));
//// block_fun.instanciate_at(0, 4, 5, "if", None);
//// block_fun.instanciate_at(1, 0, 0, "value", Some("0.5".to_string()));
//// block_fun.instanciate_at(2, 0, 0, "value", Some("-0.5".to_string()));
////
//// block_fun.instanciate_at(0, 6, 1, "set", Some("*a".to_string()));
//// block_fun.instanciate_at(0, 6, 2, "set", Some("x".to_string()));
//// block_fun.instanciate_at(0, 6, 0, "->", None);
//// block_fun.instanciate_at(0, 7, 0, "->2", None);
////
//// block_fun.instanciate_at(0, 0, 3, "get", Some("in1".to_string()));
//// block_fun.instanciate_at(0, 0, 4, "get", Some("in2".to_string()));
//// block_fun.instanciate_at(0, 1, 3, "/%", None);
//// block_fun.instanciate_at(0, 2, 3, "->", None);
//// block_fun.instanciate_at(0, 3, 3, "/%", None);
//// block_fun.instanciate_at(0, 4, 3, "set", Some("&sig2".to_string()));
//// block_fun.instanciate_at(0, 4, 4, "set", Some("*ap".to_string()));
//// }
////
//// matrix.check_block_function(0).expect("no compile error");
////
//// let res = run_for_ms(&mut node_exec, 25.0);
//// assert_decimated_feq!(res.0, 50, vec![0.2; 100]);
////}

View file

@ -5,7 +5,7 @@
mod common; mod common;
use common::*; use common::*;
use hexodsp::blocklang::BlockFun; use hexodsp::wblockdsp::BlockFun;
fn setup() -> (Matrix, NodeExecutor) { fn setup() -> (Matrix, NodeExecutor) {
let (node_conf, node_exec) = new_node_engine(); let (node_conf, node_exec) = new_node_engine();

View file

@ -1,41 +0,0 @@
// 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::*;
#[cfg(feature="synfx-dsp-jit")]
use hexodsp::wblockdsp::*;
#[cfg(feature="synfx-dsp-jit")]
#[test]
fn check_wblockdsp_init() {
let mut engine = CodeEngine::new();
let backend = engine.get_backend();
}
#[cfg(feature="synfx-dsp-jit")]
#[test]
fn check_wblockdsp_code_node() {
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", "sig")
.node_io("code", "in1", "sig")
.node_inp("out", "ch1")
.place(&mut matrix, 0, 0)
.unwrap();
matrix.sync().unwrap();
let mut chain = MatrixCellChain::new(CellDir::B);
chain
.node_out("code", "sig")
.node_io("code", "in1", "sig")
.node_inp("out", "ch1")
.place(&mut matrix, 0, 0)
.unwrap();
matrix.sync().unwrap();
}