debugging FbWr/FbRd, the buffer is not read correctly

This commit is contained in:
Weird Constructor 2021-06-03 05:10:29 +02:00
parent b7284b6b8a
commit 3bf1d62239
9 changed files with 101 additions and 25 deletions

View file

@ -14,6 +14,8 @@ mod node_test;
mod node_tseq; mod node_tseq;
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
mod node_sampl; mod node_sampl;
#[allow(non_upper_case_globals)]
mod node_fbwr_fbrd;
pub mod tracker; pub mod tracker;
mod satom; mod satom;
@ -35,6 +37,8 @@ use node_out::Out;
use node_test::Test; use node_test::Test;
use node_tseq::TSeq; use node_tseq::TSeq;
use node_sampl::Sampl; use node_sampl::Sampl;
use node_fbwr_fbrd::FbWr;
use node_fbwr_fbrd::FbRd;
pub const MIDI_MAX_FREQ : f32 = 13289.75; pub const MIDI_MAX_FREQ : f32 = 13289.75;
@ -303,6 +307,11 @@ macro_rules! node_list {
// | | | | defa/lt_/value // | | | | defa/lt_/value
// | | | | | | / // | | | | | | /
{2 0 mono setting(0) 0 1}, {2 0 mono setting(0) 0 1},
fbwr => FbWr UIType::Generic UICategory::IOUtil
(0 inp n_id d_id -1.0, 1.0, 0.0),
fbrd => FbRd UIType::Generic UICategory::IOUtil
(0 atv n_id d_id -1.0, 1.0, 1.0)
[0 sig],
test => Test UIType::Generic UICategory::IOUtil test => Test UIType::Generic UICategory::IOUtil
(0 f n_id d_id 0.0, 1.0, 0.5) (0 f n_id d_id 0.0, 1.0, 0.5)
{1 0 s setting(0) 0 10}, {1 0 s setting(0) 0 10},
@ -321,7 +330,7 @@ pub mod labels {
} }
pub mod Out { pub mod Out {
pub const mono : [&'static str; 2] = ["Mono", "Stereo"]; pub const mono : [&'static str; 2] = ["Stereo", "Mono"];
} }
pub mod Amp { pub mod Amp {
@ -1099,7 +1108,7 @@ pub fn node_factory(node_id: NodeId) -> Option<(Node, NodeInfo)> {
) => { ) => {
match node_id { match node_id {
$(NodeId::$variant(_) => Some(( $(NodeId::$variant(_) => Some((
Node::$variant { node: $variant::new() }, Node::$variant { node: $variant::new(&node_id) },
NodeInfo::from_node_id(node_id), NodeInfo::from_node_id(node_id),
)),)+ )),)+
_ => None, _ => None,

View file

@ -3,7 +3,7 @@
// See README.md and COPYING for details. // See README.md and COPYING for details.
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{SAtom, ProcBuf, DspNode, LedPhaseVals}; use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals};
/// A simple amplifier /// A simple amplifier
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -11,7 +11,7 @@ pub struct Amp {
} }
impl Amp { impl Amp {
pub fn new() -> Self { pub fn new(_nid: &NodeId) -> Self {
Self { Self {
} }
} }

View file

@ -3,7 +3,7 @@
// See README.md and COPYING for details. // See README.md and COPYING for details.
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{SAtom, ProcBuf, inp, at, DspNode, LedPhaseVals}; use crate::dsp::{NodeId, SAtom, ProcBuf, inp, at, DspNode, LedPhaseVals};
/// The (stereo) output port of the plugin /// The (stereo) output port of the plugin
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -14,7 +14,7 @@ pub struct Out {
} }
impl Out { impl Out {
pub fn new() -> Self { pub fn new(_nid: &NodeId) -> Self {
Self { Self {
input: [0.0; 2], input: [0.0; 2],
} }

View file

@ -3,7 +3,7 @@
// See README.md and COPYING for details. // See README.md and COPYING for details.
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{SAtom, ProcBuf, DspNode, LedPhaseVals}; use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals};
use crate::dsp::{out, at, inp, denorm}; //, inp, denorm, denorm_v, inp_dir, at}; use crate::dsp::{out, at, inp, denorm}; //, inp, denorm, denorm_v, inp_dir, at};
use super::helpers::Trigger; use super::helpers::Trigger;
@ -19,7 +19,7 @@ pub struct Sampl {
} }
impl Sampl { impl Sampl {
pub fn new() -> Self { pub fn new(_nid: &NodeId) -> Self {
Self { Self {
phase: 0.0, phase: 0.0,
srate: 44100.0, srate: 44100.0,

View file

@ -3,7 +3,7 @@
// See README.md and COPYING for details. // See README.md and COPYING for details.
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{SAtom, ProcBuf, denorm, out, inp, DspNode, LedPhaseVals}; use crate::dsp::{NodeId, SAtom, ProcBuf, denorm, out, inp, DspNode, LedPhaseVals};
use crate::dsp::helpers::fast_sin; use crate::dsp::helpers::fast_sin;
@ -19,7 +19,7 @@ pub struct Sin {
const TWOPI : f32 = 2.0 * std::f32::consts::PI; const TWOPI : f32 = 2.0 * std::f32::consts::PI;
impl Sin { impl Sin {
pub fn new() -> Self { pub fn new(_nid: &NodeId) -> Self {
Self { Self {
srate: 44100.0, srate: 44100.0,
phase: 0.0, phase: 0.0,

View file

@ -3,7 +3,7 @@
// See README.md and COPYING for details. // See README.md and COPYING for details.
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{SAtom, ProcBuf, GraphFun, GraphAtomData, DspNode, LedPhaseVals}; use crate::dsp::{NodeId, SAtom, ProcBuf, GraphFun, GraphAtomData, DspNode, LedPhaseVals};
/// A simple amplifier /// A simple amplifier
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -11,7 +11,7 @@ pub struct Test {
} }
impl Test { impl Test {
pub fn new() -> Self { pub fn new(_nid: &NodeId) -> Self {
Self { Self {
} }
} }

View file

@ -4,7 +4,7 @@
use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::helpers::TriggerClock; use crate::dsp::helpers::TriggerClock;
use crate::dsp::{SAtom, ProcBuf, DspNode, LedPhaseVals}; use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals};
use crate::dsp::tracker::TrackerBackend; use crate::dsp::tracker::TrackerBackend;
use crate::dsp::MAX_BLOCK_SIZE; use crate::dsp::MAX_BLOCK_SIZE;
@ -18,11 +18,11 @@ pub struct TSeq {
} }
impl Clone for TSeq { impl Clone for TSeq {
fn clone(&self) -> Self { Self::new() } fn clone(&self) -> Self { Self::new(&NodeId::Nop) }
} }
impl TSeq { impl TSeq {
pub fn new() -> Self { pub fn new(_nid: &NodeId) -> Self {
Self { Self {
backend: None, backend: None,
srate: 48000.0, srate: 48000.0,

View file

@ -82,20 +82,34 @@ pub trait NodeAudioContext {
fn input(&mut self, channel: usize, frame: usize) -> f32; fn input(&mut self, channel: usize, frame: usize) -> f32;
} }
/// Implements a trivial delay buffer for the feedback nodes /// Implements a trivial buffer for the feedback nodes
/// FbWr and FbRd. /// FbWr and FbRd.
pub struct FeedbackDelay { ///
/// Note that the previous audio period or even the first one ever may
/// produce less than 64 samples. This means we need to keep track
/// how many samples were actually written to the feedback buffer!
/// See also `sample_count` field.
pub struct FeedbackBuffer {
/// The feedback buffer that holds the samples of the previous period.
buffer: [f32; MAX_FB_DELAY_SIZE], buffer: [f32; MAX_FB_DELAY_SIZE],
/// The write pointer.
write_ptr: usize, write_ptr: usize,
/// Read pointer, is always behind write_ptr by an initial amount
read_ptr: usize, read_ptr: usize,
/// The number of samples written into the buffer (to prevent overreads)
/// We need to keep track of the number of samples actually written into
/// the delay because the first or previous periods may have produced
/// not enough samples.
sample_count: usize,
} }
impl FeedbackDelay { impl FeedbackBuffer {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
buffer: [0.0; MAX_FB_DELAY_SIZE], buffer: [0.0; MAX_FB_DELAY_SIZE],
write_ptr: 0, write_ptr: 0,
read_ptr: (64 + MAX_FB_DELAY_SIZE) % MAX_FB_DELAY_SIZE, read_ptr: (64 + MAX_FB_DELAY_SIZE) % MAX_FB_DELAY_SIZE,
sample_count: 0,
} }
} }
@ -106,6 +120,7 @@ impl FeedbackDelay {
pub fn set_sample_rate(&mut self, sr: f32) { pub fn set_sample_rate(&mut self, sr: f32) {
self.buffer = [0.0; MAX_FB_DELAY_SIZE]; self.buffer = [0.0; MAX_FB_DELAY_SIZE];
self.write_ptr = 0; self.write_ptr = 0;
self.sample_count = 0;
// The delay sample count maximum is defined by MAX_FB_DELAY_SRATE, // The delay sample count maximum is defined by MAX_FB_DELAY_SRATE,
// after that the feedback delays become shorter than they should be // after that the feedback delays become shorter than they should be
// and things won't sound the same at sample rate // and things won't sound the same at sample rate
@ -125,26 +140,35 @@ impl FeedbackDelay {
#[inline] #[inline]
pub fn write(&mut self, s: f32) { pub fn write(&mut self, s: f32) {
self.write_ptr = (self.write_ptr + 1) % MAX_FB_DELAY_SIZE; self.write_ptr = (self.write_ptr + 1) % MAX_FB_DELAY_SIZE;
self.sample_count += 1;
self.buffer[self.write_ptr] = s; self.buffer[self.write_ptr] = s;
println!("WRITE[{}]={}", self.write_ptr, s);
} }
#[inline] #[inline]
pub fn read(&mut self) -> f32 { pub fn read(&mut self) -> f32 {
if self.sample_count > 0 {
self.sample_count - 1;
self.read_ptr = (self.read_ptr + 1) % MAX_FB_DELAY_SIZE; self.read_ptr = (self.read_ptr + 1) % MAX_FB_DELAY_SIZE;
self.buffer[self.read_ptr] let s = self.buffer[self.read_ptr];
println!("READ[{}]={}", self.read_ptr, s);
s
} else {
0.0
}
} }
} }
/// Contains global state that all nodes can access. /// Contains global state that all nodes can access.
/// This is used for instance to implement the feedbackd delay nodes. /// This is used for instance to implement the feedbackd delay nodes.
pub struct NodeExecContext { pub struct NodeExecContext {
pub feedback_delay_buffers: Vec<FeedbackDelay>, pub feedback_delay_buffers: Vec<FeedbackBuffer>,
} }
impl NodeExecContext { impl NodeExecContext {
fn new() -> Self { fn new() -> Self {
let mut fbdb = vec![]; let mut fbdb = vec![];
fbdb.resize_with(MAX_ALLOCATED_NODES, || FeedbackDelay::new()); fbdb.resize_with(MAX_ALLOCATED_NODES, || FeedbackBuffer::new());
Self { Self {
feedback_delay_buffers: fbdb, feedback_delay_buffers: fbdb,
} }

View file

@ -916,3 +916,46 @@ fn check_matrix_output_feedback() {
assert_float_eq!(fo_amp.1, 0.11627); assert_float_eq!(fo_amp.1, 0.11627);
} }
#[test]
fn check_matrix_node_feedback() {
let (node_conf, mut node_exec) = new_node_engine();
let mut matrix = Matrix::new(node_conf, 7, 7);
let sin = NodeId::Sin(0);
let sin2 = NodeId::Sin(1);
let wr = NodeId::FbWr(0);
let rd = NodeId::FbRd(0);
let wr2 = NodeId::FbWr(1);
let rd2 = NodeId::FbRd(1);
let out = NodeId::Out(0);
matrix.place(0, 0, Cell::empty(sin)
.out(None, None, sin.out("sig")));
matrix.place(0, 1, Cell::empty(wr)
.input(wr.inp("inp"), None, None));
matrix.place(1, 0, Cell::empty(rd)
.out(None, None, rd.out("sig")));
matrix.place(1, 1, Cell::empty(out)
.input(out.inp("ch1"), None, None));
matrix.place(0, 2, Cell::empty(sin2)
.out(None, None, sin2.out("sig")));
matrix.place(0, 3, Cell::empty(wr2)
.input(wr2.inp("inp"), None, None));
matrix.place(1, 2, Cell::empty(rd2)
.out(None, None, rd2.out("sig")));
matrix.place(1, 3, Cell::empty(out)
.input(out.inp("ch2"), None, None));
matrix.sync().unwrap();
let freq_param = sin2.inp_param("freq").unwrap();
matrix.set_param(
freq_param,
SAtom::param(freq_param.norm(880.0)));
let (out_l, out_r) = run_for_ms(&mut node_exec, 5.0);
println!("L: {:?}", out_l);
println!("R: {:?}", out_r);
assert!(false);
}