1use rill_core::{
4 Node, NodeCategory, NodeId, NodeMetadata, NodeState, ParamValue, ParameterId, Port,
5 ProcessError, ProcessResult, Processor, Transcendental,
6};
7use rill_core_dsp::filters::{Biquad, FilterParams, FilterType};
8
9use super::{BandType, FilterFactory, GraphicEq, ParametricEq};
10
11#[derive(Debug, Clone, Default)]
13pub struct BiquadFactory;
14
15impl FilterFactory<Biquad<f32>> for BiquadFactory {
16 fn create_filter(
17 &self,
18 filter_type: FilterType,
19 frequency: f32,
20 q: f32,
21 gain_db: f32,
22 ) -> Biquad<f32> {
23 let params = FilterParams {
24 filter_type,
25 cutoff: frequency,
26 q,
27 gain_db,
28 };
29 Biquad::new(params)
30 }
31}
32
33pub struct ParametricEqProcessor<T: Transcendental, const BUF_SIZE: usize> {
35 id: NodeId,
37 metadata: NodeMetadata,
39 inputs: Vec<Port<T, BUF_SIZE>>,
41 outputs: Vec<Port<T, BUF_SIZE>>,
43 controls: Vec<Port<T, BUF_SIZE>>,
45 state: NodeState<T, BUF_SIZE>,
47 eq: ParametricEq<Biquad<f32>, BiquadFactory>,
49 pub output_gain: f32,
51 num_bands: usize,
53}
54
55impl<T: Transcendental, const BUF_SIZE: usize> ParametricEqProcessor<T, BUF_SIZE> {
56 pub fn new(sample_rate: f32, num_bands: usize) -> Self {
58 let metadata = NodeMetadata::new("ParametricEqProcessor", NodeCategory::Processor);
59
60 let mut inputs = Vec::new();
61 let mut outputs = Vec::new();
62
63 inputs.push(Port::input(NodeId(0), 0, "signal_in"));
65 outputs.push(Port::output(NodeId(0), 0, "signal_out"));
66
67 let factory = BiquadFactory;
68 let mut eq = ParametricEq::new(factory, num_bands, sample_rate);
69 eq.init(sample_rate);
70
71 Self {
72 id: NodeId(0),
73 metadata,
74 inputs,
75 outputs,
76 controls: Vec::new(),
77 state: NodeState::new(sample_rate),
78 eq,
79 output_gain: 1.0,
80 num_bands,
81 }
82 }
83
84 pub fn set_band(
86 &mut self,
87 index: usize,
88 frequency: f32,
89 q: f32,
90 gain_db: f32,
91 ) -> Result<(), rill_core::Error> {
92 self.eq.set_band(index, frequency, q, gain_db)?;
93 Ok(())
94 }
95
96 pub fn set_band_type(
98 &mut self,
99 index: usize,
100 band_type: BandType,
101 ) -> Result<(), rill_core::Error> {
102 self.eq.set_band_type(index, band_type)?;
103 Ok(())
104 }
105
106 pub fn set_band_enabled(
108 &mut self,
109 index: usize,
110 enabled: bool,
111 ) -> Result<(), rill_core::Error> {
112 self.eq.set_band_enabled(index, enabled)?;
113 Ok(())
114 }
115
116 pub fn set_output_gain(&mut self, gain: f32) {
118 self.output_gain = gain.clamp(0.0, 4.0);
119 self.eq.set_output_gain(self.output_gain);
120 }
121
122 pub fn num_bands(&self) -> usize {
124 self.num_bands
125 }
126
127 pub fn eq(&self) -> &ParametricEq<Biquad<f32>, BiquadFactory> {
129 &self.eq
130 }
131
132 pub fn eq_mut(&mut self) -> &mut ParametricEq<Biquad<f32>, BiquadFactory> {
134 &mut self.eq
135 }
136}
137
138impl<T: Transcendental, const BUF_SIZE: usize> Node<T, BUF_SIZE>
139 for ParametricEqProcessor<T, BUF_SIZE>
140{
141 fn node_type_id(&self) -> rill_core::NodeTypeId
142 where
143 Self: 'static + Sized,
144 {
145 rill_core::NodeTypeId::of::<Self>()
146 }
147
148 fn id(&self) -> NodeId {
149 self.id
150 }
151
152 fn set_id(&mut self, id: NodeId) {
153 self.id = id;
154 }
157
158 fn metadata(&self) -> NodeMetadata {
159 self.metadata.clone()
160 }
161
162 fn init(&mut self, sample_rate: f32) {
163 self.state.sample_rate = sample_rate;
164 self.eq.init(sample_rate);
165 }
166
167 fn reset(&mut self) {
168 self.state.sample_pos = 0;
169 self.state.blocks_processed = 0;
170 self.eq.reset();
171 }
172
173 fn get_parameter(&self, id: &ParameterId) -> Option<ParamValue> {
174 let name = id.as_str();
175 if name == "output_gain" {
176 return Some(ParamValue::Float(self.output_gain));
177 }
178
179 let parts: Vec<&str> = name.split('_').collect();
181 if parts.len() >= 3 && parts[0] == "band" {
182 if let Ok(index) = parts[1].parse::<usize>() {
183 if index < self.num_bands {
184 let field = parts[2];
185 match field {
186 "freq" => {
187 return self.eq.get_band_frequency(index).map(ParamValue::Float);
188 }
189 "q" => {
190 return self.eq.get_band_q(index).map(ParamValue::Float);
191 }
192 "gain" => {
193 return self.eq.get_band_gain(index).map(ParamValue::Float);
194 }
195 "enabled" => {
196 return self.eq.get_band_enabled(index).map(ParamValue::Bool);
197 }
198 _ => {}
199 }
200 }
201 }
202 }
203
204 None
205 }
206
207 fn set_parameter(&mut self, id: &ParameterId, value: ParamValue) -> ProcessResult<()> {
208 let name = id.as_str();
209 if name == "output_gain" {
210 if let Some(v) = value.as_f32() {
211 self.set_output_gain(v);
212 Ok(())
213 } else {
214 Err(ProcessError::parameter("Expected float value"))
215 }
216 } else {
217 let parts: Vec<&str> = name.split('_').collect();
219 if parts.len() >= 3 && parts[0] == "band" {
220 if let Ok(index) = parts[1].parse::<usize>() {
221 if index >= self.num_bands {
222 return Err(ProcessError::parameter(format!(
223 "Band index {} out of range",
224 index
225 )));
226 }
227 let field = parts[2];
228 match field {
229 "freq" => {
230 if let Some(v) = value.as_f32() {
231 self.eq
232 .set_band(
233 index,
234 v,
235 self.eq.get_band_q(index).unwrap_or(1.0),
236 self.eq.get_band_gain(index).unwrap_or(0.0),
237 )
238 .map_err(|e| ProcessError::parameter(e.to_string()))?;
239 Ok(())
240 } else {
241 Err(ProcessError::parameter("Expected float value"))
242 }
243 }
244 "q" => {
245 if let Some(v) = value.as_f32() {
246 self.eq
247 .set_band(
248 index,
249 self.eq.get_band_frequency(index).unwrap_or(1000.0),
250 v,
251 self.eq.get_band_gain(index).unwrap_or(0.0),
252 )
253 .map_err(|e| ProcessError::parameter(e.to_string()))?;
254 Ok(())
255 } else {
256 Err(ProcessError::parameter("Expected float value"))
257 }
258 }
259 "gain" => {
260 if let Some(v) = value.as_f32() {
261 self.eq
262 .set_band(
263 index,
264 self.eq.get_band_frequency(index).unwrap_or(1000.0),
265 self.eq.get_band_q(index).unwrap_or(1.0),
266 v,
267 )
268 .map_err(|e| ProcessError::parameter(e.to_string()))?;
269 Ok(())
270 } else {
271 Err(ProcessError::parameter("Expected float value"))
272 }
273 }
274 "enabled" => {
275 if let Some(b) = value.as_bool() {
276 self.eq
277 .set_band_enabled(index, b)
278 .map_err(|e| ProcessError::parameter(e.to_string()))?;
279 Ok(())
280 } else {
281 Err(ProcessError::parameter("Expected boolean value"))
282 }
283 }
284 _ => Err(ProcessError::parameter(format!(
285 "Unknown band field: {}",
286 field
287 ))),
288 }
289 } else {
290 Err(ProcessError::parameter(format!(
291 "Invalid band index: {}",
292 parts[1]
293 )))
294 }
295 } else {
296 Err(ProcessError::parameter(format!(
297 "Unknown parameter: {}",
298 name
299 )))
300 }
301 }
302 }
303
304 fn input_port(&self, index: usize) -> Option<&Port<T, BUF_SIZE>> {
305 self.inputs.get(index)
306 }
307
308 fn input_port_mut(&mut self, index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
309 self.inputs.get_mut(index)
310 }
311
312 fn output_port(&self, index: usize) -> Option<&Port<T, BUF_SIZE>> {
313 self.outputs.get(index)
314 }
315
316 fn output_port_mut(&mut self, index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
317 self.outputs.get_mut(index)
318 }
319
320 fn control_port(&self, index: usize) -> Option<&Port<T, BUF_SIZE>> {
321 self.controls.get(index)
322 }
323
324 fn control_port_mut(&mut self, index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
325 self.controls.get_mut(index)
326 }
327
328 fn num_inputs(&self) -> usize {
329 self.inputs.len()
330 }
331
332 fn num_outputs(&self) -> usize {
333 self.outputs.len()
334 }
335
336 fn num_signal_inputs(&self) -> usize {
337 self.inputs.len()
338 }
339
340 fn num_signal_outputs(&self) -> usize {
341 self.outputs.len()
342 }
343
344 fn state(&self) -> &NodeState<T, BUF_SIZE> {
345 &self.state
346 }
347
348 fn state_mut(&mut self) -> &mut NodeState<T, BUF_SIZE> {
349 &mut self.state
350 }
351}
352
353impl<T: Transcendental, const BUF_SIZE: usize> Processor<T, BUF_SIZE>
354 for ParametricEqProcessor<T, BUF_SIZE>
355{
356 fn process(
357 &mut self,
358 _ctx: &rill_core::RenderContext,
359 _signal_inputs: &[&[T; BUF_SIZE]],
360 _control_inputs: &[T],
361 _clock_inputs: &[rill_core::RenderContext],
362 _feedback_inputs: &[&[T; BUF_SIZE]],
363 ) -> ProcessResult<()> {
364 let input_buf = *self.inputs[0].read();
365 let output_buf = self.outputs[0].write();
366
367 let mut input_f32 = [0.0f32; BUF_SIZE];
368 for (dest, &src) in input_f32.iter_mut().zip(input_buf.iter()) {
369 *dest = src.to_f32();
370 }
371
372 let mut output_f32 = [0.0f32; BUF_SIZE];
373 self.eq.process_block(&input_f32, &mut output_f32);
374
375 for (dest, &src) in output_buf.iter_mut().zip(output_f32.iter()) {
376 *dest = T::from_f32(src);
377 }
378
379 Ok(())
380 }
381
382 fn latency(&self) -> usize {
383 0
384 }
385}
386
387pub struct GraphicEqProcessor<T: Transcendental, const BUF_SIZE: usize> {
389 id: NodeId,
391 metadata: NodeMetadata,
393 inputs: Vec<Port<T, BUF_SIZE>>,
395 outputs: Vec<Port<T, BUF_SIZE>>,
397 controls: Vec<Port<T, BUF_SIZE>>,
399 state: NodeState<T, BUF_SIZE>,
401 eq: GraphicEq<Biquad<f32>>,
403 pub output_gain: f32,
405 num_bands: usize,
407}
408
409impl<T: Transcendental, const BUF_SIZE: usize> GraphicEqProcessor<T, BUF_SIZE> {
410 pub fn new_third_octave(sample_rate: f32) -> Self {
412 let metadata = NodeMetadata::new("GraphicEqProcessor", NodeCategory::Processor);
413
414 let mut inputs = Vec::new();
415 let mut outputs = Vec::new();
416
417 inputs.push(Port::input(NodeId(0), 0, "signal_in"));
418 outputs.push(Port::output(NodeId(0), 0, "signal_out"));
419
420 let factory = BiquadFactory;
421 let mut eq = GraphicEq::new_third_octave(factory, sample_rate);
422 eq.init(sample_rate);
423
424 let num_bands = eq.num_bands();
425
426 Self {
427 id: NodeId(0),
428 metadata,
429 inputs,
430 outputs,
431 controls: Vec::new(),
432 state: NodeState::new(sample_rate),
433 eq,
434 output_gain: 1.0,
435 num_bands,
436 }
437 }
438
439 pub fn with_frequencies(frequencies: Vec<f32>, sample_rate: f32) -> Self {
441 let metadata = NodeMetadata::new("GraphicEqProcessor", NodeCategory::Processor);
442
443 let mut inputs = Vec::new();
444 let mut outputs = Vec::new();
445
446 inputs.push(Port::input(NodeId(0), 0, "signal_in"));
447 outputs.push(Port::output(NodeId(0), 0, "signal_out"));
448
449 let factory = BiquadFactory;
450 let mut eq = GraphicEq::with_frequencies(factory, frequencies, sample_rate);
451 eq.init(sample_rate);
452
453 let num_bands = eq.num_bands();
454
455 Self {
456 id: NodeId(0),
457 metadata,
458 inputs,
459 outputs,
460 controls: Vec::new(),
461 state: NodeState::new(sample_rate),
462 eq,
463 output_gain: 1.0,
464 num_bands,
465 }
466 }
467
468 pub fn set_band_gain(&mut self, index: usize, gain_db: f32) -> Result<(), rill_core::Error> {
470 self.eq.set_band_gain(index, gain_db)?;
471 Ok(())
472 }
473
474 pub fn set_band_enabled(
476 &mut self,
477 index: usize,
478 enabled: bool,
479 ) -> Result<(), rill_core::Error> {
480 self.eq.set_band_enabled(index, enabled)?;
481 Ok(())
482 }
483
484 pub fn set_output_gain(&mut self, gain: f32) {
486 self.output_gain = gain.clamp(0.0, 4.0);
487 self.eq.set_output_gain(self.output_gain);
488 }
489
490 pub fn num_bands(&self) -> usize {
492 self.num_bands
493 }
494
495 pub fn eq(&self) -> &GraphicEq<Biquad<f32>> {
497 &self.eq
498 }
499
500 pub fn eq_mut(&mut self) -> &mut GraphicEq<Biquad<f32>> {
502 &mut self.eq
503 }
504}
505
506impl<T: Transcendental, const BUF_SIZE: usize> Node<T, BUF_SIZE>
507 for GraphicEqProcessor<T, BUF_SIZE>
508{
509 fn node_type_id(&self) -> rill_core::NodeTypeId
510 where
511 Self: 'static + Sized,
512 {
513 rill_core::NodeTypeId::of::<Self>()
514 }
515
516 fn id(&self) -> NodeId {
517 self.id
518 }
519
520 fn set_id(&mut self, id: NodeId) {
521 self.id = id;
522 }
523
524 fn metadata(&self) -> NodeMetadata {
525 self.metadata.clone()
526 }
527
528 fn init(&mut self, sample_rate: f32) {
529 self.state.sample_rate = sample_rate;
530 self.eq.init(sample_rate);
531 }
532
533 fn reset(&mut self) {
534 self.state.sample_pos = 0;
535 self.state.blocks_processed = 0;
536 self.eq.reset();
537 }
538
539 fn get_parameter(&self, id: &ParameterId) -> Option<ParamValue> {
540 let name = id.as_str();
541 if name == "output_gain" {
542 return Some(ParamValue::Float(self.output_gain));
543 }
544
545 let parts: Vec<&str> = name.split('_').collect();
547 if parts.len() >= 3 && parts[0] == "band" {
548 if let Ok(index) = parts[1].parse::<usize>() {
549 if index < self.num_bands {
550 let field = parts[2];
551 match field {
552 "gain" => {
553 return self.eq.get_band_gain(index).map(ParamValue::Float);
554 }
555 "enabled" => {
556 return self.eq.get_band_enabled(index).map(ParamValue::Bool);
557 }
558 _ => {}
559 }
560 }
561 }
562 }
563
564 None
565 }
566
567 fn set_parameter(&mut self, id: &ParameterId, value: ParamValue) -> ProcessResult<()> {
568 let name = id.as_str();
569 if name == "output_gain" {
570 if let Some(v) = value.as_f32() {
571 self.set_output_gain(v);
572 Ok(())
573 } else {
574 Err(ProcessError::parameter("Expected float value"))
575 }
576 } else {
577 let parts: Vec<&str> = name.split('_').collect();
579 if parts.len() >= 3 && parts[0] == "band" {
580 if let Ok(index) = parts[1].parse::<usize>() {
581 if index >= self.num_bands {
582 return Err(ProcessError::parameter(format!(
583 "Band index {} out of range",
584 index
585 )));
586 }
587 let field = parts[2];
588 match field {
589 "gain" => {
590 if let Some(v) = value.as_f32() {
591 self.eq
592 .set_band_gain(index, v)
593 .map_err(|e| ProcessError::parameter(e.to_string()))?;
594 Ok(())
595 } else {
596 Err(ProcessError::parameter("Expected float value"))
597 }
598 }
599 "enabled" => {
600 if let Some(b) = value.as_bool() {
601 self.eq
602 .set_band_enabled(index, b)
603 .map_err(|e| ProcessError::parameter(e.to_string()))?;
604 Ok(())
605 } else {
606 Err(ProcessError::parameter("Expected boolean value"))
607 }
608 }
609 _ => Err(ProcessError::parameter(format!(
610 "Unknown band field: {}",
611 field
612 ))),
613 }
614 } else {
615 Err(ProcessError::parameter(format!(
616 "Invalid band index: {}",
617 parts[1]
618 )))
619 }
620 } else {
621 Err(ProcessError::parameter(format!(
622 "Unknown parameter: {}",
623 name
624 )))
625 }
626 }
627 }
628
629 fn input_port(&self, index: usize) -> Option<&Port<T, BUF_SIZE>> {
630 self.inputs.get(index)
631 }
632
633 fn input_port_mut(&mut self, index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
634 self.inputs.get_mut(index)
635 }
636
637 fn output_port(&self, index: usize) -> Option<&Port<T, BUF_SIZE>> {
638 self.outputs.get(index)
639 }
640
641 fn output_port_mut(&mut self, index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
642 self.outputs.get_mut(index)
643 }
644
645 fn control_port(&self, index: usize) -> Option<&Port<T, BUF_SIZE>> {
646 self.controls.get(index)
647 }
648
649 fn control_port_mut(&mut self, index: usize) -> Option<&mut Port<T, BUF_SIZE>> {
650 self.controls.get_mut(index)
651 }
652
653 fn num_inputs(&self) -> usize {
654 self.inputs.len()
655 }
656
657 fn num_outputs(&self) -> usize {
658 self.outputs.len()
659 }
660
661 fn num_signal_inputs(&self) -> usize {
662 self.inputs.len()
663 }
664
665 fn num_signal_outputs(&self) -> usize {
666 self.outputs.len()
667 }
668
669 fn state(&self) -> &NodeState<T, BUF_SIZE> {
670 &self.state
671 }
672
673 fn state_mut(&mut self) -> &mut NodeState<T, BUF_SIZE> {
674 &mut self.state
675 }
676}
677
678impl<T: Transcendental, const BUF_SIZE: usize> Processor<T, BUF_SIZE>
679 for GraphicEqProcessor<T, BUF_SIZE>
680{
681 fn process(
682 &mut self,
683 _ctx: &rill_core::RenderContext,
684 _signal_inputs: &[&[T; BUF_SIZE]],
685 _control_inputs: &[T],
686 _clock_inputs: &[rill_core::RenderContext],
687 _feedback_inputs: &[&[T; BUF_SIZE]],
688 ) -> ProcessResult<()> {
689 let input_buf = *self.inputs[0].read();
690 let output_buf = self.outputs[0].write();
691
692 let mut input_f32 = [0.0f32; BUF_SIZE];
693 for (dest, &src) in input_f32.iter_mut().zip(input_buf.iter()) {
694 *dest = src.to_f32();
695 }
696
697 let mut output_f32 = [0.0f32; BUF_SIZE];
698 self.eq.process_block(&input_f32, &mut output_f32);
699
700 for (dest, &src) in output_buf.iter_mut().zip(output_f32.iter()) {
701 *dest = T::from_f32(src);
702 }
703
704 Ok(())
705 }
706
707 fn latency(&self) -> usize {
708 0
709 }
710}