loopers_engine/
sample.rs

1use std::sync::Arc;
2use std::fmt::{Debug, Formatter};
3use loopers_common::api::LooperSpeed;
4use itertools::Itertools;
5
6#[cfg(test)]
7mod tests {
8    use super::*;
9
10    #[test]
11    fn test_new() {
12        let sample = Sample::with_size(100);
13        assert_eq!(100, sample.length());
14        assert_eq!(100, sample.buffer[0].len());
15        assert_eq!(100, sample.buffer[1].len());
16    }
17
18    #[test]
19    fn test_from_mono() {
20        let buf = vec![1.0f32, 1.0, 2.0, 2.0];
21        let sample = Sample::from_mono(&buf);
22        assert_eq!(4, sample.length());
23        assert_eq!(vec![0.5f32, 0.5, 1.0, 1.0], sample.buffer[0]);
24        assert_eq!(vec![0.5f32, 0.5, 1.0, 1.0], sample.buffer[1]);
25    }
26
27    #[test]
28    fn test_record() {
29        let mut sample = Sample::new();
30        let data = [vec![1.0f32, 1.0], vec![-1.0, -1.0]];
31
32        sample.record(&[&data[0], &data[1]]);
33        assert_eq!(2, sample.length());
34        assert_eq!(vec![1.0f32, 1.0], sample.buffer[0]);
35        assert_eq!(vec![-1.0f32, -1.0], sample.buffer[1]);
36
37        sample.record(&[&data[1], &data[0]]);
38        assert_eq!(4, sample.length());
39        assert_eq!(vec![1.0f32, 1.0, -1.0, -1.0], sample.buffer[0]);
40        assert_eq!(vec![-1.0f32, -1.0, 1.0, 1.0], sample.buffer[1]);
41    }
42
43    #[test]
44    fn test_overdub() {
45        let mut sample = Sample::with_size(8);
46        let data = [vec![1.0f32, 1.0], vec![-1.0, -1.0]];
47        sample.overdub(0, &[&data[0], &data[1]], LooperSpeed::One);
48        assert_eq!(8, sample.length());
49        assert_eq!(
50            vec![1.0f32, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
51            sample.buffer[0]
52        );
53        assert_eq!(
54            vec![-1.0f32, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
55            sample.buffer[1]
56        );
57
58        sample.overdub(0, &[&data[0], &data[1]], LooperSpeed::One);
59        assert_eq!(8, sample.length());
60        assert_eq!(
61            vec![2.0f32, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
62            sample.buffer[0]
63        );
64        assert_eq!(
65            vec![-2.0f32, -2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
66            sample.buffer[1]
67        );
68
69        sample.overdub(6, &[&data[0], &data[1]], LooperSpeed::One);
70        assert_eq!(8, sample.length());
71        assert_eq!(
72            vec![2.0f32, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0],
73            sample.buffer[0]
74        );
75        assert_eq!(
76            vec![-2.0f32, -2.0, 0.0, 0.0, 0.0, 0.0, -1.0, -1.0],
77            sample.buffer[1]
78        );
79    }
80
81    #[test]
82    fn test_overdub_0_5x() {
83        let mut sample = Sample::with_size(8);
84        let data = [vec![1.0f32, 2.0, 3.0, 4.0], vec![-1.0, -2.0, -3.0, -4.0]];
85        sample.overdub(0, &[&data[0], &data[1]], LooperSpeed::Half);
86        assert_eq!(8, sample.length());
87        assert_eq!(
88            vec![1.5f32, 3.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
89            sample.buffer[0]
90        );
91        assert_eq!(
92            vec![-1.5f32, -3.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
93            sample.buffer[1]
94        );
95    }
96
97    #[test]
98    fn test_overdub_2x() {
99        let mut sample = Sample::with_size(8);
100        let data = [vec![1.0f32, 2.0, 3.0, 4.0], vec![-1.0, -2.0, -3.0, -4.0]];
101        sample.overdub(0, &[&data[0], &data[1]], LooperSpeed::Double);
102        assert_eq!(8, sample.length());
103        assert_eq!(
104            vec![1.0f32, 1.0, 2.0, 2.0, 3.0, 3.0, 4.0, 4.0],
105            sample.buffer[0]
106        );
107        assert_eq!(
108            vec![-1.0f32, -1.0, -2.0, -2.0, -3.0, -3.0, -4.0, -4.0],
109            sample.buffer[1]
110        );
111
112    }
113
114    #[test]
115    fn test_xfade() {
116        let mut sample = Sample::with_size(0);
117        let data = [vec![1.0f32; 8], vec![-1.0f32; 8]];
118        sample.record(&[&data[0], &data[1]]);
119
120        let xfade = [vec![3.0f32; 3], vec![-3.0f32; 3]];
121        sample.xfade(
122            3,
123            0,
124            0,
125            &[&xfade[0][0..2], &xfade[1][0..2]],
126            XfadeDirection::OUT,
127            linear,
128        );
129        sample.xfade(
130            3,
131            2,
132            2,
133            &[&xfade[0][2..], &xfade[1][2..]],
134            XfadeDirection::OUT,
135            linear,
136        );
137
138        let l: Vec<i64> = sample.buffer[0]
139            .iter()
140            .map(|f| (*f * 1000f32).floor() as i64)
141            .collect();
142        let r: Vec<i64> = sample.buffer[1]
143            .iter()
144            .map(|f| (*f * 1000f32).ceil() as i64)
145            .collect();
146
147        assert_eq!(8, sample.length());
148        assert_eq!(vec![3000i64, 2333, 1666, 1000, 1000, 1000, 1000, 1000], l);
149        assert_eq!(
150            vec![-3000i64, -2333, -1666, -1000, -1000, -1000, -1000, -1000],
151            r
152        );
153    }
154}
155
156#[allow(dead_code)]
157pub fn linear(x: f32) -> f32 {
158    x
159}
160
161pub fn norm(x: f32) -> f32 {
162    x / (x * x + (1.0 - x) * (1.0 - x)).sqrt()
163}
164
165#[derive(Clone)]
166pub struct Sample {
167    pub buffer: [Vec<f32>; 2],
168}
169
170pub enum XfadeDirection {
171    IN,
172    OUT,
173}
174
175impl Debug for Sample {
176    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
177        write!(f, "<sample [{}]>", self.buffer[0].len())
178    }
179}
180
181impl Sample {
182    pub fn new() -> Sample {
183        Sample::with_size(0)
184    }
185
186    pub fn with_size(len: usize) -> Sample {
187        Sample {
188            buffer: [vec![0f32; len], vec![0f32; len]],
189        }
190    }
191
192    pub fn from_mono(buffer: &[f32]) -> Sample {
193        let half: Vec<f32> = buffer.iter().map(|x| *x / 2f32).collect();
194        Sample {
195            buffer: [half.clone(), half],
196        }
197    }
198
199    pub fn length(&self) -> u64 {
200        self.buffer[0].len() as u64
201    }
202
203    // Records data onto this sample, expanding the buffer as necessary
204    pub fn record(&mut self, data: &[&[f32]]) {
205        assert_eq!(2, data.len());
206        assert_eq!(data[0].len(), data[1].len());
207
208        self.buffer[0].extend_from_slice(data[0]);
209        self.buffer[1].extend_from_slice(data[1]);
210    }
211
212    // Overdubs the buffer, starting at the give time. len(data[{0, 1}]) + time_in_samples must
213    // be < than self.len().
214    pub fn overdub(&mut self, time_in_samples: u64, data: &[&[f32]], speed: LooperSpeed) {
215        assert_eq!(2, data.len());
216        assert_eq!(data[0].len(), data[1].len());
217        let len = self.length() as usize;
218
219        let time_in_samples = match speed {
220            LooperSpeed::Half => time_in_samples / 2,
221            LooperSpeed::One => time_in_samples,
222            LooperSpeed::Double => time_in_samples * 2,
223        };
224
225        for (i, channel) in data.iter().enumerate() {
226            match speed {
227                LooperSpeed::Double => {
228                    // in half speed mode we record every sample twice
229                    for (t, v) in channel.iter().interleave(channel.iter()).enumerate() {
230                        self.buffer[i][(time_in_samples as usize + t) % len] += *v;
231                    }
232                }
233                LooperSpeed::One => {
234                    // in 1x speed mode we record every sample
235                    for (t, v) in channel.iter().enumerate() {
236                        self.buffer[i][(time_in_samples as usize + t) % len] += *v;
237                    }
238                }
239                LooperSpeed::Half => {
240                    for (t, (v1, v2)) in channel.iter().tuples().enumerate() {
241                        self.buffer[i][(time_in_samples as usize + t) % len] += (*v1 + *v2) / 2.0;
242                    }
243                }
244            }
245        };
246
247    }
248
249    pub fn replace(&mut self, time_in_samples: u64, data: &[&[f32]]) {
250        assert_eq!(2, data.len());
251        assert_eq!(data[0].len(), data[1].len());
252        let len = self.length() as usize;
253
254        for (i, channel) in data.iter().enumerate() {
255            for (t, v) in channel.iter().enumerate() {
256                self.buffer[i][(time_in_samples as usize + t) % len] = *v;
257            }
258        }
259    }
260
261    pub fn clear(&mut self) {
262        for b in self.buffer.iter_mut() {
263            b.iter_mut().for_each(|m| *m = 0.0);
264        }
265    }
266
267    /// Performs a crossfade with the existing buffer using the given function
268    /// The fade direction refers to the given sample -- i.e., a fade in starts
269    /// with 100% of the existing sample, and ends at 100% of the new sample.
270    pub fn xfade(
271        &mut self,
272        xfade_size: usize,
273        start_time_in_fade: u64,
274        time_in_samples: u64,
275        data: &[&[f32]],
276        direction: XfadeDirection,
277        f: fn(f32) -> f32,
278    ) {
279        assert_eq!(2, data.len());
280        assert_eq!(data[0].len(), data[1].len());
281
282        let len = self.length();
283
284        // let end_time = time_in_samples % len + data[0].len() as u64;
285        // assert!(end_time <= xfade_size as u64,
286        //         format!("expected {} <= {}", end_time, xfade_size));
287
288        for i in 0..data.len() {
289            for j in 0..data[i].len() {
290                let idx = ((time_in_samples + j as u64) % len) as usize;
291                let q = (start_time_in_fade + j as u64) as f32 / xfade_size as f32;
292                self.buffer[i][idx] = match direction {
293                    XfadeDirection::IN => self.buffer[i][idx] * f(1.0 - q) + data[i][j] * f(q),
294                    XfadeDirection::OUT => self.buffer[i][idx] * f(q) + data[i][j] * f(1.0 - q),
295                }
296            }
297        }
298    }
299}
300
301pub struct SamplePlayer {
302    pub sample: Arc<Sample>,
303    pub time: usize,
304}
305
306#[derive(PartialOrd, PartialEq)]
307pub enum PlayOutput {
308    Done,
309    NotDone,
310}
311
312impl SamplePlayer {
313    pub fn new(sample: Arc<Sample>) -> SamplePlayer {
314        SamplePlayer { sample, time: 0 }
315    }
316
317    pub fn play(&mut self, out: &mut [&mut [f32]; 2], volume: f32) -> PlayOutput {
318        for i in 0..out[0].len() {
319            let t = self.time + i;
320
321            if t >= self.sample.length() as usize {
322                return PlayOutput::Done;
323            }
324
325            out[0][i] += self.sample.buffer[0][t] * volume;
326            out[1][i] += self.sample.buffer[1][t] * volume;
327        }
328
329        self.time += out[0].len();
330
331        if self.sample.length() <= self.time as u64 {
332            PlayOutput::Done
333        } else {
334            PlayOutput::NotDone
335        }
336    }
337}