insta_fun/
snapshot.rs

1use fundsp::prelude::*;
2
3use crate::chart::generate_svg;
4use crate::config::{Processing, SnapshotConfig};
5use crate::input::InputSource;
6
7/// Create an SVG snapshot of audio unit outputs
8/// ## Example
9///
10/// ```
11/// use insta_fun::prelude::*;
12/// use fundsp::hacker::prelude::*;
13///
14/// let unit = sine_hz::<f32>(440.0);
15/// let svg = snapshot_audio_unit(unit);
16/// println!("{svg}");
17/// ```
18pub 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
25/// Create an SVG snapshot of audio unit outputs, with options
26///
27/// ## Example
28///
29/// ```
30/// use insta_fun::prelude::*;
31/// use fundsp::hacker::prelude::*;
32///
33/// let unit = sine_hz::<f32>(440.0);
34/// let svg = snapshot_audio_unit_with_options(unit, SnapshotConfig::default());
35/// println!("{svg}");
36/// ```
37pub 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
44/// Create an SVG snapshot of audio unit inputs and outputs
45///
46/// ## Example
47///
48/// ```
49/// use insta_fun::prelude::*;
50/// use fundsp::hacker::prelude::*;
51///
52/// let unit = sine_hz::<f32>(440.0);
53/// let svg = snapshot_audio_unit_with_input(unit, InputSource::None);
54/// println!("{svg}");
55/// ```
56pub 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
70/// Create an SVG snapshot of audio unit inputs and outputs, with options
71///
72/// ## Example
73///
74/// ```
75/// use insta_fun::prelude::*;
76/// use fundsp::hacker::prelude::*;
77///
78/// let config = SnapshotConfig::default();
79/// let unit = sine_hz::<f32>(440.0);
80/// let svg = snapshot_audio_unit_with_input_and_options(unit, InputSource::None, config);
81/// println!("{svg}");
82/// ```
83pub 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}