1use crate::{
7 blocks::{
8 effectors::{
9 ambisonic_decoder::AmbisonicDecoderBlock, binaural_decoder::BinauralDecoderBlock,
10 channel_merger::ChannelMergerBlock, channel_router::ChannelRouterBlock,
11 channel_splitter::ChannelSplitterBlock, dc_blocker::DcBlockerBlock, gain::GainBlock,
12 low_pass_filter::LowPassFilterBlock, matrix_mixer::MatrixMixerBlock, mixer::MixerBlock,
13 overdrive::OverdriveBlock, panner::PannerBlock, vca::VcaBlock,
14 },
15 generators::oscillator::OscillatorBlock,
16 io::{file_input::FileInputBlock, file_output::FileOutputBlock, output::OutputBlock},
17 modulators::{envelope::EnvelopeBlock, lfo::LfoBlock},
18 },
19 channel::ChannelConfig,
20 context::DspContext,
21 parameter::{ModulationOutput, Parameter},
22 sample::Sample,
23};
24
25pub(crate) const DEFAULT_EFFECTOR_INPUT_COUNT: usize = 1;
27pub(crate) const DEFAULT_EFFECTOR_OUTPUT_COUNT: usize = 1;
29
30pub(crate) const DEFAULT_GENERATOR_INPUT_COUNT: usize = 0;
32pub(crate) const DEFAULT_GENERATOR_OUTPUT_COUNT: usize = 1;
34
35pub(crate) const DEFAULT_MODULATOR_INPUT_COUNT: usize = 0;
37pub(crate) const DEFAULT_MODULATOR_OUTPUT_COUNT: usize = 1;
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
45pub struct BlockId(pub usize);
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
49pub enum BlockCategory {
50 Generator,
52 Effector,
54 Modulator,
56 IO,
58}
59
60pub trait Block<S: Sample> {
66 fn process(&mut self, inputs: &[&[S]], outputs: &mut [&mut [S]], modulation_values: &[S], context: &DspContext);
75
76 fn input_count(&self) -> usize;
78
79 fn output_count(&self) -> usize;
81
82 fn modulation_outputs(&self) -> &[ModulationOutput];
87
88 fn channel_config(&self) -> ChannelConfig {
94 ChannelConfig::Parallel
95 }
96
97 fn set_smoothing(&mut self, _sample_rate: f64, _ramp_time_ms: f64) {}
105}
106
107pub enum BlockType<S: Sample> {
112 FileInput(FileInputBlock<S>),
115 FileOutput(FileOutputBlock<S>),
117 Output(OutputBlock<S>),
119
120 Oscillator(OscillatorBlock<S>),
123
124 AmbisonicDecoder(AmbisonicDecoderBlock<S>),
127 BinauralDecoder(BinauralDecoderBlock<S>),
129 ChannelMerger(ChannelMergerBlock<S>),
131 ChannelRouter(ChannelRouterBlock<S>),
133 ChannelSplitter(ChannelSplitterBlock<S>),
135 DcBlocker(DcBlockerBlock<S>),
137 Gain(GainBlock<S>),
139 LowPassFilter(LowPassFilterBlock<S>),
141 MatrixMixer(MatrixMixerBlock<S>),
143 Mixer(MixerBlock<S>),
145 Overdrive(OverdriveBlock<S>),
147 Panner(PannerBlock<S>),
149 Vca(VcaBlock<S>),
151
152 Envelope(EnvelopeBlock<S>),
155 Lfo(LfoBlock<S>),
157}
158
159impl<S: Sample> BlockType<S> {
160 #[inline]
162 pub fn process(
163 &mut self,
164 inputs: &[&[S]],
165 outputs: &mut [&mut [S]],
166 modulation_values: &[S],
167 context: &DspContext,
168 ) {
169 match self {
170 BlockType::FileInput(block) => block.process(inputs, outputs, modulation_values, context),
172 BlockType::FileOutput(block) => block.process(inputs, outputs, modulation_values, context),
173 BlockType::Output(block) => block.process(inputs, outputs, modulation_values, context),
174
175 BlockType::Oscillator(block) => block.process(inputs, outputs, modulation_values, context),
177
178 BlockType::AmbisonicDecoder(block) => block.process(inputs, outputs, modulation_values, context),
180 BlockType::BinauralDecoder(block) => block.process(inputs, outputs, modulation_values, context),
181 BlockType::ChannelMerger(block) => block.process(inputs, outputs, modulation_values, context),
182 BlockType::ChannelRouter(block) => block.process(inputs, outputs, modulation_values, context),
183 BlockType::ChannelSplitter(block) => block.process(inputs, outputs, modulation_values, context),
184 BlockType::DcBlocker(block) => block.process(inputs, outputs, modulation_values, context),
185 BlockType::Gain(block) => block.process(inputs, outputs, modulation_values, context),
186 BlockType::LowPassFilter(block) => block.process(inputs, outputs, modulation_values, context),
187 BlockType::MatrixMixer(block) => block.process(inputs, outputs, modulation_values, context),
188 BlockType::Mixer(block) => block.process(inputs, outputs, modulation_values, context),
189 BlockType::Overdrive(block) => block.process(inputs, outputs, modulation_values, context),
190 BlockType::Panner(block) => block.process(inputs, outputs, modulation_values, context),
191 BlockType::Vca(block) => block.process(inputs, outputs, modulation_values, context),
192
193 BlockType::Envelope(block) => block.process(inputs, outputs, modulation_values, context),
195 BlockType::Lfo(block) => block.process(inputs, outputs, modulation_values, context),
196 }
197 }
198
199 #[inline]
201 pub fn input_count(&self) -> usize {
202 match self {
203 BlockType::FileInput(block) => block.input_count(),
205 BlockType::FileOutput(block) => block.input_count(),
206 BlockType::Output(block) => block.input_count(),
207
208 BlockType::Oscillator(block) => block.input_count(),
210
211 BlockType::AmbisonicDecoder(block) => block.input_count(),
213 BlockType::BinauralDecoder(block) => block.input_count(),
214 BlockType::ChannelMerger(block) => block.input_count(),
215 BlockType::ChannelRouter(block) => block.input_count(),
216 BlockType::ChannelSplitter(block) => block.input_count(),
217 BlockType::DcBlocker(block) => block.input_count(),
218 BlockType::Gain(block) => block.input_count(),
219 BlockType::LowPassFilter(block) => block.input_count(),
220 BlockType::MatrixMixer(block) => block.input_count(),
221 BlockType::Mixer(block) => block.input_count(),
222 BlockType::Overdrive(block) => block.input_count(),
223 BlockType::Panner(block) => block.input_count(),
224 BlockType::Vca(block) => block.input_count(),
225
226 BlockType::Envelope(block) => block.input_count(),
228 BlockType::Lfo(block) => block.input_count(),
229 }
230 }
231
232 #[inline]
234 pub fn output_count(&self) -> usize {
235 match self {
236 BlockType::FileInput(block) => block.output_count(),
238 BlockType::FileOutput(block) => block.output_count(),
239 BlockType::Output(block) => block.output_count(),
240
241 BlockType::Oscillator(block) => block.output_count(),
243
244 BlockType::AmbisonicDecoder(block) => block.output_count(),
246 BlockType::BinauralDecoder(block) => block.output_count(),
247 BlockType::ChannelMerger(block) => block.output_count(),
248 BlockType::ChannelRouter(block) => block.output_count(),
249 BlockType::ChannelSplitter(block) => block.output_count(),
250 BlockType::DcBlocker(block) => block.output_count(),
251 BlockType::Gain(block) => block.output_count(),
252 BlockType::LowPassFilter(block) => block.output_count(),
253 BlockType::MatrixMixer(block) => block.output_count(),
254 BlockType::Mixer(block) => block.output_count(),
255 BlockType::Overdrive(block) => block.output_count(),
256 BlockType::Panner(block) => block.output_count(),
257 BlockType::Vca(block) => block.output_count(),
258
259 BlockType::Envelope(block) => block.output_count(),
261 BlockType::Lfo(block) => block.output_count(),
262 }
263 }
264
265 #[inline]
267 pub fn modulation_outputs(&self) -> &[ModulationOutput] {
268 match self {
269 BlockType::FileInput(block) => block.modulation_outputs(),
271 BlockType::FileOutput(block) => block.modulation_outputs(),
272 BlockType::Output(block) => block.modulation_outputs(),
273
274 BlockType::Oscillator(block) => block.modulation_outputs(),
276
277 BlockType::AmbisonicDecoder(block) => block.modulation_outputs(),
279 BlockType::BinauralDecoder(block) => block.modulation_outputs(),
280 BlockType::ChannelMerger(block) => block.modulation_outputs(),
281 BlockType::ChannelRouter(block) => block.modulation_outputs(),
282 BlockType::ChannelSplitter(block) => block.modulation_outputs(),
283 BlockType::DcBlocker(block) => block.modulation_outputs(),
284 BlockType::Gain(block) => block.modulation_outputs(),
285 BlockType::LowPassFilter(block) => block.modulation_outputs(),
286 BlockType::MatrixMixer(block) => block.modulation_outputs(),
287 BlockType::Mixer(block) => block.modulation_outputs(),
288 BlockType::Overdrive(block) => block.modulation_outputs(),
289 BlockType::Panner(block) => block.modulation_outputs(),
290 BlockType::Vca(block) => block.modulation_outputs(),
291
292 BlockType::Envelope(block) => block.modulation_outputs(),
294 BlockType::Lfo(block) => block.modulation_outputs(),
295 }
296 }
297
298 #[inline]
300 pub fn channel_config(&self) -> ChannelConfig {
301 match self {
302 BlockType::FileInput(block) => block.channel_config(),
304 BlockType::FileOutput(block) => block.channel_config(),
305 BlockType::Output(block) => block.channel_config(),
306
307 BlockType::Oscillator(block) => block.channel_config(),
309
310 BlockType::AmbisonicDecoder(block) => block.channel_config(),
312 BlockType::BinauralDecoder(block) => block.channel_config(),
313 BlockType::ChannelMerger(block) => block.channel_config(),
314 BlockType::ChannelRouter(block) => block.channel_config(),
315 BlockType::ChannelSplitter(block) => block.channel_config(),
316 BlockType::DcBlocker(block) => block.channel_config(),
317 BlockType::Gain(block) => block.channel_config(),
318 BlockType::LowPassFilter(block) => block.channel_config(),
319 BlockType::MatrixMixer(block) => block.channel_config(),
320 BlockType::Mixer(block) => block.channel_config(),
321 BlockType::Overdrive(block) => block.channel_config(),
322 BlockType::Panner(block) => block.channel_config(),
323 BlockType::Vca(block) => block.channel_config(),
324
325 BlockType::Envelope(block) => block.channel_config(),
327 BlockType::Lfo(block) => block.channel_config(),
328 }
329 }
330
331 pub fn set_smoothing(&mut self, sample_rate: f64, ramp_time_ms: f64) {
336 match self {
337 BlockType::Panner(block) => block.set_smoothing(sample_rate, ramp_time_ms),
338 BlockType::Gain(block) => block.set_smoothing(sample_rate, ramp_time_ms),
339 BlockType::Overdrive(block) => block.set_smoothing(sample_rate, ramp_time_ms),
340 _ => {} }
342 }
343
344 pub fn set_parameter(&mut self, parameter_name: &str, parameter: Parameter<S>) -> Result<(), String> {
346 match self {
347 BlockType::FileInput(_) => Err("File input blocks have no modulated parameters".to_string()),
349 BlockType::FileOutput(_) => Err("File output blocks have no modulated parameters".to_string()),
350 BlockType::Output(_) => Err("Output blocks have no modulated parameters".to_string()),
351
352 BlockType::Oscillator(block) => match parameter_name.to_lowercase().as_str() {
354 "frequency" => {
355 block.frequency = parameter;
356 Ok(())
357 }
358 "pitch_offset" => {
359 block.pitch_offset = parameter;
360 Ok(())
361 }
362 _ => Err(format!("Unknown oscillator parameter: {parameter_name}")),
363 },
364
365 BlockType::AmbisonicDecoder(_) => Err("Ambisonic decoder has no modulated parameters".to_string()),
367 BlockType::BinauralDecoder(_) => Err("Binaural decoder has no modulated parameters".to_string()),
368 BlockType::ChannelMerger(_) => Err("Channel merger has no modulated parameters".to_string()),
369 BlockType::ChannelRouter(_) => Err("Channel router uses direct field access, not Parameter<S>".to_string()),
370 BlockType::ChannelSplitter(_) => Err("Channel splitter has no modulated parameters".to_string()),
371 BlockType::DcBlocker(_) => Err("DC blocker uses direct field access, not Parameter<S>".to_string()),
372 BlockType::Gain(block) => match parameter_name.to_lowercase().as_str() {
373 "level" | "level_db" => {
374 block.level_db = parameter;
375 Ok(())
376 }
377 _ => Err(format!("Unknown gain parameter: {parameter_name}")),
378 },
379 BlockType::LowPassFilter(block) => match parameter_name.to_lowercase().as_str() {
380 "cutoff" | "frequency" => {
381 block.cutoff = parameter;
382 Ok(())
383 }
384 "resonance" | "q" => {
385 block.resonance = parameter;
386 Ok(())
387 }
388 _ => Err(format!("Unknown low-pass filter parameter: {parameter_name}")),
389 },
390 BlockType::MatrixMixer(_) => Err("Matrix mixer uses set_gain method, not Parameter<S>".to_string()),
391 BlockType::Mixer(_) => Err("Mixer has no modulated parameters".to_string()),
392 BlockType::Overdrive(block) => match parameter_name.to_lowercase().as_str() {
393 "drive" => {
394 block.drive = parameter;
395 Ok(())
396 }
397 "level" => {
398 block.level = parameter;
399 Ok(())
400 }
401 _ => Err(format!("Unknown overdrive parameter: {parameter_name}")),
402 },
403 BlockType::Panner(block) => match parameter_name.to_lowercase().as_str() {
404 "position" | "pan" => {
405 block.position = parameter;
406 Ok(())
407 }
408 "azimuth" => {
409 block.azimuth = parameter;
410 Ok(())
411 }
412 "elevation" => {
413 block.elevation = parameter;
414 Ok(())
415 }
416 _ => Err(format!("Unknown panner parameter: {parameter_name}")),
417 },
418 BlockType::Vca(_) => Err("VCA has no modulated parameters".to_string()),
419
420 BlockType::Envelope(block) => match parameter_name.to_lowercase().as_str() {
422 "attack" => {
423 block.attack = parameter;
424 Ok(())
425 }
426 "decay" => {
427 block.decay = parameter;
428 Ok(())
429 }
430 "sustain" => {
431 block.sustain = parameter;
432 Ok(())
433 }
434 "release" => {
435 block.release = parameter;
436 Ok(())
437 }
438 _ => Err(format!("Unknown envelope parameter: {parameter_name}")),
439 },
440 BlockType::Lfo(block) => match parameter_name.to_lowercase().as_str() {
441 "frequency" => {
442 block.frequency = parameter;
443 Ok(())
444 }
445 "depth" => {
446 block.depth = parameter;
447 Ok(())
448 }
449 _ => Err(format!("Unknown LFO parameter: {parameter_name}")),
450 },
451 }
452 }
453
454 #[inline]
456 pub fn is_modulator(&self) -> bool {
457 matches!(self, BlockType::Envelope(_) | BlockType::Lfo(_))
458 }
459
460 #[inline]
462 pub fn is_output(&self) -> bool {
463 matches!(self, BlockType::Output(_) | BlockType::FileOutput(_))
464 }
465
466 #[inline]
468 pub fn category(&self) -> BlockCategory {
469 match self {
470 BlockType::FileInput(_) | BlockType::FileOutput(_) | BlockType::Output(_) => BlockCategory::IO,
471 BlockType::Oscillator(_) => BlockCategory::Generator,
472 BlockType::AmbisonicDecoder(_)
473 | BlockType::BinauralDecoder(_)
474 | BlockType::ChannelMerger(_)
475 | BlockType::ChannelRouter(_)
476 | BlockType::ChannelSplitter(_)
477 | BlockType::DcBlocker(_)
478 | BlockType::Gain(_)
479 | BlockType::LowPassFilter(_)
480 | BlockType::MatrixMixer(_)
481 | BlockType::Mixer(_)
482 | BlockType::Overdrive(_)
483 | BlockType::Panner(_)
484 | BlockType::Vca(_) => BlockCategory::Effector,
485 BlockType::Envelope(_) | BlockType::Lfo(_) => BlockCategory::Modulator,
486 }
487 }
488
489 #[inline]
491 pub fn name(&self) -> &'static str {
492 match self {
493 BlockType::FileInput(_) => "File Input",
494 BlockType::FileOutput(_) => "File Output",
495 BlockType::Output(_) => "Output",
496 BlockType::Oscillator(_) => "Oscillator",
497 BlockType::AmbisonicDecoder(_) => "Ambisonic Decoder",
498 BlockType::BinauralDecoder(_) => "Binaural Decoder",
499 BlockType::ChannelMerger(_) => "Channel Merger",
500 BlockType::ChannelRouter(_) => "Channel Router",
501 BlockType::ChannelSplitter(_) => "Channel Splitter",
502 BlockType::DcBlocker(_) => "DC Blocker",
503 BlockType::Gain(_) => "Gain",
504 BlockType::LowPassFilter(_) => "Low Pass Filter",
505 BlockType::MatrixMixer(_) => "Matrix Mixer",
506 BlockType::Mixer(_) => "Mixer",
507 BlockType::Overdrive(_) => "Overdrive",
508 BlockType::Panner(_) => "Panner",
509 BlockType::Vca(_) => "VCA",
510 BlockType::Envelope(_) => "Envelope",
511 BlockType::Lfo(_) => "LFO",
512 }
513 }
514
515 pub fn get_modulated_parameters(&self) -> Vec<(&'static str, BlockId)> {
525 let mut result = Vec::new();
526
527 match self {
528 BlockType::FileInput(_) | BlockType::FileOutput(_) | BlockType::Output(_) => {}
529
530 BlockType::Oscillator(block) => {
531 if let Parameter::Modulated(id) = &block.frequency {
532 result.push(("frequency", *id));
533 }
534 if let Parameter::Modulated(id) = &block.pitch_offset {
535 result.push(("pitch_offset", *id));
536 }
537 }
538
539 BlockType::AmbisonicDecoder(_)
540 | BlockType::BinauralDecoder(_)
541 | BlockType::ChannelMerger(_)
542 | BlockType::ChannelRouter(_)
543 | BlockType::ChannelSplitter(_)
544 | BlockType::DcBlocker(_)
545 | BlockType::MatrixMixer(_)
546 | BlockType::Mixer(_)
547 | BlockType::Vca(_) => {}
548
549 BlockType::Gain(block) => {
550 if let Parameter::Modulated(id) = &block.level_db {
551 result.push(("level", *id));
552 }
553 }
554
555 BlockType::LowPassFilter(block) => {
556 if let Parameter::Modulated(id) = &block.cutoff {
557 result.push(("cutoff", *id));
558 }
559 if let Parameter::Modulated(id) = &block.resonance {
560 result.push(("resonance", *id));
561 }
562 }
563
564 BlockType::Overdrive(block) => {
565 if let Parameter::Modulated(id) = &block.drive {
566 result.push(("drive", *id));
567 }
568 if let Parameter::Modulated(id) = &block.level {
569 result.push(("level", *id));
570 }
571 }
572
573 BlockType::Panner(block) => {
574 if let Parameter::Modulated(id) = &block.position {
575 result.push(("position", *id));
576 }
577 if let Parameter::Modulated(id) = &block.azimuth {
578 result.push(("azimuth", *id));
579 }
580 if let Parameter::Modulated(id) = &block.elevation {
581 result.push(("elevation", *id));
582 }
583 }
584
585 BlockType::Envelope(block) => {
586 if let Parameter::Modulated(id) = &block.attack {
587 result.push(("attack", *id));
588 }
589 if let Parameter::Modulated(id) = &block.decay {
590 result.push(("decay", *id));
591 }
592 if let Parameter::Modulated(id) = &block.sustain {
593 result.push(("sustain", *id));
594 }
595 if let Parameter::Modulated(id) = &block.release {
596 result.push(("release", *id));
597 }
598 }
599
600 BlockType::Lfo(block) => {
601 if let Parameter::Modulated(id) = &block.frequency {
602 result.push(("frequency", *id));
603 }
604 if let Parameter::Modulated(id) = &block.depth {
605 result.push(("depth", *id));
606 }
607 }
608 }
609
610 result
611 }
612}
613
614impl<S: Sample> From<FileInputBlock<S>> for BlockType<S> {
618 fn from(block: FileInputBlock<S>) -> Self {
619 BlockType::FileInput(block)
620 }
621}
622
623impl<S: Sample> From<FileOutputBlock<S>> for BlockType<S> {
624 fn from(block: FileOutputBlock<S>) -> Self {
625 BlockType::FileOutput(block)
626 }
627}
628
629impl<S: Sample> From<OutputBlock<S>> for BlockType<S> {
630 fn from(block: OutputBlock<S>) -> Self {
631 BlockType::Output(block)
632 }
633}
634
635impl<S: Sample> From<OscillatorBlock<S>> for BlockType<S> {
637 fn from(block: OscillatorBlock<S>) -> Self {
638 BlockType::Oscillator(block)
639 }
640}
641
642impl<S: Sample> From<AmbisonicDecoderBlock<S>> for BlockType<S> {
644 fn from(block: AmbisonicDecoderBlock<S>) -> Self {
645 BlockType::AmbisonicDecoder(block)
646 }
647}
648
649impl<S: Sample> From<BinauralDecoderBlock<S>> for BlockType<S> {
650 fn from(block: BinauralDecoderBlock<S>) -> Self {
651 BlockType::BinauralDecoder(block)
652 }
653}
654
655impl<S: Sample> From<ChannelMergerBlock<S>> for BlockType<S> {
656 fn from(block: ChannelMergerBlock<S>) -> Self {
657 BlockType::ChannelMerger(block)
658 }
659}
660
661impl<S: Sample> From<ChannelRouterBlock<S>> for BlockType<S> {
662 fn from(block: ChannelRouterBlock<S>) -> Self {
663 BlockType::ChannelRouter(block)
664 }
665}
666
667impl<S: Sample> From<ChannelSplitterBlock<S>> for BlockType<S> {
668 fn from(block: ChannelSplitterBlock<S>) -> Self {
669 BlockType::ChannelSplitter(block)
670 }
671}
672
673impl<S: Sample> From<DcBlockerBlock<S>> for BlockType<S> {
674 fn from(block: DcBlockerBlock<S>) -> Self {
675 BlockType::DcBlocker(block)
676 }
677}
678
679impl<S: Sample> From<GainBlock<S>> for BlockType<S> {
680 fn from(block: GainBlock<S>) -> Self {
681 BlockType::Gain(block)
682 }
683}
684
685impl<S: Sample> From<LowPassFilterBlock<S>> for BlockType<S> {
686 fn from(block: LowPassFilterBlock<S>) -> Self {
687 BlockType::LowPassFilter(block)
688 }
689}
690
691impl<S: Sample> From<MatrixMixerBlock<S>> for BlockType<S> {
692 fn from(block: MatrixMixerBlock<S>) -> Self {
693 BlockType::MatrixMixer(block)
694 }
695}
696
697impl<S: Sample> From<MixerBlock<S>> for BlockType<S> {
698 fn from(block: MixerBlock<S>) -> Self {
699 BlockType::Mixer(block)
700 }
701}
702
703impl<S: Sample> From<OverdriveBlock<S>> for BlockType<S> {
704 fn from(block: OverdriveBlock<S>) -> Self {
705 BlockType::Overdrive(block)
706 }
707}
708
709impl<S: Sample> From<PannerBlock<S>> for BlockType<S> {
710 fn from(block: PannerBlock<S>) -> Self {
711 BlockType::Panner(block)
712 }
713}
714
715impl<S: Sample> From<VcaBlock<S>> for BlockType<S> {
716 fn from(block: VcaBlock<S>) -> Self {
717 BlockType::Vca(block)
718 }
719}
720
721impl<S: Sample> From<EnvelopeBlock<S>> for BlockType<S> {
723 fn from(block: EnvelopeBlock<S>) -> Self {
724 BlockType::Envelope(block)
725 }
726}
727
728impl<S: Sample> From<LfoBlock<S>> for BlockType<S> {
729 fn from(block: LfoBlock<S>) -> Self {
730 BlockType::Lfo(block)
731 }
732}