1use fundsp::prelude::*;
2
3use crate::chart::generate_svg;
4use crate::config::{Processing, SnapshotConfig};
5use crate::input::InputSource;
6
7pub fn snapshot_audio_unit<N>(unit: N) -> String
19where
20 N: AudioUnit,
21{
22 snapshot_audio_unit_with_input_and_options(unit, InputSource::None, SnapshotConfig::default())
23}
24
25pub fn snapshot_audio_unit_with_options<N>(unit: N, options: SnapshotConfig) -> String
38where
39 N: AudioUnit,
40{
41 snapshot_audio_unit_with_input_and_options(unit, InputSource::None, options)
42}
43
44pub fn snapshot_audio_unit_with_input<N>(unit: N, input_source: InputSource) -> String
57where
58 N: AudioUnit,
59{
60 snapshot_audio_unit_with_input_and_options(
61 unit,
62 input_source,
63 SnapshotConfig {
64 with_inputs: true,
65 ..SnapshotConfig::default()
66 },
67 )
68}
69
70pub fn snapshot_audio_unit_with_input_and_options<N>(
84 mut unit: N,
85 input_source: InputSource,
86 config: SnapshotConfig,
87) -> String
88where
89 N: AudioUnit,
90{
91 let num_inputs = N::inputs(&unit);
92 let num_outputs = N::outputs(&unit);
93
94 unit.set_sample_rate(config.sample_rate);
95 unit.reset();
96 unit.allocate();
97
98 let input_data = input_source.into_data(num_inputs, config.num_samples);
99
100 let mut output_data: Vec<Vec<f32>> = vec![vec![]; num_outputs];
101
102 match config.processing_mode {
103 Processing::Tick => {
104 (0..config.num_samples).for_each(|i| {
105 let mut input_frame = vec![0.0; num_inputs];
106 for ch in 0..num_inputs {
107 input_frame[ch] = input_data[ch][i];
108 }
109 let mut output_frame = vec![0.0; num_outputs];
110 unit.tick(&input_frame, &mut output_frame);
111 for ch in 0..num_outputs {
112 output_data[ch].push(output_frame[ch]);
113 }
114 });
115 }
116 Processing::Batch(batch_size) => {
117 assert!(
118 batch_size <= MAX_BUFFER_SIZE as u8,
119 "Batch size must be less than or equal to [{MAX_BUFFER_SIZE}]"
120 );
121
122 let samples_index = (0..config.num_samples).collect::<Vec<_>>();
123 for chunk in samples_index.chunks(batch_size as usize) {
124 let mut input_buff = BufferVec::new(num_inputs);
125 for (frame_index, input_index) in chunk.iter().enumerate() {
126 for (ch, input) in input_data.iter().enumerate() {
127 let value: f32 = input[*input_index];
128 input_buff.set_f32(ch, frame_index, value);
129 }
130 }
131 let input_ref = input_buff.buffer_ref();
132 let mut output_buf = BufferVec::new(num_outputs);
133 let mut output_ref = output_buf.buffer_mut();
134
135 unit.process(chunk.len(), &input_ref, &mut output_ref);
136
137 for (ch, data) in output_data.iter_mut().enumerate() {
138 data.extend_from_slice(output_buf.channel_f32(ch));
139 }
140 }
141 }
142 }
143
144 generate_svg(&input_data, &output_data, &config)
145}