1use rill_core::{
4 buffer::DelayLine,
5 math::Transcendental,
6 traits::{Node, NodeCategory, NodeMetadata, NodeState, Processor},
7 NodeId, ParamValue, ParameterId, Port, ProcessError, ProcessResult, RenderContext,
8};
9
10const MAX_DELAY_SECONDS: f32 = 0.5;
12const MAX_SAMPLE_RATE: f32 = 48_000.0;
14const MAX_DELAY_SAMPLES: usize = (MAX_DELAY_SECONDS * MAX_SAMPLE_RATE) as usize;
16
17pub struct Delay<T: Transcendental, const BUF_SIZE: usize> {
24 id: NodeId,
26 metadata: NodeMetadata,
28 inputs: Vec<Port<T, BUF_SIZE>>,
30 outputs: Vec<Port<T, BUF_SIZE>>,
32 controls: Vec<Port<T, BUF_SIZE>>,
34 state: NodeState<T, BUF_SIZE>,
36 pub delay_time: f32,
38 delay_samples: usize,
40 pub feedback: f32,
42 pub mix: f32,
44 delay_line: DelayLine<T, MAX_DELAY_SAMPLES>,
46 sample_rate: f32,
48}
49
50impl<T: Transcendental, const BUF_SIZE: usize> Delay<T, BUF_SIZE> {
51 pub fn new(sample_rate: f32) -> Self {
53 let metadata = NodeMetadata::new("Delay", NodeCategory::Processor);
54
55 let mut inputs = Vec::new();
56 let mut outputs = Vec::new();
57
58 inputs.push(Port::input(NodeId(0), 0, "signal_in"));
60 outputs.push(Port::output(NodeId(0), 0, "signal_out"));
61
62 let delay_time = 0.5;
63 let delay_samples = (delay_time * sample_rate) as usize;
64 let mut delay_line = DelayLine::new(sample_rate);
65 delay_line.set_delay_samples(delay_samples);
66
67 Self {
68 id: NodeId(0),
69 metadata,
70 inputs,
71 outputs,
72 controls: Vec::new(),
73 state: NodeState::new(sample_rate),
74 delay_time,
75 delay_samples,
76 feedback: 0.3,
77 mix: 0.5,
78 delay_line,
79 sample_rate,
80 }
81 }
82
83 pub fn with_params(sample_rate: f32, delay_time: f32, feedback: f32, mix: f32) -> Self {
85 let mut instance = Self::new(sample_rate);
86 instance.set_delay_time(delay_time);
87 instance.set_feedback(feedback);
88 instance.set_mix(mix);
89 instance
90 }
91
92 pub fn set_delay_time(&mut self, time: f32) {
94 self.delay_time = time.clamp(0.01, MAX_DELAY_SECONDS);
95 self.update_delay_samples();
96 }
97
98 pub fn set_feedback(&mut self, fb: f32) {
100 self.feedback = fb.clamp(0.0, 0.99);
101 }
102
103 pub fn set_mix(&mut self, mix: f32) {
105 self.mix = mix.clamp(0.0, 1.0);
106 }
107
108 fn update_delay_samples(&mut self) {
110 self.delay_samples = (self.delay_time * self.sample_rate) as usize;
111 if self.delay_samples >= MAX_DELAY_SAMPLES {
112 self.delay_samples = MAX_DELAY_SAMPLES - 1;
113 }
114 self.delay_line.set_delay_samples(self.delay_samples);
115 }
116
117 pub fn process_sample(&mut self, input: T) -> T {
119 let delayed = self.delay_line.read_delayed(self.delay_samples);
121 let dry = input;
123 let wet = delayed;
124 let mix = T::from_f32(self.mix);
125 let one_minus_mix = T::ONE - mix;
126 let output = dry.mul(one_minus_mix).add(wet.mul(mix));
127 let feedback = T::from_f32(self.feedback);
129 let write_sample = input.add(delayed.mul(feedback));
130 self.delay_line.write(write_sample);
131 output
132 }
133}
134
135impl<T: Transcendental, const BUF_SIZE: usize> Node<T, BUF_SIZE> for Delay<T, BUF_SIZE> {
136 fn node_type_id(&self) -> rill_core::NodeTypeId
137 where
138 Self: 'static + Sized,
139 {
140 rill_core::NodeTypeId::of::<Self>()
141 }
142
143 fn id(&self) -> NodeId {
144 self.id
145 }
146
147 fn set_id(&mut self, id: NodeId) {
148 self.id = id;
149 }
151
152 fn metadata(&self) -> NodeMetadata {
153 self.metadata.clone()
154 }
155
156 fn init(&mut self, sample_rate: f32) {
157 self.sample_rate = sample_rate;
158 self.update_delay_samples();
159 self.delay_line.clear();
160 }
161
162 fn reset(&mut self) {
163 self.state.sample_pos = 0;
164 self.state.blocks_processed = 0;
165 self.delay_line.clear();
166 }
167
168 fn get_parameter(&self, id: &ParameterId) -> Option<ParamValue> {
169 let name = id.as_str();
170 match name {
171 "delay_time" => Some(ParamValue::Float(self.delay_time)),
172 "feedback" => Some(ParamValue::Float(self.feedback)),
173 "mix" => Some(ParamValue::Float(self.mix)),
174 _ => None,
175 }
176 }
177
178 fn set_parameter(&mut self, id: &ParameterId, value: ParamValue) -> ProcessResult<()> {
179 let name = id.as_str();
180 if let Some(v) = value.as_f32() {
181 match name {
182 "delay_time" => {
183 self.set_delay_time(v);
184 Ok(())
185 }
186 "feedback" => {
187 self.set_feedback(v);
188 Ok(())
189 }
190 "mix" => {
191 self.set_mix(v);
192 Ok(())
193 }
194 _ => Err(ProcessError::parameter(format!(
195 "Unknown parameter: {}",
196 name
197 ))),
198 }
199 } else {
200 Err(ProcessError::parameter("Expected float value"))
201 }
202 }
203
204 fn input_port(&self, index: usize) -> Option<&Port<T, BUF_SIZE>> {
205 self.inputs.get(index)
206 }
207
208 fn input_port_mut(&mut self, index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
209 self.inputs.get_mut(index)
210 }
211
212 fn output_port(&self, index: usize) -> Option<&Port<T, BUF_SIZE>> {
213 self.outputs.get(index)
214 }
215
216 fn output_port_mut(&mut self, index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
217 self.outputs.get_mut(index)
218 }
219
220 fn control_port(&self, index: usize) -> Option<&Port<T, BUF_SIZE>> {
221 self.controls.get(index)
222 }
223
224 fn control_port_mut(&mut self, index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
225 self.controls.get_mut(index)
226 }
227
228 fn num_inputs(&self) -> usize {
229 self.inputs.len()
230 }
231
232 fn num_outputs(&self) -> usize {
233 self.outputs.len()
234 }
235
236 fn num_signal_inputs(&self) -> usize {
237 self.inputs.len()
238 }
239
240 fn num_signal_outputs(&self) -> usize {
241 self.outputs.len()
242 }
243
244 fn state(&self) -> &NodeState<T, BUF_SIZE> {
245 &self.state
246 }
247
248 fn state_mut(&mut self) -> &mut NodeState<T, BUF_SIZE> {
249 &mut self.state
250 }
251}
252
253impl<T: Transcendental, const BUF_SIZE: usize> Processor<T, BUF_SIZE> for Delay<T, BUF_SIZE> {
254 fn process(
255 &mut self,
256 _ctx: &RenderContext,
257 _signal_inputs: &[&[T; BUF_SIZE]],
258 _control_inputs: &[T],
259 _clock_inputs: &[RenderContext],
260 _feedback_inputs: &[&[T; BUF_SIZE]],
261 ) -> ProcessResult<()> {
262 let inp = self.inputs[0].read();
263 let out = self.outputs[0].write();
264 let mix = T::from_f32(self.mix);
265 let one_minus_mix = T::ONE - mix;
266 let feedback = T::from_f32(self.feedback);
267 let delay_samples = self.delay_samples;
268 for i in 0..BUF_SIZE {
269 let input = inp[i];
270 let delayed = self.delay_line.read_delayed(delay_samples);
271 let output = input.mul(one_minus_mix).add(delayed.mul(mix));
272 let write_sample = input.add(delayed.mul(feedback));
273 self.delay_line.write(write_sample);
274 out[i] = output;
275 }
276 self.state.advance();
277 Ok(())
278 }
279
280 fn latency(&self) -> usize {
281 0
282 }
283}