1use std::collections::VecDeque;
32use std::sync::Arc;
33use std::sync::atomic::{AtomicUsize, Ordering};
34
35use super::queue::{self, Consumer, Producer, PushError};
36use super::voice::Ramp;
37use super::{Action, Bus, BusId, Commands, Fade, Mixer, MixerEvent, MixerHandle};
38use crate::math::{cos_turns, db_to_gain, exp, log2, sin_turns};
39use crate::{Error, ErrorCode, FadeCurve, Result};
40
41mod colour;
42pub use colour::{Bitcrusher, Chorus, Flanger, ModulationRate, Phaser, Saturation};
43
44pub const MAX_EFFECTS: usize = 16;
46
47#[derive(Clone, Copy, Debug, PartialEq)]
50pub enum EffectTime {
51 Seconds(f64),
52 Beats { beats: f64, bpm: f64 },
53}
54impl EffectTime {
55 fn seconds(self) -> Result<f64> {
56 let s = match self {
57 Self::Seconds(s) => s,
58 Self::Beats { beats, bpm } => {
59 if !(1.0..=1000.0).contains(&bpm) || !beats.is_finite() || beats <= 0.0 {
60 return Err(Error::invalid(
61 "Effect beats must be positive, BPM 1..=1000",
62 ));
63 }
64 beats * 60.0 / bpm
65 }
66 };
67 if !s.is_finite() || s <= 0.0 {
68 return Err(Error::invalid("Effect time must be finite and positive"));
69 }
70 Ok(s)
71 }
72}
73
74#[derive(Clone, Copy, Debug, PartialEq)]
77pub struct Compressor {
78 pub threshold_db: f32,
80 pub ratio: f32,
82 pub attack_ms: f32,
84 pub release_ms: f32,
86 pub makeup_db: f32,
88 pub depth: f32,
90 pub sidechain: Option<BusId>,
91}
92impl Default for Compressor {
93 fn default() -> Self {
94 Self {
95 threshold_db: -18.0,
96 ratio: 4.0,
97 attack_ms: 10.0,
98 release_ms: 100.0,
99 makeup_db: 0.0,
100 depth: 1.0,
101 sidechain: None,
102 }
103 }
104}
105impl Compressor {
106 pub fn ducking(key: BusId) -> Self {
108 Self {
109 threshold_db: -30.0,
110 ratio: 20.0,
111 attack_ms: 5.0,
112 release_ms: 250.0,
113 sidechain: Some(key),
114 ..Self::default()
115 }
116 }
117}
118
119#[derive(Clone, Copy, Debug, PartialEq)]
121pub struct Delay {
122 pub time: EffectTime,
123 pub max_seconds: f64,
126 pub feedback: f32,
128 pub mix: f32,
130}
131impl Default for Delay {
132 fn default() -> Self {
133 Self {
134 time: EffectTime::Seconds(0.25),
135 max_seconds: 2.0,
136 feedback: 0.35,
137 mix: 0.25,
138 }
139 }
140}
141
142#[derive(Clone, Copy, Debug, PartialEq)]
144pub struct Reverb {
145 pub decay_seconds: f32,
147 pub damping: f32,
149 pub mix: f32,
151}
152impl Default for Reverb {
153 fn default() -> Self {
154 Self {
155 decay_seconds: 1.5,
156 damping: 0.25,
157 mix: 0.2,
158 }
159 }
160}
161
162#[derive(Clone, Copy, Debug, PartialEq)]
165#[non_exhaustive]
166pub enum Effect {
167 LowPass {
169 cutoff_hz: f32,
170 },
171 HighPass {
173 cutoff_hz: f32,
174 },
175 Compressor(Compressor),
176 Delay(Delay),
177 Reverb(Reverb),
178 Chorus(Chorus),
179 Flanger(Flanger),
180 Phaser(Phaser),
181 Bitcrusher(Bitcrusher),
182 Saturation(Saturation),
183}
184
185#[derive(Clone, Copy)]
186pub(super) struct Settings {
187 kind: u8,
188 values: [f64; 6],
189 key: Option<usize>,
190 capacity: f64,
191}
192impl Effect {
193 fn settings(self, rate: u32, bus: BusId, buses: usize) -> Result<Settings> {
194 let mut s = Settings {
195 kind: 0,
196 values: [0.0; 6],
197 key: None,
198 capacity: 0.0,
199 };
200 match self {
201 Self::LowPass { cutoff_hz } | Self::HighPass { cutoff_hz } => {
202 within(cutoff_hz as f64, 1.0, rate as f64 * 0.45)?;
203 s.kind = u8::from(matches!(self, Self::HighPass { .. }));
204 s.values[0] = cutoff_hz as f64;
205 }
206 Self::Compressor(c) => {
207 s.kind = 2;
208 for (v, lo, hi) in [
209 (c.threshold_db, -96.0, 0.0),
210 (c.ratio, 1.0, 100.0),
211 (c.attack_ms, 0.0, 5000.0),
212 (c.release_ms, 0.0, 5000.0),
213 (c.makeup_db, -24.0, 24.0),
214 (c.depth, 0.0, 1.0),
215 ] {
216 within(v as f64, lo, hi)?;
217 }
218 s.values = [
219 c.threshold_db as f64,
220 c.ratio as f64,
221 c.attack_ms as f64,
222 c.release_ms as f64,
223 c.makeup_db as f64,
224 c.depth as f64,
225 ];
226 if let Some(key) = c.sidechain {
227 if key.0 == 0 || key == bus || key.0 >= buses {
228 return Err(Error::invalid("Sidechain needs another named bus"));
229 }
230 s.key = Some(key.0);
231 }
232 }
233 Self::Delay(d) => {
234 s.kind = 3;
235 within(d.max_seconds, 1.0 / rate as f64, 10.0)?;
236 let time = d.time.seconds()?;
237 within(time, 1.0 / rate as f64, d.max_seconds)?;
238 within(d.feedback as f64, -(0.99f32 as f64), 0.99f32 as f64)?;
239 within(d.mix as f64, 0.0, 1.0)?;
240 s.values = [
241 time * rate as f64,
242 d.feedback as f64,
243 d.mix as f64,
244 0.0,
245 0.0,
246 0.0,
247 ];
248 s.capacity = d.max_seconds * rate as f64;
249 }
250 Self::Reverb(r) => {
251 s.kind = 4;
252 within(r.decay_seconds as f64, 0.05, 20.0)?;
253 within(r.damping as f64, 0.0, 0.99f32 as f64)?;
254 within(r.mix as f64, 0.0, 1.0)?;
255 s.values = [
256 r.decay_seconds as f64,
257 r.damping as f64,
258 r.mix as f64,
259 0.0,
260 0.0,
261 0.0,
262 ];
263 }
264 Self::Chorus(c) => {
265 s.kind = 5;
266 s.values = c.values(rate)?;
267 }
268 Self::Flanger(f) => {
269 s.kind = 6;
270 s.values = f.values(rate)?;
271 }
272 Self::Phaser(p) => {
273 s.kind = 7;
274 s.values = p.values(rate)?;
275 }
276 Self::Bitcrusher(b) => {
277 s.kind = 8;
278 s.values = b.values()?;
279 }
280 Self::Saturation(d) => {
281 s.kind = 9;
282 s.values = d.values()?;
283 }
284 }
285 Ok(s)
286 }
287}
288fn within(value: f64, lo: f64, hi: f64) -> Result<()> {
289 if !(lo..=hi).contains(&value) {
290 Err(Error::invalid(
291 "Effect parameter is non-finite or outside its documented range",
292 ))
293 } else {
294 Ok(())
295 }
296}
297
298pub(super) struct Chain {
299 nodes: Vec<Node>,
300}
301struct Node {
302 settings: Settings,
303 ramps: [Ramp; 6],
304 state: State,
305}
306enum State {
307 Colour(colour::Processor),
308 Filter {
309 memory: [f64; 8],
310 cutoff: f64,
311 coefficient: f64,
312 },
313 Compressor {
314 gain: f64,
315 threshold: Cache,
316 makeup: Cache,
317 attack: Cache,
318 release: Cache,
319 },
320 Delay {
321 ring: Vec<f64>,
322 at: usize,
323 },
324 Reverb {
325 channels: Vec<ReverbChannel>,
326 },
327}
328struct Line {
329 ring: Vec<f64>,
330 at: usize,
331 memory: f64,
332}
333impl Line {
334 fn new(len: usize) -> Self {
335 Self {
336 ring: vec![0.0; len.max(1)],
337 at: 0,
338 memory: 0.0,
339 }
340 }
341 fn get(&self) -> f64 {
342 self.ring[self.at]
343 }
344 fn put(&mut self, value: f64) {
345 self.ring[self.at] = value;
346 self.at = (self.at + 1) % self.ring.len();
347 }
348}
349struct ReverbChannel {
350 combs: [Line; 4],
351 diffusers: [Line; 2],
352 decay: f64,
353 feedback: [f64; 4],
354}
355struct Cache {
356 input: f64,
357 output: f64,
358}
359impl Cache {
360 fn new() -> Self {
361 Self {
362 input: f64::NAN,
363 output: 0.0,
364 }
365 }
366 fn get(&mut self, input: f64, compute: impl FnOnce(f64) -> f64) -> f64 {
367 if self.input != input {
368 self.input = input;
369 self.output = compute(input);
370 }
371 self.output
372 }
373}
374
375impl Chain {
376 fn new(effects: &[Effect], rate: u32, ch: usize, bus: BusId, buses: usize) -> Result<Self> {
377 if effects.len() > MAX_EFFECTS {
378 return Err(Error::limit("Too many effects on a bus"));
379 }
380 let settings: Vec<_> = effects
382 .iter()
383 .map(|e| e.settings(rate, bus, buses))
384 .collect::<Result<_>>()?;
385 let nodes = settings
386 .into_iter()
387 .map(|s| {
388 let state = match s.kind {
389 0 | 1 => State::Filter {
390 memory: [0.0; 8],
391 cutoff: 0.0,
392 coefficient: 0.0,
393 },
394 2 => State::Compressor {
395 gain: 1.0,
396 threshold: Cache::new(),
397 makeup: Cache::new(),
398 attack: Cache::new(),
399 release: Cache::new(),
400 },
401 3 => State::Delay {
402 ring: vec![0.0; (s.capacity.ceil() as usize + 2) * ch],
403 at: 0,
404 },
405 4 => State::Reverb {
406 channels: (0..ch)
407 .map(|c| {
408 let line = |seconds: f64| {
409 Line::new(((seconds + c as f64 * 0.0011) * rate as f64).round()
410 as usize)
411 };
412 ReverbChannel {
413 combs: [line(0.0297), line(0.0371), line(0.0411), line(0.0437)],
414 diffusers: [line(0.005), line(0.0017)],
415 decay: 0.0,
416 feedback: [0.0; 4],
417 }
418 })
419 .collect(),
420 },
421 _ => State::Colour(colour::Processor::new(s.kind, rate, ch)),
422 };
423 Node {
424 settings: s,
425 ramps: s.values.map(Ramp::constant),
426 state,
427 }
428 })
429 .collect();
430 Ok(Self { nodes })
431 }
432 fn accepts(&self, slot: usize, settings: Settings) -> bool {
433 self.nodes.get(slot).is_some_and(|n| {
434 n.settings.kind == settings.kind
435 && (settings.kind != 3 || settings.capacity <= n.settings.capacity)
436 })
437 }
438 fn update(&mut self, slot: usize, settings: Settings, clock: u64, len: u64, curve: FadeCurve) {
439 let n = &mut self.nodes[slot];
440 n.settings.key = settings.key;
442 for (r, value) in n.ramps.iter_mut().zip(settings.values) {
443 r.retarget(clock, value, len, curve);
444 }
445 }
446}
447
448impl Node {
449 fn process(&mut self, clock: u64, rate: u32, ch: usize, out: &mut [f32], key: Option<&[f32]>) {
450 let kind = self.settings.kind;
451 for (i, frame) in out.chunks_exact_mut(ch).enumerate() {
452 let p = self.ramps.map(|r| r.value(clock + i as u64));
453 let mut x = [0.0; 8];
454 for c in 0..ch {
455 x[c] = finite(frame[c] as f64);
456 }
457 match &mut self.state {
458 State::Colour(processor) => processor.process(&mut x, p, rate, ch),
459 State::Filter {
460 memory,
461 cutoff,
462 coefficient,
463 } => {
464 if *cutoff != p[0] {
465 let turns = p[0] / (2.0 * rate as f64);
466 let g = sin_turns(turns) / cos_turns(turns);
467 *coefficient = g / (1.0 + g);
468 *cutoff = p[0];
469 }
470 for c in 0..ch {
471 let v = (x[c] - memory[c]) * *coefficient;
472 let low = v + memory[c];
473 memory[c] = low + v;
474 x[c] = if kind == 0 { low } else { x[c] - low };
475 }
476 }
477 State::Compressor {
478 gain,
479 threshold,
480 makeup,
481 attack,
482 release,
483 } => {
484 let peak = if let Some(key) = key {
485 key[i * ch..i * ch + ch]
486 .iter()
487 .map(|&v| finite(v as f64).abs())
488 .fold(0.0, f64::max)
489 } else {
490 x[..ch].iter().map(|v| v.abs()).fold(0.0, f64::max)
491 };
492 let threshold = threshold.get(p[0], db_to_gain);
493 let reduction = if peak > threshold {
494 crate::math::exp2(log2(threshold / peak) * (1.0 - 1.0 / p[1]))
495 } else {
496 1.0
497 };
498 let target = 1.0 - p[5] * (1.0 - reduction);
499 let coefficient = |ms| {
500 if ms == 0.0 {
501 0.0
502 } else {
503 exp(-1000.0 / (ms * rate as f64))
504 }
505 };
506 let a = if target < *gain {
507 attack.get(p[2], coefficient)
508 } else {
509 release.get(p[3], coefficient)
510 };
511 *gain = target + (*gain - target) * a;
512 let g = *gain * makeup.get(p[4], db_to_gain);
513 for s in &mut x[..ch] {
514 *s *= g;
515 }
516 }
517 State::Delay { ring, at } => {
518 let frames = ring.len() / ch;
519 let mut pos = *at as f64 - p[0];
520 if pos < 0.0 {
521 pos += frames as f64;
522 }
523 let a = pos.floor() as usize;
524 let b = (a + 1) % frames;
525 let f = pos - a as f64;
526 for c in 0..ch {
527 let delayed = ring[a * ch + c] * (1.0 - f) + ring[b * ch + c] * f;
528 ring[*at * ch + c] = finite(x[c] + delayed * p[1]);
529 x[c] = x[c] * (1.0 - p[2]) + delayed * p[2];
530 }
531 *at = (*at + 1) % frames;
532 }
533 State::Reverb { channels } => {
534 for c in 0..ch {
535 let channel = &mut channels[c];
536 if channel.decay != p[0] {
537 channel.decay = p[0];
538 for (feedback, line) in channel.feedback.iter_mut().zip(&channel.combs)
539 {
540 *feedback = db_to_gain(
541 -60.0 * line.ring.len() as f64 / (rate as f64 * p[0]),
542 );
543 }
544 }
545 let mut wet = 0.0;
546 for (line, &feedback) in channel.combs.iter_mut().zip(&channel.feedback) {
547 let d = line.get();
548 line.memory = d * (1.0 - p[1]) + line.memory * p[1];
549 line.put(finite(x[c] + line.memory * feedback));
550 wet += d * 0.25;
551 }
552 for line in &mut channel.diffusers {
553 let value = line.get() - wet * 0.5;
554 line.put(wet + value * 0.5);
555 wet = value;
556 }
557 x[c] = x[c] * (1.0 - p[2]) + wet * p[2];
558 }
559 }
560 }
561 for c in 0..ch {
562 frame[c] = finite(x[c]) as f32;
563 }
564 }
565 }
566}
567fn finite(x: f64) -> f64 {
568 if x.is_nan() {
569 0.0
570 } else {
571 x.clamp(-(f32::MAX as f64), f32::MAX as f64)
572 }
573}
574
575pub(super) struct Edit {
580 bus: usize,
581 chain: Option<Box<Chain>>,
582 event: Option<MixerEvent>,
583 credits: Arc<AtomicUsize>,
584}
585impl Drop for Edit {
586 fn drop(&mut self) {
587 self.credits.fetch_sub(1, Ordering::Release);
588 }
589}
590pub(super) struct AudioEffects {
591 returns: Producer<Box<Edit>>,
592 retired: VecDeque<Box<Edit>>,
593 pub(super) order: [usize; 256],
594}
595pub(super) struct ControlEffects {
596 returns: Consumer<Box<Edit>>,
597 credits: Arc<AtomicUsize>,
598 capacity: usize,
599}
600pub(super) fn create(capacity: usize, buses: usize) -> (AudioEffects, ControlEffects) {
601 let (tx, rx) = queue::queue(capacity);
602 let mut order = [0; 256];
603 for (i, b) in order[..buses - 1].iter_mut().enumerate() {
604 *b = i + 1;
605 }
606 (
607 AudioEffects {
608 returns: tx,
609 retired: VecDeque::with_capacity(capacity),
610 order,
611 },
612 ControlEffects {
613 returns: rx,
614 credits: Arc::new(AtomicUsize::new(0)),
615 capacity,
616 },
617 )
618}
619impl AudioEffects {
620 pub(super) fn send_returns(&mut self) {
621 while let Some(edit) = self.retired.pop_front() {
622 match self.returns.push(edit) {
623 Ok(()) => (),
624 Err(PushError::Full(edit) | PushError::Disconnected(edit)) => {
625 self.retired.push_front(edit);
626 break;
627 }
628 }
629 }
630 }
631}
632impl ControlEffects {
633 pub(super) fn poll(&mut self) -> Option<MixerEvent> {
634 let edit = self.returns.pop()?;
635 edit.event
636 }
638}
639
640impl MixerHandle {
641 pub fn set_effects(&mut self, bus: BusId, effects: &[Effect]) -> Result<()> {
644 self.now().set_effects(bus, effects)
645 }
646 pub fn set_effect(
650 &mut self,
651 bus: BusId,
652 slot: usize,
653 effect: Effect,
654 fade: Fade,
655 ) -> Result<()> {
656 self.now().set_effect(bus, slot, effect, fade)
657 }
658}
659impl Commands<'_> {
660 pub fn set_effects(self, bus: BusId, effects: &[Effect]) -> Result<()> {
661 if bus.0 > self.handle.buses.len() {
662 return Err(Error::invalid("Unknown bus"));
663 }
664 let fx = &self.handle.effects;
665 if fx.credits.load(Ordering::Acquire) >= fx.capacity {
666 return Err(Error::limit(
667 "Poll mixer events before sending more effect chain edits",
668 ));
669 }
670 let chain = Chain::new(
671 effects,
672 self.handle.rate,
673 self.handle.channels,
674 bus,
675 self.handle.buses.len() + 1,
676 )?;
677 let chain = if effects.is_empty() {
678 None
679 } else {
680 Some(Box::new(chain))
681 };
682 fx.credits.fetch_add(1, Ordering::Relaxed);
683 let edit = Box::new(Edit {
684 bus: bus.0,
685 chain,
686 event: None,
687 credits: fx.credits.clone(),
688 });
689 self.handle.send(self.frame, Action::Effects(edit))
690 }
691 pub fn set_effect(self, bus: BusId, slot: usize, effect: Effect, fade: Fade) -> Result<()> {
692 if bus.0 > self.handle.buses.len() || slot >= MAX_EFFECTS {
693 return Err(Error::invalid("Unknown bus or effect slot"));
694 }
695 let settings = effect.settings(self.handle.rate, bus, self.handle.buses.len() + 1)?;
696 let (len, curve) = self.handle.frames(fade)?;
697 self.handle.send(
698 self.frame,
699 Action::Effect(bus.0, slot, settings, len, curve),
700 )
701 }
702}
703
704pub(super) enum Change<'a> {
705 Current,
706 Chain(usize, Option<&'a Chain>),
707 Parameter(usize, usize, Settings),
708}
709pub(super) fn topology(
713 buses: &[Bus],
714 change: Change<'_>,
715 graph: Option<&super::routing::Graph>,
716) -> Option<[usize; 256]> {
717 let mut done = [false; 256];
718 let mut order = [0; 256];
719 for entry in &mut order[..buses.len() - 1] {
720 let ready = (1..buses.len()).find(|&b| {
721 if done[b] {
722 return false;
723 }
724 if graph.is_some_and(|g| g.incoming[b].iter().any(|&source| !done[source])) {
725 return false;
726 }
727 let chain = match change {
728 Change::Chain(target, chain) if target == b => chain,
729 _ => buses[b].effects.as_deref(),
730 };
731 chain.is_none_or(|chain| {
732 chain.nodes.iter().enumerate().all(|(slot, node)| {
733 let key = match change {
734 Change::Parameter(target, index, settings)
735 if target == b && index == slot =>
736 {
737 settings.key
738 }
739 _ => node.settings.key,
740 };
741 key.is_none_or(|key| done[key])
742 })
743 })
744 })?;
745 *entry = ready;
746 done[ready] = true;
747 }
748 Some(order)
749}
750
751impl Mixer {
752 pub(super) fn mix_routing(&mut self, first: u64, out: &mut [f32]) {
755 use super::routing::SendPosition;
756 let graph = self.routing.graph.as_mut().unwrap();
757 let ch = self.channels;
758 let frames = out.len() / ch;
759 let master_paused = self.buses[0].paused;
760 for (b, bus) in self.buses.iter_mut().enumerate() {
763 if !graph.input[b] {
764 bus.buffer[..out.len()].fill(0.0);
765 }
766 }
767 for index in 0..self.buses.len() {
768 let b = self.effects.order[index];
769 let node = &graph.nodes[b];
770 let pre = node
771 .edges
772 .iter()
773 .any(|e| e.enabled && e.position == SendPosition::PreFader);
774 let (before, rest) = self.buses.split_at_mut(b);
775 let (bus, after) = rest.split_first_mut().unwrap();
776 let buffer = &mut bus.buffer[..out.len()];
777 if master_paused || bus.paused {
778 buffer.fill(0.0);
779 if pre {
780 graph.pre[..out.len()].fill(0.0);
781 }
782 } else {
783 if let Some(chain) = &mut bus.effects {
784 for effect in &mut chain.nodes {
785 let key = effect.settings.key.map(|key| {
786 if key < b {
787 &before[key].buffer[..out.len()]
788 } else {
789 &after[key - b - 1].buffer[..out.len()]
790 }
791 });
792 effect.process(bus.effect_clock, self.rate, ch, buffer, key);
793 }
794 }
795 bus.effect_clock += frames as u64;
796 for (i, frame) in buffer.chunks_exact_mut(ch).enumerate() {
797 let at = first + i as u64;
798 let pause = bus.pause.value(at);
799 let gain = bus.gain.value(at) * pause;
800 for (c, sample) in frame.iter_mut().enumerate() {
801 if pre {
802 graph.pre[i * ch + c] = (*sample as f64 * pause) as f32;
803 }
804 let pan = if node.pan == 0.0 {
805 1.0
806 } else if c == 0 {
807 1.0 - node.pan.max(0.0)
808 } else {
809 1.0 + node.pan.min(0.0)
810 };
811 *sample = (*sample as f64 * (gain * pan)) as f32;
812 }
813 }
814 if node.muted || !node.audible {
815 buffer.fill(0.0);
816 if pre {
817 graph.pre[..out.len()].fill(0.0);
818 }
819 }
820 }
821 for edge in node.edges.iter().filter(|e| e.enabled) {
822 let source = if edge.position == SendPosition::PreFader {
823 &graph.pre[..out.len()]
824 } else {
825 &buffer[..]
826 };
827 let to = edge.destination;
828 let destination = if to < b {
829 &mut before[to].buffer[..out.len()]
830 } else {
831 &mut after[to - b - 1].buffer[..out.len()]
832 };
833 for (dest, &sample) in destination.iter_mut().zip(source) {
834 *dest += (sample as f64 * edge.gain) as f32;
835 }
836 }
837 if b == 0 {
838 out.copy_from_slice(buffer);
839 }
840 }
841 }
842 pub(super) fn apply_effects(&mut self, frame: u64, mut edit: Box<Edit>) {
843 let bus = edit.bus;
844 if let Some(order) = topology(
845 &self.buses,
846 Change::Chain(bus, edit.chain.as_deref()),
847 self.routing.graph.as_deref(),
848 ) {
849 self.effects.order = order;
850 std::mem::swap(&mut self.buses[bus].effects, &mut edit.chain);
851 edit.event = Some(MixerEvent::EffectsApplied(BusId(bus), frame));
852 } else {
853 edit.event = Some(MixerEvent::EffectsRejected(
854 BusId(bus),
855 ErrorCode::InvalidArgument,
856 ));
857 }
858 self.effects.retired.push_back(edit);
859 }
860 pub(super) fn apply_effect(
861 &mut self,
862 bus: usize,
863 slot: usize,
864 settings: Settings,
865 len: u64,
866 curve: FadeCurve,
867 ) {
868 let valid = self.buses[bus]
869 .effects
870 .as_ref()
871 .is_some_and(|c| c.accepts(slot, settings));
872 let order = valid
873 .then(|| {
874 topology(
875 &self.buses,
876 Change::Parameter(bus, slot, settings),
877 self.routing.graph.as_deref(),
878 )
879 })
880 .flatten();
881 if let Some(order) = order {
882 self.effects.order = order;
883 let bus = &mut self.buses[bus];
884 bus.effects
885 .as_mut()
886 .unwrap()
887 .update(slot, settings, bus.effect_clock, len, curve);
888 } else {
889 self.event(MixerEvent::EffectsRejected(
890 BusId(bus),
891 ErrorCode::InvalidArgument,
892 ));
893 }
894 }
895
896 pub(super) fn mix_effects(&mut self, first: u64, out: &mut [f32]) {
898 let ch = self.channels;
899 let frames = out.len() / ch;
900 let master_paused = self.buses[0].paused;
901 for index in 0..self.buses.len() {
902 let b = self.effects.order[index];
903 if b == 0 {
904 for bus in &self.buses[1..] {
905 for (o, &s) in out.iter_mut().zip(&bus.buffer) {
906 *o += s;
907 }
908 }
909 for (o, &s) in out.iter_mut().zip(&self.buses[0].buffer) {
910 *o += s;
911 }
912 self.buses[0].buffer[..out.len()].copy_from_slice(out);
913 }
914 let (before, rest) = self.buses.split_at_mut(b);
917 let (bus, after) = rest.split_first_mut().unwrap();
918 let buffer = &mut bus.buffer[..out.len()];
919 if master_paused || bus.paused {
920 buffer.fill(0.0);
921 } else {
922 if let Some(chain) = &mut bus.effects {
923 for node in &mut chain.nodes {
925 let key = node.settings.key.map(|key| {
926 if key < b {
927 &before[key].buffer[..out.len()]
928 } else {
929 &after[key - b - 1].buffer[..out.len()]
930 }
931 });
932 node.process(bus.effect_clock, self.rate, ch, buffer, key);
933 }
934 }
935 bus.effect_clock += frames as u64;
936 for (i, frame) in buffer.chunks_exact_mut(ch).enumerate() {
937 let at = first + i as u64;
938 let gain = bus.gain.value(at) * bus.pause.value(at);
939 for sample in frame {
940 *sample = (*sample as f64 * gain) as f32;
941 }
942 }
943 }
944 if b == 0 {
945 out.copy_from_slice(buffer);
946 }
947 }
948 }
949}