hexodsp/dsp/
node_fbwr_fbrd.rs1use crate::dsp::{
6 DspNode, GraphFun, LedPhaseVals, NodeContext, NodeGlobalRef, NodeId, ProcBuf, SAtom,
7};
8use crate::nodes::{NodeAudioContext, NodeExecContext};
9use crate::{SharedFeedback, SharedFeedbackReader, SharedFeedbackWriter};
10
11#[derive(Debug, Clone)]
13pub struct FbWr {
14 fb_wr: Box<SharedFeedbackWriter>,
15}
16
17impl FbWr {
18 pub fn new(nid: &NodeId, node_global: &NodeGlobalRef) -> Self {
19 let fb_wr = if let Ok(mut node_global) = node_global.lock() {
20 node_global.get_feedback_writer(nid.instance() as usize)
21 } else {
22 let sfb = SharedFeedback::new(44100.0);
25 Box::new(SharedFeedbackWriter::new(&sfb))
26 };
27 Self { fb_wr }
28 }
29 pub const inp: &'static str = "Signal input";
30
31 pub const DESC: &'static str = "Feedback Delay Writer\n\n\
32HexoSynth does not allow direct feedback cycles in it's graph.\n\
33To make feedback possible anyways the `FbWr` and `FbRd` nodes are provided.\n\
34This node allows you to write a signal into the corresponsing signal delay buffer.\n\
35Use `FbRd` for using the signal. The delay is **3.14ms**.";
36 pub const HELP: &'static str = r#"Feedback Delay Writer
37
38HexoSynth does not allow direct feedback cycles in it's graph.
39To make feedback possible anyways the `FbWr` and `FbRd` nodes are provided.
40This node allows you to send a signal into the corresponding `FbWr` signal
41delay.
42
43The instance id of the node defines which `FbWr` and `FbRd` are connected.
44That means `FbRd 0` is connected to the corresponding `FbWr 0`. You can use
45the signal multiple times by connecting the `FbRd 0` ~~sig~~ port to multiple
46inputs.
47
48The delay is always **3.14ms**, regardless of the sampling rate the synthesizer
49is running at.
50"#;
51
52 pub fn graph_fun() -> Option<GraphFun> {
53 None
54 }
55}
56
57impl DspNode for FbWr {
58 fn set_sample_rate(&mut self, _srate: f32) {}
59 fn reset(&mut self) {}
60
61 #[inline]
62 fn process(
63 &mut self,
64 ctx: &mut dyn NodeAudioContext,
65 _ectx: &mut NodeExecContext,
66 _nctx: &NodeContext,
67 _atoms: &[SAtom],
68 inputs: &[ProcBuf],
69 _outputs: &mut [ProcBuf],
70 ctx_vals: LedPhaseVals,
71 ) {
72 use crate::dsp::inp;
73
74 let inp = inp::FbWr::inp(inputs);
75
76 for frame in 0..ctx.nframes() {
77 self.fb_wr.write(inp.read(frame));
78 }
79
80 ctx_vals[0].set(inp.read(ctx.nframes() - 1));
81 }
82}
83
84#[derive(Debug, Clone)]
86pub struct FbRd {
87 fb_rd: Box<SharedFeedbackReader>,
88}
89
90impl FbRd {
91 pub fn new(nid: &NodeId, node_global: &NodeGlobalRef) -> Self {
92 let fb_rd = if let Ok(mut node_global) = node_global.lock() {
93 node_global.get_feedback_reader(nid.instance() as usize)
94 } else {
95 let sfb = SharedFeedback::new(44100.0);
98 Box::new(SharedFeedbackReader::new(&sfb))
99 };
100 Self { fb_rd }
101 }
102 pub const vol: &'static str = "Volume of the input.\n\
103 Use this to adjust the feedback amount.";
104 pub const sig: &'static str = "Feedback signal output.";
105
106 pub const DESC: &'static str = "Feedback Delay Reader\n\n\
107HexoSynth does not allow direct feedback cycles in it's graph.\n\
108To make feedback possible anyways the `FbWr` and `FbRd` nodes are provided.\n\
109This node allows you to tap into the corresponding `FbWr` signal delay \
110for feedback. The delay is **3.14ms**.";
111 pub const HELP: &'static str = r#"Feedback Delay Reader
112
113HexoSynth does not allow direct feedback cycles in it's graph.
114To make feedback possible anyways the `FbWr` and `FbRd` nodes are provided.
115This node allows you to tap into the corresponding `FbWr` signal delay for
116feedback.
117
118The instance id of the node defines which `FbWr` and `FbRd` are connected.
119That means `FbRd 0` is connected to the corresponding `FbWr 0`. You can use
120the signal multiple times by connecting the `FbRd 0` ~~sig~~ port to multiple
121inputs.
122
123The delay is always **3.14ms**, regardless of the sampling rate the synthesizer
124is running at.
125
126The ~~vol~~ parameter is a convenience parameter to allow to control the
127volume of the feedback.
128"#;
129
130 pub fn graph_fun() -> Option<GraphFun> {
131 None
132 }
133}
134
135impl DspNode for FbRd {
136 fn set_sample_rate(&mut self, _srate: f32) {}
137 fn reset(&mut self) {}
138
139 #[inline]
140 fn process(
141 &mut self,
142 ctx: &mut dyn NodeAudioContext,
143 _ectx: &mut NodeExecContext,
144 _nctx: &NodeContext,
145 _atoms: &[SAtom],
146 inputs: &[ProcBuf],
147 outputs: &mut [ProcBuf],
148 ctx_vals: LedPhaseVals,
149 ) {
150 use crate::dsp::{denorm, inp, out};
151
152 let vol = inp::FbRd::vol(inputs);
153 let sig = out::FbRd::sig(outputs);
154
155 let mut last_val = 0.0;
156 for frame in 0..ctx.nframes() {
157 last_val = self.fb_rd.read();
158 last_val *= denorm::FbRd::vol(vol, frame);
159 sig.write(frame, last_val);
160 }
161
162 ctx_vals[0].set(last_val);
163 }
164}