1#![allow(clippy::needless_range_loop)]
2
3use crate::{ChannelLayout, ProcessCtx, Processor, StateBlob, StateError};
4
5#[derive(Copy, Clone, Debug, Eq, PartialEq)]
7#[non_exhaustive]
8pub enum ChainError {
9 MultipleInputs,
13}
14
15impl core::fmt::Display for ChainError {
16 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
17 formatter.write_str(match self {
18 Self::MultipleInputs => {
19 "a processor chain takes only processors that read one input per output"
20 }
21 })
22 }
23}
24
25impl std::error::Error for ChainError {}
26
27#[derive(Copy, Clone, Debug, Eq, PartialEq)]
30#[non_exhaustive]
31pub struct ChainStateError {
32 pub node: Option<usize>,
35 pub error: StateError,
37}
38
39impl ChainStateError {
40 const fn chain(error: StateError) -> Self {
41 Self { node: None, error }
42 }
43}
44
45impl core::fmt::Display for ChainStateError {
46 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
47 match self.node {
48 Some(node) => write!(formatter, "node {node}: {}", self.error),
49 None => write!(formatter, "the chain: {}", self.error),
50 }
51 }
52}
53
54impl std::error::Error for ChainStateError {
55 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
56 Some(&self.error)
57 }
58}
59
60#[derive(Copy, Clone, Debug, Eq, PartialEq)]
63#[non_exhaustive]
64pub enum GraphStateError {
65 Topology,
67 ClipChain {
69 bus: usize,
71 error: ChainStateError,
73 },
74 TrackBus {
76 bus: usize,
78 error: ChainStateError,
80 },
81 Master(ChainStateError),
83 Alignment {
86 bus: usize,
88 error: StateError,
90 },
91}
92
93impl core::fmt::Display for GraphStateError {
94 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
95 match self {
96 Self::Topology => {
97 formatter.write_str("the saved state was made by a graph with other buses")
98 }
99 Self::ClipChain { bus, error } => write!(formatter, "clip chain {bus}, {error}"),
100 Self::TrackBus { bus, error } => write!(formatter, "track bus {bus}, {error}"),
101 Self::Master(error) => write!(formatter, "master, {error}"),
102 Self::Alignment { bus, error } => write!(formatter, "bus {bus} alignment: {error}"),
103 }
104 }
105}
106
107impl std::error::Error for GraphStateError {}
108
109#[derive(Copy, Clone, Debug, Eq, PartialEq)]
111enum Prepared {
112 No,
115 Nodes,
118 Full,
120}
121
122pub struct ProcessorChain {
131 processors: Vec<Box<dyn Processor>>,
132 layout: ChannelLayout,
133 scratch_a: [Vec<f32>; 2],
134 scratch_b: [Vec<f32>; 2],
135 bypass: bool,
136 prepared: Prepared,
137 max_block: usize,
138 bypassable: bool,
141 dry: Delay,
144}
145
146impl ProcessorChain {
147 #[must_use]
149 pub fn new(layout: ChannelLayout) -> Self {
150 Self {
151 processors: Vec::new(),
152 layout,
153 scratch_a: [Vec::new(), Vec::new()],
154 scratch_b: [Vec::new(), Vec::new()],
155 bypass: false,
156 prepared: Prepared::No,
157 max_block: 0,
158 bypassable: false,
159 dry: Delay::default(),
160 }
161 }
162 pub fn push(&mut self, processor: impl Processor + 'static) -> Result<(), ChainError> {
169 if processor.inputs_per_output() != 1 {
170 return Err(ChainError::MultipleInputs);
171 }
172 self.processors.push(Box::new(processor));
173 self.prepared = Prepared::No;
174 Ok(())
175 }
176 pub fn set_bypass(&mut self, bypass: bool) {
189 self.bypass = bypass;
190 if !self.bypassable {
191 self.bypassable = true;
192 if self.prepared != Prepared::No {
193 self.dry
194 .resize(self.delay_samples(), self.layout.channels());
195 }
196 }
197 if bypass && self.prepared == Prepared::Nodes {
199 self.allocate_scratch(false);
200 }
201 }
202 #[must_use]
207 pub fn passes_through(&self) -> bool {
208 self.processors.is_empty() || self.prepared == Prepared::No
209 }
210 #[must_use]
213 pub fn is_prepared(&self) -> bool {
214 self.prepared != Prepared::No
215 }
216 pub fn prepare(&mut self, sample_rate: u32, max_block: usize) {
218 for processor in &mut self.processors {
219 processor.prepare(sample_rate, max_block);
220 }
221 self.max_block = max_block.max(1);
223 self.prepared = Prepared::Full;
224 if self.processors.is_empty() {
225 self.scratch_a.iter_mut().for_each(Vec::clear);
226 self.scratch_b.iter_mut().for_each(Vec::clear);
227 self.dry.resize(0, 0);
228 return;
229 }
230 self.allocate_scratch(true);
231 self.dry
232 .resize(self.delay_samples(), self.layout.channels());
233 }
234 pub fn prepare_nodes(&mut self, sample_rate: u32, max_block: usize) {
240 for processor in &mut self.processors {
241 processor.prepare(sample_rate, max_block);
242 }
243 self.max_block = max_block.max(1);
244 for channel in self.scratch_a.iter_mut().chain(&mut self.scratch_b) {
245 *channel = Vec::new();
246 }
247 self.prepared = Prepared::Nodes;
248 if self.bypass {
249 self.allocate_scratch(false);
250 }
251 self.dry
252 .resize(self.delay_samples(), self.layout.channels());
253 }
254 fn allocate_scratch(&mut self, both: bool) {
257 for channel in 0..self.layout.channels() {
258 self.scratch_a[channel].resize(self.max_block, 0.0);
259 if both {
260 self.scratch_b[channel].resize(self.max_block, 0.0);
261 }
262 }
263 }
264 fn delay_samples(&self) -> usize {
266 if self.bypassable {
267 usize::try_from(self.latency_samples()).unwrap_or(usize::MAX)
268 } else {
269 0
270 }
271 }
272 pub fn process_in_place(
278 &mut self,
279 ctx: &ProcessCtx,
280 buffer: &mut [Vec<f32>; 2],
281 spare: &mut [Vec<f32>; 2],
282 frames: usize,
283 ) {
284 let channels = self.layout.channels();
285 if self.processors.is_empty() || self.prepared == Prepared::No {
286 return;
287 }
288 let frames = buffer
289 .iter()
290 .take(channels)
291 .chain(spare.iter().take(channels))
292 .map(Vec::len)
293 .fold(frames, usize::min);
294 if !self.bypass {
295 for channel in 0..channels {
296 self.dry.remember(channel, &buffer[channel][..frames]);
297 }
298 self.dry.advance(frames);
299 let mut upstream = 0_u32;
300 for processor in &mut self.processors {
301 let node_ctx = ctx.offset_by(-i64::from(upstream));
302 process_processor(
303 processor.as_mut(),
304 &node_ctx,
305 channels,
306 (buffer, 0..frames),
307 (spare, 0..frames),
308 );
309 core::mem::swap(buffer, spare);
310 upstream = upstream.saturating_add(processor.latency_samples());
311 }
312 return;
313 }
314 let piece = self.scratch_a[0].len().max(1);
318 let mut start = 0;
319 while start < frames {
320 let end = (start + piece).min(frames);
321 let count = end - start;
322 let piece_ctx = ctx.offset_by(i64::try_from(start).unwrap_or(i64::MAX));
323 let mut upstream = 0_u32;
324 for (index, processor) in self.processors.iter_mut().enumerate() {
325 let node_ctx = piece_ctx.offset_by(-i64::from(upstream));
326 if index == 0 {
327 process_processor(
328 processor.as_mut(),
329 &node_ctx,
330 channels,
331 (buffer, start..end),
332 (spare, start..end),
333 );
334 } else if index % 2 == 1 {
335 process_processor(
336 processor.as_mut(),
337 &node_ctx,
338 channels,
339 (spare, start..end),
340 (&mut self.scratch_a, 0..count),
341 );
342 } else {
343 process_processor(
344 processor.as_mut(),
345 &node_ctx,
346 channels,
347 (&self.scratch_a, 0..count),
348 (spare, start..end),
349 );
350 }
351 upstream = upstream.saturating_add(processor.latency_samples());
352 }
353 for channel in 0..channels {
354 self.dry
355 .delay_in_place(channel, &mut buffer[channel][start..end]);
356 }
357 self.dry.advance(count);
358 start = end;
359 }
360 }
361 #[must_use]
364 pub fn latency_samples(&self) -> u32 {
365 if self.prepared == Prepared::No {
366 return 0;
367 }
368 self.processors.iter().fold(0_u32, |total, processor| {
369 total.saturating_add(processor.latency_samples())
370 })
371 }
372 #[must_use]
374 pub fn history_samples(&self) -> u32 {
375 self.processors.iter().fold(0_u32, |total, processor| {
376 total.saturating_add(processor.history_samples())
377 })
378 }
379 pub fn reset(&mut self) {
381 for processor in &mut self.processors {
382 processor.reset();
383 }
384 for channel in &mut self.scratch_a {
385 channel.fill(0.0);
386 }
387 for channel in &mut self.scratch_b {
388 channel.fill(0.0);
389 }
390 self.dry.reset();
391 }
392 pub fn process(&mut self, ctx: &ProcessCtx, inputs: &[&[f32]], outputs: &mut [&mut [f32]]) {
399 let channels = self.layout.channels();
400 if inputs.len() < channels || outputs.len() < channels {
401 for output in outputs.iter_mut() {
402 output.fill(0.0);
403 }
404 return;
405 }
406 let frames = inputs
407 .iter()
408 .take(channels)
409 .map(|v| v.len())
410 .chain(outputs.iter().take(channels).map(|v| v.len()))
411 .min()
412 .unwrap_or(0);
413 if self.processors.is_empty() || self.prepared != Prepared::Full {
414 for channel in 0..channels {
415 outputs[channel][..frames].copy_from_slice(&inputs[channel][..frames]);
416 }
417 return;
418 }
419 let piece = self.scratch_a[0].len();
420 let mut start = 0;
421 while start < frames {
422 let end = (start + piece).min(frames);
423 let count = end - start;
424 for channel in 0..channels {
425 self.scratch_a[channel][..count].copy_from_slice(&inputs[channel][start..end]);
426 }
427 let piece_ctx = ctx.offset_by(i64::try_from(start).unwrap_or(i64::MAX));
428 let mut upstream = 0_u32;
429 for processor in &mut self.processors {
430 let node_ctx = piece_ctx.offset_by(-i64::from(upstream));
431 process_processor(
432 processor.as_mut(),
433 &node_ctx,
434 channels,
435 (&self.scratch_a, 0..count),
436 (&mut self.scratch_b, 0..count),
437 );
438 core::mem::swap(&mut self.scratch_a, &mut self.scratch_b);
439 upstream = upstream.saturating_add(processor.latency_samples());
440 }
441 for channel in 0..channels {
442 if self.bypass {
443 self.dry.delay(
444 channel,
445 &inputs[channel][start..end],
446 &mut outputs[channel][start..end],
447 );
448 } else {
449 self.dry.remember(channel, &inputs[channel][start..end]);
450 outputs[channel][start..end].copy_from_slice(&self.scratch_a[channel][..count]);
451 }
452 }
453 self.dry.advance(count);
454 start = end;
455 }
456 }
457 #[must_use]
460 pub fn save_state(&self) -> StateBlob {
461 let mut bytes = Vec::new();
462 bytes.extend_from_slice(
463 &(u32::try_from(self.processors.len()).unwrap_or(u32::MAX)).to_le_bytes(),
464 );
465 for state in self
466 .processors
467 .iter()
468 .map(|processor| processor.save_state())
469 .chain(core::iter::once(self.dry.save_state()))
470 {
471 bytes.extend_from_slice(
472 &(u64::try_from(state.as_bytes().len()).unwrap_or(u64::MAX)).to_le_bytes(),
473 );
474 bytes.extend_from_slice(state.as_bytes());
475 }
476 StateBlob::new(bytes)
477 }
478 pub fn load_state(&mut self, state: &StateBlob) -> Result<(), ChainStateError> {
491 let (nodes, record) = Self::split_state(state.as_bytes(), self.processors.len())
492 .ok_or(ChainStateError::chain(StateError::Mismatch))?;
493 let record = self
494 .dry
495 .check_record(&record)
496 .map_err(ChainStateError::chain)?;
497 let snapshot = self
498 .processors
499 .iter()
500 .map(|processor| processor.save_state())
501 .collect::<Vec<_>>();
502 for (index, part) in nodes.iter().enumerate() {
503 if let Err(error) = self.processors[index].load_state(part) {
504 undo(&mut self.processors[..index], &snapshot);
505 return Err(ChainStateError {
506 node: Some(index),
507 error,
508 });
509 }
510 }
511 self.dry.load_record(record);
512 Ok(())
513 }
514 #[must_use]
521 pub fn node_state(&self, index: usize) -> Option<StateBlob> {
522 self.processors
523 .get(index)
524 .map(|processor| processor.save_state())
525 }
526 pub fn load_node_state(&mut self, index: usize, state: &StateBlob) -> Result<(), StateError> {
534 self.processors
535 .get_mut(index)
536 .ok_or(StateError::Mismatch)?
537 .load_state(state)
538 }
539 fn split_state(bytes: &[u8], count: usize) -> Option<(Vec<StateBlob>, StateBlob)> {
542 let saved = u32::from_le_bytes(bytes.get(0..4)?.try_into().ok()?);
543 if usize::try_from(saved).ok()? != count {
544 return None;
545 }
546 let mut offset = 4;
547 let mut parts = Vec::with_capacity(count + 1);
548 for _ in 0..=count {
549 let length = usize::try_from(u64::from_le_bytes(
550 bytes.get(offset..offset + 8)?.try_into().ok()?,
551 ))
552 .ok()?;
553 let end = (offset + 8).checked_add(length)?;
554 parts.push(StateBlob::new(bytes.get(offset + 8..end)?.to_vec()));
555 offset = end;
556 }
557 let record = parts.pop()?;
558 (offset == bytes.len()).then_some((parts, record))
559 }
560}
561
562fn undo(processors: &mut [Box<dyn Processor>], snapshot: &[StateBlob]) {
566 for (processor, state) in processors.iter_mut().zip(snapshot) {
567 if processor.load_state(state).is_err() {
568 processor.reset();
569 }
570 }
571}
572
573fn process_processor(
576 processor: &mut dyn Processor,
577 ctx: &ProcessCtx,
578 channels: usize,
579 (input, from): (&[Vec<f32>; 2], core::ops::Range<usize>),
580 (output, to): (&mut [Vec<f32>; 2], core::ops::Range<usize>),
581) {
582 match channels {
583 1 => processor.process(ctx, &[&input[0][from]], &mut [&mut output[0][to]]),
584 2 => {
585 let (left, right) = output.split_at_mut(1);
586 processor.process(
587 ctx,
588 &[&input[0][from.clone()], &input[1][from]],
589 &mut [&mut left[0][to.clone()], &mut right[0][to]],
590 );
591 }
592 _ => {}
593 }
594}
595
596#[derive(Clone, Debug, Default)]
600struct Delay {
601 lines: [Vec<f32>; 2],
602 cursor: usize,
603}
604
605impl Delay {
606 fn resize(&mut self, samples: usize, channels: usize) {
608 for (channel, line) in self.lines.iter_mut().enumerate() {
609 line.clear();
610 if channel < channels {
611 line.resize(samples, 0.0);
612 } else {
613 line.shrink_to_fit();
614 }
615 }
616 self.cursor = 0;
617 }
618 fn reset(&mut self) {
619 for line in &mut self.lines {
620 line.fill(0.0);
621 }
622 self.cursor = 0;
623 }
624 fn delay(&mut self, channel: usize, input: &[f32], output: &mut [f32]) {
626 let line = &mut self.lines[channel];
627 if line.is_empty() {
628 output.copy_from_slice(input);
629 return;
630 }
631 let mut cursor = self.cursor;
632 for (input, output) in input.iter().zip(output.iter_mut()) {
633 *output = line[cursor];
634 line[cursor] = *input;
635 cursor += 1;
636 if cursor == line.len() {
637 cursor = 0;
638 }
639 }
640 }
641 fn delay_in_place(&mut self, channel: usize, samples: &mut [f32]) {
643 let line = &mut self.lines[channel];
644 if line.is_empty() {
645 return;
646 }
647 let mut cursor = self.cursor;
648 for sample in samples {
649 core::mem::swap(&mut line[cursor], sample);
650 cursor += 1;
651 if cursor == line.len() {
652 cursor = 0;
653 }
654 }
655 }
656 fn remember(&mut self, channel: usize, input: &[f32]) {
658 let line = &mut self.lines[channel];
659 let length = line.len();
660 if length == 0 {
661 return;
662 }
663 let skip = input.len().saturating_sub(length);
664 let mut cursor = (self.cursor + skip % length) % length;
665 for &sample in &input[skip..] {
666 line[cursor] = sample;
667 cursor += 1;
668 if cursor == length {
669 cursor = 0;
670 }
671 }
672 }
673 fn advance(&mut self, frames: usize) {
675 let length = self.lines[0].len();
676 if length != 0 {
677 self.cursor = (self.cursor + frames % length) % length;
678 }
679 }
680 fn save_state(&self) -> StateBlob {
681 let mut bytes = Vec::with_capacity(8 + self.lines.iter().map(Vec::len).sum::<usize>() * 4);
682 bytes.extend_from_slice(&(u64::try_from(self.cursor).unwrap_or(0)).to_le_bytes());
683 for value in self.lines.iter().flatten() {
684 bytes.extend_from_slice(&value.to_le_bytes());
685 }
686 StateBlob::new(bytes)
687 }
688 fn check(&self, state: &StateBlob) -> Result<usize, StateError> {
692 let bytes = state.as_bytes();
693 let samples = self.lines.iter().map(Vec::len).sum::<usize>();
694 if bytes.len() != 8 + samples * 4 {
695 return Err(StateError::Mismatch);
696 }
697 let cursor = usize::try_from(u64::from_le_bytes(
698 bytes[..8].try_into().expect("fixed range"),
699 ))
700 .map_err(|_| StateError::Invalid)?;
701 if cursor >= self.lines[0].len().max(1) {
702 return Err(StateError::Invalid);
703 }
704 Ok(cursor)
705 }
706 fn load(&mut self, state: &StateBlob, cursor: usize) {
708 let values = state.as_bytes()[8..]
709 .as_chunks::<4>()
710 .0
711 .iter()
712 .map(|word| f32::from_le_bytes(*word));
713 for (target, value) in self.lines.iter_mut().flatten().zip(values) {
714 *target = value;
715 }
716 self.cursor = cursor;
717 }
718 fn check_record<'a>(&self, state: &'a StateBlob) -> Result<Record<'a>, StateError> {
722 if self.lines[0].is_empty() {
723 Ok(Record::Ignore)
724 } else if state.as_bytes().len() == 8 {
725 Ok(Record::Empty)
726 } else {
727 Ok(Record::Load(state, self.check(state)?))
728 }
729 }
730 fn load_record(&mut self, record: Record<'_>) {
731 match record {
732 Record::Ignore => {}
733 Record::Empty => self.reset(),
734 Record::Load(state, cursor) => self.load(state, cursor),
735 }
736 }
737}
738
739#[derive(Copy, Clone)]
741enum Record<'a> {
742 Ignore,
743 Empty,
744 Load(&'a StateBlob, usize),
745}
746
747pub struct AudioGraph {
755 layout: ChannelLayout,
756 clip_chains: Vec<ProcessorChain>,
757 track_buses: Vec<ProcessorChain>,
758 master: ProcessorChain,
759 alignment: Vec<Delay>,
761 mix: [Vec<f32>; 2],
762 bus_output: [Vec<f32>; 2],
763 track_output: [Vec<f32>; 2],
764 max_block: usize,
765}
766
767#[derive(Clone, Debug, Default, Eq, PartialEq)]
769pub struct AudioGraphState {
770 clip_chains: Vec<StateBlob>,
771 track_buses: Vec<StateBlob>,
772 master: StateBlob,
773 alignment: Vec<StateBlob>,
774}
775
776impl AudioGraph {
777 #[must_use]
779 pub fn new(layout: ChannelLayout, buses: usize) -> Self {
780 Self {
781 layout,
782 clip_chains: (0..buses).map(|_| ProcessorChain::new(layout)).collect(),
783 track_buses: (0..buses).map(|_| ProcessorChain::new(layout)).collect(),
784 master: ProcessorChain::new(layout),
785 alignment: (0..buses).map(|_| Delay::default()).collect(),
786 mix: [Vec::new(), Vec::new()],
787 bus_output: [Vec::new(), Vec::new()],
788 track_output: [Vec::new(), Vec::new()],
789 max_block: 0,
790 }
791 }
792 #[must_use]
794 pub const fn layout(&self) -> ChannelLayout {
795 self.layout
796 }
797 #[must_use]
799 pub fn buses(&self) -> usize {
800 self.clip_chains.len()
801 }
802 pub fn clip_chain_mut(&mut self, bus: usize) -> Option<&mut ProcessorChain> {
804 self.clip_chains.get_mut(bus)
805 }
806 pub fn track_bus_mut(&mut self, bus: usize) -> Option<&mut ProcessorChain> {
808 self.track_buses.get_mut(bus)
809 }
810 pub fn master_mut(&mut self) -> &mut ProcessorChain {
812 &mut self.master
813 }
814 pub fn prepare(&mut self, sample_rate: u32, max_block: usize) {
816 self.max_block = max_block.max(1);
818 for chain in self
819 .clip_chains
820 .iter_mut()
821 .chain(&mut self.track_buses)
822 .chain(core::iter::once(&mut self.master))
823 {
824 chain.prepare(sample_rate, self.max_block);
825 }
826 for channel in 0..2 {
827 self.mix[channel].resize(self.max_block, 0.0);
828 self.bus_output[channel].resize(self.max_block, 0.0);
829 self.track_output[channel].resize(self.max_block, 0.0);
830 }
831 let longest = self.bus_latency();
832 for bus in 0..self.alignment.len() {
833 let pad = longest - self.path_latency(bus);
834 self.alignment[bus].resize(
835 usize::try_from(pad).unwrap_or(usize::MAX),
836 self.layout.channels(),
837 );
838 }
839 }
840 fn path_latency(&self, bus: usize) -> u32 {
842 self.clip_chains[bus]
843 .latency_samples()
844 .saturating_add(self.track_buses[bus].latency_samples())
845 }
846 fn bus_latency(&self) -> u32 {
848 (0..self.clip_chains.len())
849 .map(|bus| self.path_latency(bus))
850 .max()
851 .unwrap_or(0)
852 }
853 #[must_use]
856 pub fn latency_samples(&self) -> u32 {
857 self.bus_latency()
858 .saturating_add(self.master.latency_samples())
859 }
860 pub fn process(&mut self, ctx: &ProcessCtx, inputs: &[&[f32]], outputs: &mut [&mut [f32]]) {
868 let channels = self.layout.channels();
869 if inputs.len() < self.clip_chains.len() * channels
870 || outputs.len() < channels
871 || self.max_block == 0
872 {
873 for output in outputs.iter_mut() {
874 output.fill(0.0);
875 }
876 return;
877 }
878 let frames = outputs
879 .iter()
880 .take(channels)
881 .map(|v| v.len())
882 .min()
883 .unwrap_or(0);
884 let mut start = 0;
885 while start < frames {
886 let end = (start + self.max_block).min(frames);
887 let ctx = ctx.offset_by(i64::try_from(start).unwrap_or(i64::MAX));
888 self.process_piece(&ctx, inputs, outputs, start, end);
889 start = end;
890 }
891 }
892
893 fn process_piece(
895 &mut self,
896 ctx: &ProcessCtx,
897 inputs: &[&[f32]],
898 outputs: &mut [&mut [f32]],
899 start: usize,
900 end: usize,
901 ) {
902 let channels = self.layout.channels();
903 let frames = end - start;
904 for channel in 0..channels {
905 self.mix[channel][..frames].fill(0.0);
906 }
907 for bus in 0..self.clip_chains.len() {
908 let base = bus * channels;
909 let piece = |channel: usize| {
910 let input = inputs[base + channel];
911 &input[start.min(input.len())..end.min(input.len())]
912 };
913 let bus_inputs: [&[f32]; 2] = [piece(0), piece(channels - 1)];
914 process_chain_to_internal(
915 &mut self.clip_chains[bus],
916 ctx,
917 channels,
918 frames,
919 &bus_inputs[..channels],
920 &mut self.bus_output,
921 );
922 let bus_refs: [&[f32]; 2] =
923 [&self.bus_output[0][..frames], &self.bus_output[1][..frames]];
924 let track_ctx = ctx.offset_by(-i64::from(self.clip_chains[bus].latency_samples()));
926 process_chain_to_internal(
927 &mut self.track_buses[bus],
928 &track_ctx,
929 channels,
930 frames,
931 &bus_refs[..channels],
932 &mut self.track_output,
933 );
934 let alignment = &mut self.alignment[bus];
935 for channel in 0..channels {
936 alignment.delay_in_place(channel, &mut self.track_output[channel][..frames]);
937 }
938 alignment.advance(frames);
939 for channel in 0..channels {
940 for frame in 0..frames {
941 self.mix[channel][frame] += self.track_output[channel][frame];
942 }
943 }
944 }
945 let mix_refs: [&[f32]; 2] = [&self.mix[0][..frames], &self.mix[1][..frames]];
946 let ctx = ctx.offset_by(-i64::from(self.bus_latency()));
948 let (left, right) = outputs.split_at_mut(1);
949 match channels {
950 1 => self
951 .master
952 .process(&ctx, &mix_refs[..1], &mut [&mut left[0][start..end]]),
953 _ => self.master.process(
954 &ctx,
955 &mix_refs[..2],
956 &mut [&mut left[0][start..end], &mut right[0][start..end]],
957 ),
958 }
959 }
960 pub fn reset(&mut self) {
962 for chain in self
963 .clip_chains
964 .iter_mut()
965 .chain(&mut self.track_buses)
966 .chain(core::iter::once(&mut self.master))
967 {
968 chain.reset();
969 }
970 for alignment in &mut self.alignment {
971 alignment.reset();
972 }
973 }
974
975 #[must_use]
978 pub fn save_state(&self) -> AudioGraphState {
979 AudioGraphState {
980 clip_chains: self
981 .clip_chains
982 .iter()
983 .map(ProcessorChain::save_state)
984 .collect(),
985 track_buses: self
986 .track_buses
987 .iter()
988 .map(ProcessorChain::save_state)
989 .collect(),
990 master: self.master.save_state(),
991 alignment: self.alignment.iter().map(Delay::save_state).collect(),
992 }
993 }
994
995 pub fn load_state(&mut self, state: &AudioGraphState) -> Result<(), GraphStateError> {
1004 let buses = self.clip_chains.len();
1005 if state.clip_chains.len() != buses
1006 || state.track_buses.len() != buses
1007 || state.alignment.len() != buses
1008 {
1009 return Err(GraphStateError::Topology);
1010 }
1011 let mut cursors = Vec::with_capacity(buses);
1012 for (bus, (alignment, saved)) in self.alignment.iter().zip(&state.alignment).enumerate() {
1013 cursors.push(
1014 alignment
1015 .check(saved)
1016 .map_err(|error| GraphStateError::Alignment { bus, error })?,
1017 );
1018 }
1019 let snapshot = self
1020 .chains()
1021 .map(ProcessorChain::save_state)
1022 .collect::<Vec<_>>();
1023 let saved = state
1024 .clip_chains
1025 .iter()
1026 .chain(&state.track_buses)
1027 .chain(core::iter::once(&state.master));
1028 let refused =
1029 self.chains_mut()
1030 .zip(saved)
1031 .enumerate()
1032 .find_map(|(index, (chain, saved))| {
1033 chain.load_state(saved).err().map(|error| (index, error))
1034 });
1035 if let Some((index, error)) = refused {
1036 for (chain, state) in self.chains_mut().zip(&snapshot).take(index) {
1037 if chain.load_state(state).is_err() {
1038 chain.reset();
1039 }
1040 }
1041 return Err(if index < buses {
1042 GraphStateError::ClipChain { bus: index, error }
1043 } else if index < 2 * buses {
1044 GraphStateError::TrackBus {
1045 bus: index - buses,
1046 error,
1047 }
1048 } else {
1049 GraphStateError::Master(error)
1050 });
1051 }
1052 for ((alignment, saved), cursor) in
1053 self.alignment.iter_mut().zip(&state.alignment).zip(cursors)
1054 {
1055 alignment.load(saved, cursor);
1056 }
1057 Ok(())
1058 }
1059
1060 fn chains(&self) -> impl Iterator<Item = &ProcessorChain> {
1062 self.clip_chains
1063 .iter()
1064 .chain(&self.track_buses)
1065 .chain(core::iter::once(&self.master))
1066 }
1067
1068 fn chains_mut(&mut self) -> impl Iterator<Item = &mut ProcessorChain> {
1069 self.clip_chains
1070 .iter_mut()
1071 .chain(&mut self.track_buses)
1072 .chain(core::iter::once(&mut self.master))
1073 }
1074}
1075
1076fn process_chain_to_internal(
1077 chain: &mut ProcessorChain,
1078 ctx: &ProcessCtx,
1079 channels: usize,
1080 frames: usize,
1081 inputs: &[&[f32]],
1082 output: &mut [Vec<f32>; 2],
1083) {
1084 for channel in output.iter_mut().take(channels) {
1087 channel[..frames].fill(0.0);
1088 }
1089 match channels {
1090 1 => chain.process(ctx, inputs, &mut [&mut output[0][..frames]]),
1091 2 => {
1092 let (left, right) = output.split_at_mut(1);
1093 chain.process(
1094 ctx,
1095 inputs,
1096 &mut [&mut left[0][..frames], &mut right[0][..frames]],
1097 );
1098 }
1099 _ => {}
1100 }
1101}