From 36b76f538859a54b523bcdf2d67dcd64d1992ee5 Mon Sep 17 00:00:00 2001 From: Weird Constructor Date: Fri, 29 Jul 2022 21:30:56 +0200 Subject: [PATCH] Improved WBlockDSP API Integration --- src/nodes/node_conf.rs | 2 - src/nodes/node_exec.rs | 23 +------ src/wblockdsp.rs | 153 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 24 deletions(-) create mode 100644 src/wblockdsp.rs diff --git a/src/nodes/node_conf.rs b/src/nodes/node_conf.rs index 36055f3..addc9ef 100644 --- a/src/nodes/node_conf.rs +++ b/src/nodes/node_conf.rs @@ -256,8 +256,6 @@ impl SharedNodeConf { graph_update_con: rb_graph_con, graph_drop_prod: rb_drop_prod, monitor_backend, - #[cfg(feature = "wblockdsp")] - code_backend: None, // TODO: FILL THIS! }, ) } diff --git a/src/nodes/node_exec.rs b/src/nodes/node_exec.rs index dbedbfb..699d026 100644 --- a/src/nodes/node_exec.rs +++ b/src/nodes/node_exec.rs @@ -9,8 +9,6 @@ use super::{ use crate::dsp::{Node, NodeContext, NodeId, MAX_BLOCK_SIZE}; use crate::monitor::{MonitorBackend, MON_SIG_CNT}; use crate::util::{AtomicFloat, Smoother}; -#[cfg(feature = "wblockdsp")] -use crate::wblockdsp::CodeEngineBackend; use crate::log; use std::io::Write; @@ -83,9 +81,6 @@ pub(crate) struct SharedNodeExec { pub(crate) graph_drop_prod: Producer, /// For sending feedback to the frontend thread. pub(crate) monitor_backend: MonitorBackend, - /// For handing over the [crate::wblockdsp::CodeEngineBackend] - #[cfg(feature = "wblockdsp")] - pub(crate) code_backend: Option>, } /// Contains audio driver context informations. Such as the number @@ -173,41 +168,25 @@ impl Default for FeedbackBuffer { /// This is used for instance to implement the feedbackd delay nodes. pub struct NodeExecContext { pub feedback_delay_buffers: Vec, - #[cfg(feature = "wblockdsp")] - pub code_backend: Option>, } impl NodeExecContext { fn new() -> Self { let mut fbdb = vec![]; fbdb.resize_with(MAX_ALLOCATED_NODES, FeedbackBuffer::new); - Self { - feedback_delay_buffers: fbdb, - #[cfg(feature = "wblockdsp")] - code_backend: None - } + Self { feedback_delay_buffers: fbdb } } fn set_sample_rate(&mut self, srate: f32) { for b in self.feedback_delay_buffers.iter_mut() { b.set_sample_rate(srate); } - - #[cfg(feature = "wblockdsp")] - if let Some(code_backend) = self.code_backend.as_mut() { - code_backend.set_sample_rate(srate); - } } fn clear(&mut self) { for b in self.feedback_delay_buffers.iter_mut() { b.clear(); } - - #[cfg(feature = "wblockdsp")] - if let Some(code_backend) = self.code_backend.as_mut() { - code_backend.clear(); - } } } diff --git a/src/wblockdsp.rs b/src/wblockdsp.rs new file mode 100644 index 0000000..cbb5bd9 --- /dev/null +++ b/src/wblockdsp.rs @@ -0,0 +1,153 @@ +// Copyright (c) 2022 Weird Constructor +// This file is a part of HexoDSP. Released under GPL-3.0-or-later. +// See README.md and COPYING for details. + +use wblockdsp::*; + +use ringbuf::{Consumer, Producer, RingBuffer}; +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; + +const MAX_RINGBUF_SIZE: usize = 128; +const MAX_CONTEXTS: usize = 32; + +enum CodeUpdateMsg { + UpdateFun(Box), +} + +enum CodeReturnMsg { + DestroyFun(Box), +} + +pub struct CodeEngine { + dsp_ctx: Rc>, + lib: Rc>, + update_prod: Producer, + update_cons: Option>, + return_cons: Consumer, + return_prod: Option>, +} + +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_default_library(); + + Self { + lib, + dsp_ctx: DSPNodeContext::new_ref(), + update_prod, + update_cons: Some(update_cons), + return_prod: Some(return_prod), + return_cons, + } + } + + pub fn upload( + &mut self, + code_instance: usize, + ast: Box, + ) -> Result<(), JITCompileError> { + + let jit = JIT::new(self.lib.clone(), self.dsp_ctx.clone()); + let fun = jit.compile(ASTFun::new(ast))?; + self.update_prod.push(CodeUpdateMsg::UpdateFun(fun)); + + Ok(()) + } + + pub fn cleanup(&self, fun: Box) { + 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) -> Option { + 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)); + } + } + + None + } +} + +impl Drop for CodeEngine { + fn drop(&mut self) { + self.dsp_ctx.borrow_mut().free(); + } +} + + +pub struct CodeEngineBackend { + sample_rate: f32, + function: Box, + update_cons: Consumer, + return_prod: Producer, +} + +impl CodeEngineBackend { + fn new(function: Box, update_cons: Consumer, return_prod: Producer) -> 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) -> Box { + 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)); + self.return_prod.push(CodeReturnMsg::DestroyFun(fun)); + } + } + } + } +}