Added Code node

This commit is contained in:
Weird Constructor 2022-07-29 22:00:46 +02:00
parent 36b76f5388
commit 70f369af70
5 changed files with 147 additions and 16 deletions

View file

@ -537,6 +537,8 @@ mod node_tseq;
mod node_tslfo;
#[allow(non_upper_case_globals)]
mod node_vosc;
#[allow(non_upper_case_globals)]
mod node_code;
pub mod biquad;
pub mod dattorro;
@ -607,6 +609,7 @@ use node_sin::Sin;
use node_smap::SMap;
use node_test::Test;
use node_tseq::TSeq;
use node_code::Code;
use node_tslfo::TsLFO;
use node_vosc::VOsc;
@ -1367,11 +1370,21 @@ macro_rules! node_list {
[9 gat4]
[10 gat5]
[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
(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)
(2 offs n_id n_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)
(1 trig n_id d_id r_id f_def stp_d -1.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 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)
(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}

109
src/dsp/node_code.rs Normal file
View 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);
}
}

View file

@ -8,6 +8,7 @@ pub const SCOPE_SAMPLES: usize = 512;
pub const MAX_INPUTS: usize = 32;
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_CODE_ENGINES: usize = 32;
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)
// This means, until 384000 sample rate the times are accurate.

View file

@ -4,7 +4,7 @@
use super::{
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::{node_factory, Node, NodeId, NodeInfo, ParamId, SAtom};
@ -182,6 +182,9 @@ pub struct NodeConfigurator {
pub(crate) trackers: Vec<Tracker>,
/// Holding the scope buffers:
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]
/// and the [crate::nodes::NodeExecutor].
pub(crate) shared: SharedNodeConf,
@ -287,6 +290,7 @@ impl NodeConfigurator {
atom_values: std::collections::HashMap::new(),
node2idx: HashMap::new(),
trackers: vec![Tracker::new(); MAX_AVAIL_TRACKERS],
code_engines: vec![CodeEngine::new(); MAX_AVAIL_CODE_ENGINES],
scopes,
},
shared_exec,

View file

@ -24,9 +24,13 @@ pub struct CodeEngine {
dsp_ctx: Rc<RefCell<DSPNodeContext>>,
lib: Rc<RefCell<DSPNodeTypeLibrary>>,
update_prod: Producer<CodeUpdateMsg>,
update_cons: Option<Consumer<CodeUpdateMsg>>,
return_cons: Consumer<CodeReturnMsg>,
return_prod: Option<Producer<CodeReturnMsg>>,
}
impl Clone for CodeEngine {
fn clone(&self) -> Self {
CodeEngine::new()
}
}
impl CodeEngine {
@ -42,8 +46,6 @@ impl CodeEngine {
lib,
dsp_ctx: DSPNodeContext::new_ref(),
update_prod,
update_cons: Some(update_cons),
return_prod: Some(return_prod),
return_cons,
}
}
@ -75,15 +77,17 @@ impl CodeEngine {
}
}
pub fn get_backend(&mut self) -> Option<CodeEngineBackend> {
if let Some(update_cons) = self.update_cons.take() {
if let Some(return_prod) = self.return_prod.take() {
let function = get_nop_function(self.lib.clone(), self.dsp_ctx.clone());
return Some(CodeEngineBackend::new(function, update_cons, return_prod));
}
}
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();
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)
}
}