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 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 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 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 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 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 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}