2022-07-29 20:00:46 +00:00
|
|
|
// 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};
|
2022-07-30 21:11:33 +00:00
|
|
|
#[cfg(feature = "synfx-dsp-jit")]
|
2022-07-29 20:00:46 +00:00
|
|
|
use crate::wblockdsp::CodeEngineBackend;
|
|
|
|
|
2022-08-05 17:44:40 +00:00
|
|
|
//use crate::dsp::MAX_BLOCK_SIZE;
|
2022-07-29 20:00:46 +00:00
|
|
|
|
|
|
|
/// A WBlockDSP code execution node for JIT'ed DSP code
|
|
|
|
pub struct Code {
|
2022-07-30 21:11:33 +00:00
|
|
|
#[cfg(feature = "synfx-dsp-jit")]
|
2022-07-29 20:00:46 +00:00
|
|
|
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 {
|
2022-07-30 21:11:33 +00:00
|
|
|
#[cfg(feature = "synfx-dsp-jit")]
|
2022-07-29 20:00:46 +00:00
|
|
|
backend: None,
|
|
|
|
srate: 48000.0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-30 21:11:33 +00:00
|
|
|
#[cfg(feature = "synfx-dsp-jit")]
|
2022-07-29 20:00:46 +00:00
|
|
|
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;
|
2022-07-30 21:11:33 +00:00
|
|
|
#[cfg(feature = "synfx-dsp-jit")]
|
2022-07-29 20:00:46 +00:00
|
|
|
if let Some(backend) = self.backend.as_mut() {
|
|
|
|
backend.set_sample_rate(srate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn reset(&mut self) {
|
2022-07-30 21:11:33 +00:00
|
|
|
#[cfg(feature = "synfx-dsp-jit")]
|
2022-07-29 20:00:46 +00:00
|
|
|
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,
|
2022-08-05 17:44:40 +00:00
|
|
|
_atoms: &[SAtom],
|
2022-07-29 20:00:46 +00:00
|
|
|
inputs: &[ProcBuf],
|
|
|
|
outputs: &mut [ProcBuf],
|
|
|
|
ctx_vals: LedPhaseVals,
|
|
|
|
) {
|
2022-08-05 17:44:40 +00:00
|
|
|
use crate::dsp::{inp, out_idx};
|
|
|
|
let in1 = inp::Code::in1(inputs);
|
|
|
|
let in2 = inp::Code::in2(inputs);
|
|
|
|
let a = inp::Code::alpha(inputs);
|
|
|
|
let b = inp::Code::beta(inputs);
|
|
|
|
let d = inp::Code::delta(inputs);
|
|
|
|
let g = inp::Code::gamma(inputs);
|
2022-08-01 03:31:07 +00:00
|
|
|
let out_i = out_idx::Code::sig1();
|
2022-08-05 17:44:40 +00:00
|
|
|
|
2022-08-01 03:31:07 +00:00
|
|
|
let (sig, sig1) = outputs.split_at_mut(out_i);
|
|
|
|
let (sig1, sig2) = sig1.split_at_mut(1);
|
|
|
|
let sig = &mut sig[0];
|
|
|
|
let sig1 = &mut sig1[0];
|
|
|
|
let sig2 = &mut sig2[0];
|
2022-07-29 20:00:46 +00:00
|
|
|
|
2022-07-30 21:11:33 +00:00
|
|
|
#[cfg(feature = "synfx-dsp-jit")]
|
2022-07-29 22:26:01 +00:00
|
|
|
{
|
|
|
|
let backend = if let Some(backend) = &mut self.backend {
|
|
|
|
backend
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
};
|
2022-07-29 20:00:46 +00:00
|
|
|
|
2022-07-29 22:26:01 +00:00
|
|
|
backend.process_updates();
|
2022-07-29 20:00:46 +00:00
|
|
|
|
2022-08-05 17:44:40 +00:00
|
|
|
let mut ret = 0.0;
|
|
|
|
let mut s1 = 0.0;
|
|
|
|
#[allow(unused_assignments)]
|
|
|
|
let mut s2 = 0.0;
|
2022-07-29 22:26:01 +00:00
|
|
|
for frame in 0..ctx.nframes() {
|
2022-08-05 17:44:40 +00:00
|
|
|
(s1, s2, ret) = backend.process(
|
|
|
|
in1.read(frame),
|
|
|
|
in2.read(frame),
|
|
|
|
a.read(frame),
|
|
|
|
b.read(frame),
|
|
|
|
d.read(frame),
|
|
|
|
g.read(frame),
|
|
|
|
);
|
2022-08-01 03:31:07 +00:00
|
|
|
sig.write(frame, ret);
|
|
|
|
sig1.write(frame, s1);
|
|
|
|
sig2.write(frame, s2);
|
2022-07-29 22:26:01 +00:00
|
|
|
}
|
2022-07-29 20:00:46 +00:00
|
|
|
|
2022-08-05 17:44:40 +00:00
|
|
|
ctx_vals[0].set(ret);
|
|
|
|
ctx_vals[1].set(s1);
|
2022-07-29 22:26:01 +00:00
|
|
|
}
|
2022-07-29 20:00:46 +00:00
|
|
|
}
|
|
|
|
}
|