insta_fun/
input.rs

1use fundsp::prelude::AudioUnit;
2
3/// Input provided to the audio unit
4#[derive(Default)]
5pub enum InputSource {
6    /// No input
7    #[default]
8    None,
9    /// Input provided by a channel vec
10    ///
11    /// - First vec contains all **channels**
12    /// - Second vec contains **samples** per channel
13    VecByChannel(Vec<Vec<f32>>),
14    /// Input provided by a tick vec
15    ///
16    /// - First vec contains all **ticks**
17    /// - Second vec contains **samples** for all **channels** per tick
18    VecByTick(Vec<Vec<f32>>),
19    /// Input **repeated** on every tick
20    ///
21    /// - Vector contains **samples** for all **channels** for **one** tick
22    Flat(Vec<f32>),
23    /// Input provided by a generator function
24    ///
25    /// - First argument is the sample index
26    /// - Second argument is the channel index
27    Generator(Box<dyn Fn(usize, usize) -> f32>),
28    /// Input provided by an audio unit
29    ///
30    /// Number of outputs of the audio unit must match
31    /// the number of inputs to the test target
32    ///
33    /// * if you need to set sample rate on input unit do that upfront
34    Unit(Box<dyn AudioUnit>),
35}
36
37impl From<Box<dyn AudioUnit>> for InputSource {
38    fn from(unit: Box<dyn AudioUnit>) -> Self {
39        InputSource::Unit(unit)
40    }
41}
42
43impl From<Box<dyn Fn(usize, usize) -> f32>> for InputSource {
44    fn from(generator_fn: Box<dyn Fn(usize, usize) -> f32>) -> Self {
45        InputSource::Generator(generator_fn)
46    }
47}
48
49impl From<Vec<f32>> for InputSource {
50    fn from(data: Vec<f32>) -> Self {
51        InputSource::Flat(data)
52    }
53}
54
55impl From<Vec<Vec<f32>>> for InputSource {
56    fn from(data: Vec<Vec<f32>>) -> Self {
57        InputSource::VecByChannel(data)
58    }
59}
60
61impl InputSource {
62    pub fn impulse() -> Self {
63        Self::Generator(Box::new(|i, _| if i == 0 { 1.0 } else { 0.0 }))
64    }
65    pub fn sine(freq: f32, sample_rate: f32) -> Self {
66        Self::Generator(Box::new(move |i, _| {
67            let phase = 2.0 * std::f32::consts::PI * freq * i as f32 / sample_rate;
68            phase.sin()
69        }))
70    }
71
72    pub fn make_data(&mut self, num_inputs: usize, num_samples: usize) -> Vec<Vec<f32>> {
73        match self {
74            InputSource::None => vec![vec![0.0; num_samples]; num_inputs],
75            InputSource::VecByChannel(data) => {
76                assert_eq!(
77                    data.len(),
78                    num_inputs,
79                    "Input vec size mismatch. Expected {} channels, got {}",
80                    num_inputs,
81                    data.len()
82                );
83                assert!(
84                    data.iter().all(|v| v.len() == num_samples),
85                    "Input vec size mismatch. Expected {} samples per channel, got {}",
86                    num_samples,
87                    data.iter().map(|v| v.len()).max().unwrap_or(0)
88                );
89                data.to_vec()
90            }
91            InputSource::VecByTick(data) => {
92                assert!(
93                    data.iter().all(|v| v.len() == num_inputs),
94                    "Input vec size mismatch. Expected {} channels, got {}",
95                    num_inputs,
96                    data.iter().map(|v| v.len()).max().unwrap_or(0)
97                );
98                assert_eq!(
99                    data.len(),
100                    num_samples,
101                    "Input vec size mismatch. Expected {} samples, got {}",
102                    num_samples,
103                    data.len()
104                );
105                (0..num_inputs)
106                    .map(|ch| (0..num_samples).map(|i| data[i][ch]).collect())
107                    .collect()
108            }
109            InputSource::Flat(data) => {
110                assert_eq!(
111                    data.len(),
112                    num_inputs,
113                    "Input vec size mismatch. Expected {} channels, got {}",
114                    num_inputs,
115                    data.len()
116                );
117                (0..num_inputs)
118                    .map(|ch| (0..num_samples).map(|_| data[ch]).collect())
119                    .collect()
120            }
121            InputSource::Generator(generator_fn) => (0..num_inputs)
122                .map(|ch| (0..num_samples).map(|i| generator_fn(i, ch)).collect())
123                .collect(),
124            InputSource::Unit(unit) => {
125                // 1. Tick the driving unit with an output frame sized to its own outputs().
126                // 2. Collect its raw outputs.
127                // 3. Map/truncate/pad those outputs to the required num_inputs for the target snapshot.
128                let unit_outputs = unit.outputs();
129
130                // Raw capture buffer sized to the driving unit's actual outputs.
131                let mut raw = vec![vec![0.0; num_samples]; unit_outputs];
132                (0..num_samples).for_each(|i| {
133                    let mut outputs = vec![0.0; unit_outputs];
134                    unit.tick(&[], &mut outputs);
135                    for ch in 0..unit_outputs {
136                        raw[ch][i] = outputs[ch];
137                    }
138                });
139
140                // Map raw outputs to target input channels.
141                // If fewer outputs than required, remaining channels stay silent (zeros).
142                // If more outputs than required, excess channels are discarded.
143                let mut data = vec![vec![0.0; num_samples]; num_inputs];
144                for ch in 0..num_inputs {
145                    if ch < unit_outputs {
146                        data[ch] = raw[ch].clone();
147                    }
148                }
149                data
150            }
151        }
152    }
153}