Added Code node
This commit is contained in:
parent
36b76f5388
commit
70f369af70
5 changed files with 147 additions and 16 deletions
|
@ -537,6 +537,8 @@ mod node_tseq;
|
||||||
mod node_tslfo;
|
mod node_tslfo;
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
mod node_vosc;
|
mod node_vosc;
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
mod node_code;
|
||||||
|
|
||||||
pub mod biquad;
|
pub mod biquad;
|
||||||
pub mod dattorro;
|
pub mod dattorro;
|
||||||
|
@ -607,6 +609,7 @@ use node_sin::Sin;
|
||||||
use node_smap::SMap;
|
use node_smap::SMap;
|
||||||
use node_test::Test;
|
use node_test::Test;
|
||||||
use node_tseq::TSeq;
|
use node_tseq::TSeq;
|
||||||
|
use node_code::Code;
|
||||||
use node_tslfo::TsLFO;
|
use node_tslfo::TsLFO;
|
||||||
use node_vosc::VOsc;
|
use node_vosc::VOsc;
|
||||||
|
|
||||||
|
@ -1367,11 +1370,21 @@ macro_rules! node_list {
|
||||||
[9 gat4]
|
[9 gat4]
|
||||||
[10 gat5]
|
[10 gat5]
|
||||||
[11 gat6],
|
[11 gat6],
|
||||||
|
code => Code UIType::Generic UICategory::Signal
|
||||||
|
(0 in1 n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
||||||
|
(1 in2 n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
||||||
|
(2 alpha n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
||||||
|
(3 beta n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
||||||
|
(4 delta n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
||||||
|
(5 gamma n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
||||||
|
[0 sig]
|
||||||
|
[1 sig1]
|
||||||
|
[2 sig2],
|
||||||
sampl => Sampl UIType::Generic UICategory::Osc
|
sampl => Sampl UIType::Generic UICategory::Osc
|
||||||
(0 freq n_pit d_pit r_fq f_def stp_d -1.0, 0.564713133, 440.0)
|
(0 freq n_pit d_pit r_fq f_def stp_d -1.0, 0.564713133, 440.0)
|
||||||
(1 trig n_id n_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
(1 trig n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0)
|
||||||
(2 offs n_id n_id r_id f_def stp_d 0.0, 1.0, 0.0)
|
(2 offs n_id d_id r_id f_def stp_d 0.0, 1.0, 0.0)
|
||||||
(3 len n_id n_id r_id f_def stp_d 0.0, 1.0, 1.0)
|
(3 len n_id d_id r_id f_def stp_d 0.0, 1.0, 1.0)
|
||||||
(4 dcms n_declick d_declick r_dc_ms f_ms stp_m 0.0, 1.0, 3.0)
|
(4 dcms n_declick d_declick r_dc_ms f_ms stp_m 0.0, 1.0, 3.0)
|
||||||
(5 det n_det d_det r_det f_det stp_f -0.2, 0.2, 0.0)
|
(5 det n_det d_det r_det f_det stp_f -0.2, 0.2, 0.0)
|
||||||
{6 0 sample audio_unloaded("") sample f_def 0 0}
|
{6 0 sample audio_unloaded("") sample f_def 0 0}
|
||||||
|
|
109
src/dsp/node_code.rs
Normal file
109
src/dsp/node_code.rs
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
// Copyright (c) 2021 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 crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom};
|
||||||
|
use crate::nodes::{NodeAudioContext, NodeExecContext};
|
||||||
|
use crate::wblockdsp::CodeEngineBackend;
|
||||||
|
|
||||||
|
use crate::dsp::MAX_BLOCK_SIZE;
|
||||||
|
|
||||||
|
/// A WBlockDSP code execution node for JIT'ed DSP code
|
||||||
|
pub struct Code {
|
||||||
|
backend: Option<Box<CodeEngineBackend>>,
|
||||||
|
srate: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Code {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||||
|
write!(f, "Code")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for Code {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self::new(&NodeId::Nop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Code {
|
||||||
|
pub fn new(_nid: &NodeId) -> Self {
|
||||||
|
Self {
|
||||||
|
backend: None,
|
||||||
|
srate: 48000.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_backend(&mut self, backend: CodeEngineBackend) {
|
||||||
|
self.backend = Some(Box::new(backend));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const in1: &'static str = "Code in1\nInput Signal 1\nRange: (-1..1)\n";
|
||||||
|
pub const in2: &'static str = "Code in2\nInput Signal 1\nRange: (-1..1)\n";
|
||||||
|
pub const alpha: &'static str = "Code alpha\nInput Parameter Alpha\nRange: (-1..1)\n";
|
||||||
|
pub const beta: &'static str = "Code alpha\nInput Parameter Alpha\nRange: (-1..1)\n";
|
||||||
|
pub const delta: &'static str = "Code alpha\nInput Parameter Alpha\nRange: (-1..1)\n";
|
||||||
|
pub const gamma: &'static str = "Code alpha\nInput Parameter Alpha\nRange: (-1..1)\n";
|
||||||
|
pub const sig: &'static str = "Code sig\nReturn output\nRange: (-1..1)\n";
|
||||||
|
pub const sig1: &'static str = "Code sig1\nSignal channel 1 output\nRange: (-1..1)\n";
|
||||||
|
pub const sig2: &'static str = "Code sig2\nSignal channel 2 output\nRange: (-1..1)\n";
|
||||||
|
|
||||||
|
pub const DESC: &'static str = "WBlockDSP Code Execution\n\n\
|
||||||
|
This node executes just in time compiled code as fast as machine code. \
|
||||||
|
Use this to implement real time DSP code yourself.";
|
||||||
|
pub const HELP: &'static str = r#"WBlockDSP Code Execution
|
||||||
|
|
||||||
|
Do it!
|
||||||
|
"#;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DspNode for Code {
|
||||||
|
fn outputs() -> usize {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_sample_rate(&mut self, srate: f32) {
|
||||||
|
self.srate = srate as f64;
|
||||||
|
if let Some(backend) = self.backend.as_mut() {
|
||||||
|
backend.set_sample_rate(srate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) {
|
||||||
|
if let Some(backend) = self.backend.as_mut() {
|
||||||
|
backend.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn process<T: NodeAudioContext>(
|
||||||
|
&mut self,
|
||||||
|
ctx: &mut T,
|
||||||
|
_ectx: &mut NodeExecContext,
|
||||||
|
_nctx: &NodeContext,
|
||||||
|
atoms: &[SAtom],
|
||||||
|
inputs: &[ProcBuf],
|
||||||
|
outputs: &mut [ProcBuf],
|
||||||
|
ctx_vals: LedPhaseVals,
|
||||||
|
) {
|
||||||
|
use crate::dsp::{at, denorm, inp, out};
|
||||||
|
// let clock = inp::TSeq::clock(inputs);
|
||||||
|
// let trig = inp::TSeq::trig(inputs);
|
||||||
|
// let cmode = at::TSeq::cmode(atoms);
|
||||||
|
|
||||||
|
let backend = if let Some(backend) = &mut self.backend {
|
||||||
|
backend
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
backend.process_updates();
|
||||||
|
|
||||||
|
for frame in 0..ctx.nframes() {
|
||||||
|
let (s1, s2, ret) = backend.process(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx_vals[0].set(0.0);
|
||||||
|
ctx_vals[1].set(0.0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ pub const SCOPE_SAMPLES: usize = 512;
|
||||||
pub const MAX_INPUTS: usize = 32;
|
pub const MAX_INPUTS: usize = 32;
|
||||||
pub const MAX_SMOOTHERS: usize = 36 + 4; // 6 * 6 modulator inputs + 4 UI Knobs
|
pub const MAX_SMOOTHERS: usize = 36 + 4; // 6 * 6 modulator inputs + 4 UI Knobs
|
||||||
pub const MAX_AVAIL_TRACKERS: usize = 128;
|
pub const MAX_AVAIL_TRACKERS: usize = 128;
|
||||||
|
pub const MAX_AVAIL_CODE_ENGINES: usize = 32;
|
||||||
pub const MAX_FB_DELAYS: usize = 256; // 256 feedback delays, thats roughly 1.2MB RAM
|
pub const MAX_FB_DELAYS: usize = 256; // 256 feedback delays, thats roughly 1.2MB RAM
|
||||||
pub const FB_DELAY_TIME_US: usize = 3140; // 3.14ms (should be enough for MAX_BLOCK_SIZE)
|
pub const FB_DELAY_TIME_US: usize = 3140; // 3.14ms (should be enough for MAX_BLOCK_SIZE)
|
||||||
// This means, until 384000 sample rate the times are accurate.
|
// This means, until 384000 sample rate the times are accurate.
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
FeedbackFilter, GraphMessage, NodeOp, NodeProg, MAX_ALLOCATED_NODES, MAX_AVAIL_TRACKERS,
|
FeedbackFilter, GraphMessage, NodeOp, NodeProg, MAX_ALLOCATED_NODES, MAX_AVAIL_TRACKERS,
|
||||||
MAX_INPUTS, MAX_SCOPES, UNUSED_MONITOR_IDX,
|
MAX_INPUTS, MAX_SCOPES, UNUSED_MONITOR_IDX, MAX_AVAIL_CODE_ENGINES
|
||||||
};
|
};
|
||||||
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};
|
||||||
|
@ -182,6 +182,9 @@ pub struct NodeConfigurator {
|
||||||
pub(crate) trackers: Vec<Tracker>,
|
pub(crate) trackers: Vec<Tracker>,
|
||||||
/// Holding the scope buffers:
|
/// Holding the scope buffers:
|
||||||
pub(crate) scopes: Vec<Arc<ScopeHandle>>,
|
pub(crate) scopes: Vec<Arc<ScopeHandle>>,
|
||||||
|
/// Holding the WBlockDSP code engine backends:
|
||||||
|
#[cfg(feature = "wblockdsp")]
|
||||||
|
pub(crate) code_engines: Vec<CodeEngine>,
|
||||||
/// The shared parts of the [NodeConfigurator]
|
/// The shared parts of the [NodeConfigurator]
|
||||||
/// and the [crate::nodes::NodeExecutor].
|
/// and the [crate::nodes::NodeExecutor].
|
||||||
pub(crate) shared: SharedNodeConf,
|
pub(crate) shared: SharedNodeConf,
|
||||||
|
@ -287,6 +290,7 @@ impl NodeConfigurator {
|
||||||
atom_values: std::collections::HashMap::new(),
|
atom_values: std::collections::HashMap::new(),
|
||||||
node2idx: HashMap::new(),
|
node2idx: HashMap::new(),
|
||||||
trackers: vec![Tracker::new(); MAX_AVAIL_TRACKERS],
|
trackers: vec![Tracker::new(); MAX_AVAIL_TRACKERS],
|
||||||
|
code_engines: vec![CodeEngine::new(); MAX_AVAIL_CODE_ENGINES],
|
||||||
scopes,
|
scopes,
|
||||||
},
|
},
|
||||||
shared_exec,
|
shared_exec,
|
||||||
|
|
|
@ -24,9 +24,13 @@ pub struct CodeEngine {
|
||||||
dsp_ctx: Rc<RefCell<DSPNodeContext>>,
|
dsp_ctx: Rc<RefCell<DSPNodeContext>>,
|
||||||
lib: Rc<RefCell<DSPNodeTypeLibrary>>,
|
lib: Rc<RefCell<DSPNodeTypeLibrary>>,
|
||||||
update_prod: Producer<CodeUpdateMsg>,
|
update_prod: Producer<CodeUpdateMsg>,
|
||||||
update_cons: Option<Consumer<CodeUpdateMsg>>,
|
|
||||||
return_cons: Consumer<CodeReturnMsg>,
|
return_cons: Consumer<CodeReturnMsg>,
|
||||||
return_prod: Option<Producer<CodeReturnMsg>>,
|
}
|
||||||
|
|
||||||
|
impl Clone for CodeEngine {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
CodeEngine::new()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CodeEngine {
|
impl CodeEngine {
|
||||||
|
@ -42,8 +46,6 @@ impl CodeEngine {
|
||||||
lib,
|
lib,
|
||||||
dsp_ctx: DSPNodeContext::new_ref(),
|
dsp_ctx: DSPNodeContext::new_ref(),
|
||||||
update_prod,
|
update_prod,
|
||||||
update_cons: Some(update_cons),
|
|
||||||
return_prod: Some(return_prod),
|
|
||||||
return_cons,
|
return_cons,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,15 +77,17 @@ impl CodeEngine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_backend(&mut self) -> Option<CodeEngineBackend> {
|
pub fn get_backend(&mut self) -> CodeEngineBackend {
|
||||||
if let Some(update_cons) = self.update_cons.take() {
|
let rb = RingBuffer::new(MAX_RINGBUF_SIZE);
|
||||||
if let Some(return_prod) = self.return_prod.take() {
|
let (update_prod, update_cons) = rb.split();
|
||||||
let function = get_nop_function(self.lib.clone(), self.dsp_ctx.clone());
|
let rb = RingBuffer::new(MAX_RINGBUF_SIZE);
|
||||||
return Some(CodeEngineBackend::new(function, update_cons, return_prod));
|
let (return_prod, return_cons) = rb.split();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue