loopers_engine/
looper.rs

1use crate::sample;
2use crate::sample::{Sample, XfadeDirection};
3use crossbeam_channel::{bounded, Receiver, Sender, TrySendError};
4use crossbeam_queue::ArrayQueue;
5use std::path::{Path, PathBuf};
6use std::sync::Arc;
7use std::thread;
8
9use crate::error::SaveLoadError;
10use loopers_common::api::{
11    FrameTime, LooperCommand, LooperMode, LooperSpeed, Part, PartSet, SavedLooper,
12};
13use loopers_common::gui_channel::GuiCommand::{AddNewSample, AddOverdubSample};
14use loopers_common::gui_channel::{
15    GuiCommand, GuiSender, LooperState, Waveform, WAVEFORM_DOWNSAMPLE,
16};
17use loopers_common::music::PanLaw;
18use std::collections::VecDeque;
19use std::fmt::{Debug, Formatter};
20use std::mem::swap;
21
22use atomic::Atomic;
23use std::sync::atomic::Ordering;
24
25
26#[cfg(test)]
27mod tests {
28    use super::*;
29    use std::f32::consts::PI;
30    use tempfile::tempdir;
31
32    fn install_test_logger() {
33        let _ = fern::Dispatch::new()
34            .level(log::LevelFilter::Debug)
35            .chain(fern::Output::call(|record| println!("{}", record.args())))
36            .apply();
37    }
38
39    fn process_until_done(looper: &mut Looper) {
40        loop {
41            let msg = looper.backend.as_mut().unwrap().channel.try_recv();
42            match msg {
43                Ok(msg) => looper.backend.as_mut().unwrap().handle_msg(msg),
44                Err(_) => break,
45            };
46        }
47    }
48
49    fn verify_mode(looper: &Looper, expected: LooperMode) {
50        assert_eq!(
51            looper.backend.as_ref().unwrap().mode(),
52            expected,
53            "backend in unexpected state"
54        );
55        assert_eq!(looper.mode(), expected, "looper in unexpected state");
56    }
57
58    fn verify_length(looper: &Looper, expected: u64) {
59        assert_eq!(
60            looper.backend.as_ref().unwrap().length_in_samples(false),
61            expected,
62            "backend has unexpected length"
63        );
64        assert_eq!(
65            looper.length(), expected,
66            "looper has unexpected length"
67        );
68    }
69
70    fn looper_for_test() -> Looper {
71        let mut l = Looper::new(1, PartSet::new(), GuiSender::disconnected());
72        l.pan_law = PanLaw::Transparent;
73        l.backend.as_mut().unwrap().enable_crossfading = false;
74        l
75    }
76
77    #[test]
78    fn test_transfer_buf() {
79        let mut t = TransferBuf {
80            id: 0,
81            time: FrameTime(12),
82            size: 6,
83            data: [[0i32; TRANSFER_BUF_SIZE]; 2],
84        };
85
86        for i in 0usize..6 {
87            t.data[0][i] = i as i32 + 1;
88            t.data[1][i] = -(i as i32 + 1);
89        }
90
91        assert!(!t.contains_t(FrameTime(0)));
92        assert!(!t.contains_t(FrameTime(11)));
93
94        assert!(t.contains_t(FrameTime(12)));
95        assert!(t.contains_t(FrameTime(17)));
96
97        assert!(!t.contains_t(FrameTime(18)));
98
99        assert_eq!(Some((1, -1)), t.get_t(FrameTime(12)));
100        assert_eq!(Some((6, -6)), t.get_t(FrameTime(17)));
101    }
102
103    #[test]
104    fn test_new() {
105        install_test_logger();
106
107        let looper = looper_for_test();
108        verify_mode(&looper, LooperMode::Playing);
109        assert_eq!(1, looper.id);
110        assert_eq!(0, looper.length());
111    }
112
113    #[test]
114    fn test_transitions() {
115        install_test_logger();
116
117        let mut looper = looper_for_test();
118
119        verify_mode(&looper, LooperMode::Playing);
120
121        looper.transition_to(LooperMode::Recording);
122        process_until_done(&mut looper);
123        verify_mode(&looper, LooperMode::Recording);
124        assert_eq!(1, looper.backend.as_ref().unwrap().samples.len());
125
126        let data = [vec![1.0f32, 1.0], vec![-1.0, -1.0]];
127        looper.process_input(0, &[&data[0], &data[1]], Part::A);
128        process_until_done(&mut looper);
129        looper.transition_to(LooperMode::Overdubbing);
130        process_until_done(&mut looper);
131
132        assert_eq!(2, looper.backend.as_ref().unwrap().samples.len());
133        for s in &looper.backend.as_ref().unwrap().samples {
134            assert_eq!(2, s.length());
135        }
136
137        looper.transition_to(LooperMode::Playing);
138        process_until_done(&mut looper);
139        verify_mode(&looper, LooperMode::Playing);
140
141        looper.transition_to(LooperMode::Recording);
142        process_until_done(&mut looper);
143        assert_eq!(1, looper.backend.as_ref().unwrap().samples.len());
144        verify_length(&looper, 0);
145    }
146
147    #[test]
148    fn test_io() {
149        install_test_logger();
150
151        let mut l = looper_for_test();
152        l.backend.as_mut().unwrap().enable_crossfading = false;
153
154        l.transition_to(LooperMode::Recording);
155        process_until_done(&mut l);
156
157        let mut input_left = vec![0f32; TRANSFER_BUF_SIZE];
158        let mut input_right = vec![0f32; TRANSFER_BUF_SIZE];
159        for i in 0..TRANSFER_BUF_SIZE {
160            input_left[i] = i as f32;
161            input_right[i] = -(i as f32);
162        }
163
164        l.process_input(0, &[&input_left, &input_right], Part::A);
165        process_until_done(&mut l);
166
167        let mut o_l = vec![1f64; TRANSFER_BUF_SIZE];
168        let mut o_r = vec![-1f64; TRANSFER_BUF_SIZE];
169
170        l.transition_to(LooperMode::Playing);
171        process_until_done(&mut l);
172        l.process_input(
173            input_left.len() as u64,
174            &[&input_left, &input_right],
175            Part::A,
176        );
177        process_until_done(&mut l);
178
179        l.process_output(
180            FrameTime(input_left.len() as i64),
181            &mut [&mut o_l, &mut o_r],
182            Part::A,
183            false,
184        );
185        process_until_done(&mut l);
186
187        for i in 0..TRANSFER_BUF_SIZE {
188            assert_eq!(o_l[i], (i + 1) as f64);
189            assert_eq!(o_r[i], -((i + 1) as f64));
190        }
191    }
192
193    #[test]
194    fn test_overdub() {
195        install_test_logger();
196
197        let mut l = looper_for_test();
198        l.backend.as_mut().unwrap().enable_crossfading = false;
199
200        l.transition_to(LooperMode::Recording);
201        process_until_done(&mut l);
202
203        let mut input_left = vec![0f32; TRANSFER_BUF_SIZE];
204        let mut input_right = vec![0f32; TRANSFER_BUF_SIZE];
205        for i in 0..TRANSFER_BUF_SIZE {
206            input_left[i] = i as f32 + 1.0;
207            input_right[i] = -(i as f32 + 1.0);
208        }
209
210        let mut t = 0 as i64;
211
212        l.process_input(t as u64, &[&input_left, &input_right], Part::A);
213        process_until_done(&mut l);
214
215        let mut o_l = vec![0f64; TRANSFER_BUF_SIZE];
216        let mut o_r = vec![0f64; TRANSFER_BUF_SIZE];
217        l.process_output(FrameTime(t), &mut [&mut o_l, &mut o_r], Part::A, false);
218        process_until_done(&mut l);
219
220        t += TRANSFER_BUF_SIZE as i64;
221
222        for (l, r) in o_l.iter().zip(&o_r) {
223            assert_eq!(*l, 0.0);
224            assert_eq!(*r, 0.0);
225        }
226
227        l.transition_to(LooperMode::Overdubbing);
228        process_until_done(&mut l);
229
230        // first record our overdub
231        let mut o_l = vec![0f64; TRANSFER_BUF_SIZE];
232        let mut o_r = vec![0f64; TRANSFER_BUF_SIZE];
233        l.process_output(FrameTime(t), &mut [&mut o_l, &mut o_r], Part::A, false);
234        process_until_done(&mut l);
235
236        l.process_input(t as u64, &[&input_left, &input_right], Part::A);
237        process_until_done(&mut l);
238
239        t += TRANSFER_BUF_SIZE as i64;
240
241        for (i, (l, r)) in o_l.iter().zip(&o_r).enumerate() {
242            assert_eq!(*l, (i + 1) as f64);
243            assert_eq!(*r, -((i + 1) as f64));
244        }
245
246        // on the next go-around, it should be played back
247        let mut o_l = vec![0f64; TRANSFER_BUF_SIZE];
248        let mut o_r = vec![0f64; TRANSFER_BUF_SIZE];
249        l.process_output(FrameTime(t), &mut [&mut o_l, &mut o_r], Part::A, false);
250        process_until_done(&mut l);
251
252        l.process_input(t as u64, &[&input_left, &input_right], Part::A);
253        process_until_done(&mut l);
254
255        for (i, (l, r)) in o_l.iter().zip(&o_r).enumerate() {
256            let v = ((i + 1) * 2) as f64;
257            assert_eq!(*l, v);
258            assert_eq!(*r, -v);
259        }
260    }
261
262    #[test]
263    fn test_solo() {
264        install_test_logger();
265
266        let mut l = looper_for_test();
267        l.transition_to(LooperMode::Recording);
268
269        let input_left = vec![1f32; 128];
270        let input_right = vec![-1f32; 128];
271
272        l.process_input(0, &[&input_left, &input_right], Part::A);
273        process_until_done(&mut l);
274
275        let mut o_l = vec![0f64; 128];
276        let mut o_r = vec![0f64; 128];
277
278        // with solo true and us in Playing, there should be no output
279        l.set_time(FrameTime(0));
280        l.transition_to(LooperMode::Playing);
281        process_until_done(&mut l);
282
283        l.process_output(
284            FrameTime(0),
285            &mut [&mut o_l, &mut o_r],
286            Part::A,
287            true,
288        );
289
290        for i in 0..128 {
291            assert_eq!(0.0, o_l[i]);
292            assert_eq!(0.0, o_r[i]);
293        }
294
295        // with solo true and us in Solo, there should be output
296        l.set_time(FrameTime(0));
297        l.transition_to(LooperMode::Soloed);
298        process_until_done(&mut l);
299
300        l.process_output(
301            FrameTime(0),
302            &mut [&mut o_l, &mut o_r],
303            Part::A,
304            true,
305        );
306
307        for i in 0..128 {
308            assert_eq!(1.0, o_l[i]);
309            assert_eq!(-1.0, o_r[i]);
310        }
311
312        // with solo true and us in Solo, but in another part, there should not be outoput
313        o_l = vec![0f64; 128];
314        o_r = vec![0f64; 128];
315
316        l.set_time(FrameTime(0));
317        process_until_done(&mut l);
318
319        l.process_output(
320            FrameTime(0),
321            &mut [&mut o_l, &mut o_r],
322            Part::B,
323            true,
324        );
325
326        for i in 0..128 {
327            assert_eq!(0.0, o_l[i]);
328            assert_eq!(0.0, o_r[i]);
329        }
330    }
331
332    #[test]
333    fn test_non_harmonious_lengths() {
334        install_test_logger();
335
336        // ensure that everything works correctly when our looper length is not a multiple of the
337        // buffer size or our TRANSFER_BUF_SIZE
338
339        let buf_size = 128;
340
341        let mut l = looper_for_test();
342        l.transition_to(LooperMode::Recording);
343
344        let mut input_left = vec![1f32; buf_size];
345        let mut input_right = vec![-1f32; buf_size];
346
347        let mut time = 0i64;
348
349        let mut o_l = vec![0f64; buf_size];
350        let mut o_r = vec![0f64; buf_size];
351        l.process_output(FrameTime(time), &mut [&mut o_l, &mut o_r], Part::A, false);
352        process_until_done(&mut l);
353
354        l.process_input(0, &[&input_left, &input_right], Part::A);
355        process_until_done(&mut l);
356
357        time += buf_size as i64;
358
359        // first give the part before the state change (which will be recorded)
360        l.process_output(
361            FrameTime(time),
362            &mut [&mut o_l[0..100], &mut o_r[0..100]],
363            Part::A,
364            false,
365        );
366        process_until_done(&mut l);
367
368        input_left = vec![2f32; buf_size];
369        input_right = vec![-2f32; buf_size];
370        l.process_input(
371            time as u64,
372            &[&input_left[0..100], &input_right[0..100]],
373            Part::A,
374        );
375        process_until_done(&mut l);
376
377        time += 100;
378
379        // then transition
380        l.transition_to(LooperMode::Overdubbing);
381        process_until_done(&mut l);
382
383        let len = buf_size + 100;
384        verify_length(&l, len as u64);
385
386        l.process_output(
387            FrameTime(time),
388            &mut [&mut o_l[100..buf_size], &mut o_r[100..buf_size]],
389            Part::A,
390            false,
391        );
392        process_until_done(&mut l);
393
394        l.process_input(
395            time as u64,
396            &[&input_left[100..buf_size], &input_right[100..buf_size]],
397            Part::A,
398        );
399        process_until_done(&mut l);
400
401        time += buf_size as i64 - 100;
402
403        for i in 0..buf_size {
404            if i < 100 {
405                assert_eq!(o_l[i], 0f64);
406                assert_eq!(o_r[i], 0f64);
407            } else {
408                assert_eq!(o_l[i], 1f64);
409                assert_eq!(o_r[i], -1f64);
410            }
411        }
412
413        o_l = vec![0f64; buf_size];
414        o_r = vec![0f64; buf_size];
415        l.process_output(FrameTime(time), &mut [&mut o_l, &mut o_r], Part::A, false);
416        process_until_done(&mut l);
417
418        for i in 0..buf_size {
419            let t = time as usize + i;
420            if t % len < buf_size {
421                assert_eq!(o_l[i], 1f64);
422                assert_eq!(o_r[i], -1f64);
423            } else {
424                assert_eq!(o_l[i], 2f64);
425                assert_eq!(o_r[i], -2f64);
426            }
427        }
428
429        // now we play from the beginning
430        l.set_time(FrameTime(0));
431        process_until_done(&mut l);
432        l.transition_to(LooperMode::Playing);
433        process_until_done(&mut l);
434
435        o_l = vec![0f64; buf_size];
436        o_r = vec![0f64; buf_size];
437        l.process_output(FrameTime(0), &mut [&mut o_l, &mut o_r], Part::A, false);
438        process_until_done(&mut l);
439
440        for i in 0..buf_size {
441            if i < buf_size - 100 {
442                assert_eq!(o_l[i], 3f64);
443                assert_eq!(o_r[i], -3f64);
444            } else {
445                assert_eq!(o_l[i], 1.0f64);
446                assert_eq!(o_r[i], -1.0f64);
447            }
448        }
449    }
450
451    #[test]
452    fn test_offset() {
453        install_test_logger();
454
455        let offset = 4u64;
456
457        let mut l = looper_for_test();
458        l.backend.as_mut().unwrap().enable_crossfading = false;
459
460        l.set_time(FrameTime(offset as i64));
461
462        l.transition_to(LooperMode::Recording);
463        process_until_done(&mut l);
464
465        let mut input_left = vec![0f32; TRANSFER_BUF_SIZE];
466        let mut input_right = vec![0f32; TRANSFER_BUF_SIZE];
467        for i in 0..TRANSFER_BUF_SIZE {
468            input_left[i] = i as f32;
469            input_right[i] = -(i as f32);
470        }
471
472        l.process_input(offset, &[&input_left, &input_right], Part::A);
473        process_until_done(&mut l);
474
475        let mut o_l = vec![1f64; TRANSFER_BUF_SIZE];
476        let mut o_r = vec![-1f64; TRANSFER_BUF_SIZE];
477
478        l.transition_to(LooperMode::Playing);
479        process_until_done(&mut l);
480        l.process_input(
481            offset + input_left.len() as u64,
482            &[&input_left, &input_right],
483            Part::A,
484        );
485        process_until_done(&mut l);
486
487        l.process_output(
488            FrameTime(offset as i64 + input_left.len() as i64),
489            &mut [&mut o_l, &mut o_r],
490            Part::A,
491            false,
492        );
493        process_until_done(&mut l);
494
495        for i in 0..TRANSFER_BUF_SIZE {
496            assert_eq!(o_l[i], (i + 1) as f64);
497            assert_eq!(o_r[i], -((i + 1) as f64));
498        }
499    }
500
501    #[test]
502    fn test_post_xfade() {
503        install_test_logger();
504
505        let mut l = looper_for_test();
506        l.backend.as_mut().unwrap().enable_crossfading = true;
507        l.transition_to(LooperMode::Recording);
508        process_until_done(&mut l);
509
510        let mut time = 0i64;
511
512        let mut input_left = vec![1f32; CROSS_FADE_SAMPLES * 2];
513        let mut input_right = vec![-1f32; CROSS_FADE_SAMPLES * 2];
514        let mut o_l = vec![0f64; CROSS_FADE_SAMPLES * 2];
515        let mut o_r = vec![0f64; CROSS_FADE_SAMPLES * 2];
516
517        l.process_input(time as u64, &[&input_left, &input_right], Part::A);
518        process_until_done(&mut l);
519        l.process_output(FrameTime(time), &mut [&mut o_l, &mut o_r], Part::A, false);
520        process_until_done(&mut l);
521        time += input_left.len() as i64;
522
523        for i in 0..CROSS_FADE_SAMPLES {
524            let q = i as f32 / CROSS_FADE_SAMPLES as f32;
525            input_left[i] = -q / (1f32 - q);
526            input_right[i] = q / (1f32 - q);
527        }
528
529        l.transition_to(LooperMode::Playing);
530        process_until_done(&mut l);
531
532        for i in (0..CROSS_FADE_SAMPLES * 2).step_by(32) {
533            l.process_input(
534                time as u64,
535                &[&input_left[i..i + 32], &input_right[i..i + 32]],
536                Part::A,
537            );
538            process_until_done(&mut l);
539
540            let mut o_l = vec![0f64; 32];
541            let mut o_r = vec![0f64; 32];
542            l.process_output(FrameTime(time), &mut [&mut o_l, &mut o_r], Part::A, false);
543            process_until_done(&mut l);
544
545            time += 32;
546        }
547
548        let mut o_l = vec![0f64; CROSS_FADE_SAMPLES * 2];
549        let mut o_r = vec![0f64; CROSS_FADE_SAMPLES * 2];
550
551        l.process_input(time as u64, &[&input_left, &input_right], Part::A);
552        process_until_done(&mut l);
553
554        l.process_output(FrameTime(time), &mut [&mut o_l, &mut o_r], Part::A, false);
555
556        verify_length(&l, CROSS_FADE_SAMPLES as u64 * 2);
557
558        for i in 0..o_l.len() {
559            if i < CROSS_FADE_SAMPLES {
560                assert!(
561                    (0f64 - o_l[i]).abs() < 0.000001,
562                    "left is {} at idx {}, expected 0",
563                    o_l[i],
564                    time + i as i64
565                );
566                assert!(
567                    (0f64 - o_r[i]).abs() < 0.000001,
568                    "right is {} at idx {}, expected 0",
569                    o_r[i],
570                    time + i as i64
571                );
572            } else {
573                assert_eq!(1f64, o_l[i], "mismatch at {}", time + i as i64);
574                assert_eq!(-1f64, o_r[i], "mismatch at {}", time + i as i64);
575            }
576        }
577    }
578
579    #[test]
580    fn test_pre_xfade() {
581        install_test_logger();
582
583        let mut l = looper_for_test();
584
585        let mut input_left = vec![17f32; CROSS_FADE_SAMPLES];
586        let mut input_right = vec![-17f32; CROSS_FADE_SAMPLES];
587
588        let mut time = 0i64;
589        // process some random input
590        for i in (0..CROSS_FADE_SAMPLES).step_by(32) {
591            l.process_input(
592                time as u64,
593                &[&input_left[i..i + 32], &input_right[i..i + 32]],
594                Part::A,
595            );
596            process_until_done(&mut l);
597
598            let mut o_l = vec![0f64; 32];
599            let mut o_r = vec![0f64; 32];
600            l.process_output(FrameTime(time), &mut [&mut o_l, &mut o_r], Part::A, false);
601            process_until_done(&mut l);
602
603            time += 32;
604        }
605
606        // construct our real input
607        for i in 0..CROSS_FADE_SAMPLES {
608            // q = i / CROSS_FADE_SAMPLES
609            // 0 = d[i] * (1 - q) + x * q
610            // -d[i] * (1-q) = x*q
611            // (-i * (1-q)) / q
612
613            let q = 1.0 - i as f32 / CROSS_FADE_SAMPLES as f32;
614
615            if i != 0 {
616                input_left[i] = -q / (1f32 - q);
617                input_right[i] = q / (1f32 - q);
618            }
619        }
620
621        // process that
622        for i in (0..CROSS_FADE_SAMPLES).step_by(32) {
623            l.process_input(
624                time as u64,
625                &[&input_left[i..i + 32], &input_right[i..i + 32]],
626                Part::A,
627            );
628            process_until_done(&mut l);
629
630            let mut o_l = vec![0f64; 32];
631            let mut o_r = vec![0f64; 32];
632            l.process_output(FrameTime(time), &mut [&mut o_l, &mut o_r], Part::A, false);
633            process_until_done(&mut l);
634
635            time += 32;
636        }
637
638        l.transition_to(LooperMode::Recording);
639        process_until_done(&mut l);
640
641        input_left = vec![1f32; CROSS_FADE_SAMPLES * 2];
642        input_right = vec![-1f32; CROSS_FADE_SAMPLES * 2];
643
644        let mut o_l = vec![0f64; CROSS_FADE_SAMPLES * 2];
645        let mut o_r = vec![0f64; CROSS_FADE_SAMPLES * 2];
646
647        l.process_input(time as u64, &[&input_left, &input_right], Part::A);
648        process_until_done(&mut l);
649        l.process_output(FrameTime(time), &mut [&mut o_l, &mut o_r], Part::A, false);
650        process_until_done(&mut l);
651        time += input_left.len() as i64;
652
653        l.transition_to(LooperMode::Playing);
654        process_until_done(&mut l);
655
656        // Go around again (we don't have the crossfaded samples until the second time around)
657        l.process_input(time as u64, &[&input_left, &input_right], Part::A);
658        process_until_done(&mut l);
659        l.process_output(FrameTime(time), &mut [&mut o_l, &mut o_r], Part::A, false);
660        process_until_done(&mut l);
661        time += input_left.len() as i64;
662
663        let mut o_l = vec![0f64; CROSS_FADE_SAMPLES * 2];
664        let mut o_r = vec![0f64; CROSS_FADE_SAMPLES * 2];
665        l.process_output(FrameTime(time), &mut [&mut o_l, &mut o_r], Part::A, false);
666        process_until_done(&mut l);
667
668        for i in 0..o_l.len() {
669            if i > CROSS_FADE_SAMPLES {
670                assert!(
671                    (0f64 - o_l[i]).abs() < 0.000001,
672                    "left is {} at idx {}, expected 0",
673                    o_l[i],
674                    i
675                );
676                assert!(
677                    (0f64 - o_r[i]).abs() < 0.000001,
678                    "right is {} at idx {}, expected 0",
679                    o_r[i],
680                    i
681                );
682            }
683        }
684    }
685
686    #[test]
687    fn test_serialization() {
688        install_test_logger();
689
690        let dir = tempdir().unwrap();
691        let mut input_left = vec![];
692        let mut input_right = vec![];
693
694        let mut input_left2 = vec![];
695        let mut input_right2 = vec![];
696
697        for t in (0..16).map(|x| x as f32 / 44100.0) {
698            let sample = (t * 440.0 * 2.0 * PI).sin();
699            input_left.push(sample / 2.0);
700            input_right.push(sample / 2.0);
701
702            let sample = (t * 540.0 * 2.0 * PI).sin();
703            input_left2.push(sample / 2.0);
704            input_right2.push(sample / 2.0);
705        }
706
707        let mut l = Looper::new(5, PartSet::new(), GuiSender::disconnected());
708
709        l.transition_to(LooperMode::Recording);
710        process_until_done(&mut l);
711        l.process_input(0, &[&input_left, &input_right], Part::A);
712        process_until_done(&mut l);
713
714        l.transition_to(LooperMode::Overdubbing);
715        process_until_done(&mut l);
716        l.process_input(0, &[&input_left2, &input_right2], Part::A);
717        process_until_done(&mut l);
718
719        let (tx, rx) = bounded(1);
720        l.channel()
721            .send(ControlMessage::Serialize(dir.path().to_path_buf(), tx))
722            .unwrap();
723        process_until_done(&mut l);
724
725        let state = rx.recv().unwrap().unwrap();
726
727        let deserialized =
728            Looper::from_serialized(&state, dir.path(), GuiSender::disconnected()).unwrap();
729
730        assert_eq!(l.id, deserialized.id);
731
732        let b1 = l.backend.as_ref().unwrap();
733        let b2 = deserialized.backend.as_ref().unwrap();
734
735        assert_eq!(2, b2.samples.len());
736
737        for i in 0..input_left.len() {
738            assert!((b1.samples[0].buffer[0][i] - b2.samples[0].buffer[0][i]).abs() < 0.00001);
739            assert!((b1.samples[0].buffer[1][i] - b2.samples[0].buffer[1][i]).abs() < 0.00001);
740
741            assert!((b1.samples[1].buffer[0][i] - b2.samples[1].buffer[0][i]).abs() < 0.00001);
742            assert!((b1.samples[1].buffer[0][i] - b2.samples[1].buffer[1][i]).abs() < 0.00001);
743        }
744    }
745}
746
747const CROSS_FADE_SAMPLES: usize = 8192;
748
749struct StateMachine {
750    transitions: Vec<(
751        Vec<LooperMode>,
752        Vec<LooperMode>,
753        for<'r> fn(&'r mut LooperBackend, LooperMode),
754    )>,
755}
756
757impl StateMachine {
758    fn new() -> StateMachine {
759        use LooperMode::*;
760        StateMachine {
761            transitions: vec![
762                (vec![Recording], vec![], LooperBackend::finish_recording),
763                (
764                    vec![Recording, Overdubbing],
765                    vec![],
766                    LooperBackend::handle_crossfades,
767                ),
768                (
769                    vec![],
770                    vec![Overdubbing],
771                    LooperBackend::prepare_for_overdubbing,
772                ),
773                (
774                    vec![],
775                    vec![Recording],
776                    LooperBackend::prepare_for_recording,
777                ),
778                //(vec![], vec![None], LooperBackend::stop),
779            ],
780        }
781    }
782
783    fn handle_transition(&self, looper: &mut LooperBackend, next_state: LooperMode) {
784        let cur = looper.mode();
785        for transition in &self.transitions {
786            if (transition.0.is_empty() || transition.0.contains(&cur))
787                && (transition.1.is_empty() || transition.1.contains(&next_state))
788            {
789                transition.2(looper, next_state);
790            }
791        }
792        looper.mode.store(next_state, Ordering::Relaxed);
793    }
794}
795
796lazy_static! {
797    static ref STATE_MACHINE: StateMachine = StateMachine::new();
798}
799
800#[derive(Debug)]
801pub enum ControlMessage {
802    InputDataReady { id: u64, size: usize },
803    TransitionTo(LooperMode),
804    SetTime(FrameTime),
805    ReadOutput(FrameTime),
806    Shutdown,
807    Serialize(PathBuf, Sender<Result<SavedLooper, SaveLoadError>>),
808    Deleted,
809    Clear,
810    SetSpeed(LooperSpeed),
811    SetPan(f32),
812    SetLevel(f32),
813    SetParts(PartSet),
814    Undo,
815    Redo,
816    StopOutput,
817}
818
819const TRANSFER_BUF_SIZE: usize = 16;
820
821#[derive(Clone, Copy)]
822struct TransferBuf<DATA: Copy> {
823    id: u64,
824    time: FrameTime,
825    size: usize,
826    data: [[DATA; TRANSFER_BUF_SIZE]; 2],
827}
828
829impl<DATA: Copy> TransferBuf<DATA> {
830    pub fn contains_t(&self, time: FrameTime) -> bool {
831        return time.0 >= self.time.0 && time.0 < self.time.0 + self.size as i64;
832    }
833
834    pub fn get_t(&self, time: FrameTime) -> Option<(DATA, DATA)> {
835        if self.contains_t(time) {
836            let idx = (time.0 - self.time.0) as usize;
837            Some((self.data[0][idx], self.data[1][idx]))
838        } else {
839            None
840        }
841    }
842}
843
844fn compute_waveform(samples: &[Sample], downsample: usize) -> Waveform {
845    let len = samples[0].length() as usize;
846    let size = len / downsample + 1;
847    let mut out = [Vec::with_capacity(size), Vec::with_capacity(size)];
848
849    for c in 0..2 {
850        for t in (0..len).step_by(downsample) {
851            let mut p = 0f64;
852            let end = downsample.min(len - t);
853            for s in samples {
854                for j in 0..end {
855                    let i = t as usize + j;
856                    p += s.buffer[c][i].abs() as f64;
857                }
858            }
859
860            out[c].push((p as f64 / (samples.len() as f64 * end as f64)) as f32);
861        }
862    }
863
864    out
865}
866
867struct WaveformGenerator {
868    id: u32,
869    start_time: FrameTime,
870    acc: [f64; 2],
871    size: usize,
872}
873
874impl WaveformGenerator {
875    fn new(id: u32) -> Self {
876        WaveformGenerator {
877            id,
878            start_time: FrameTime(0),
879            acc: [0.0, 0.0],
880            size: 0,
881        }
882    }
883
884    fn add_buf(
885        &mut self,
886        mode: LooperMode,
887        time: FrameTime,
888        samples: &[&[f64]],
889        looper_length: u64,
890        sender: &mut GuiSender,
891    ) {
892        if !(self.start_time.0..self.start_time.0 + WAVEFORM_DOWNSAMPLE as i64).contains(&time.0) {
893            // there are no samples in this buffer that we can add, so we'll just send on the
894            // partial buffer
895            debug!(
896                "sending partial buffer to GUI because we got a newer one \
897            (cur time = {}, buf time = {})",
898                self.start_time.0, time.0
899            );
900            self.flush(mode, looper_length, sender);
901            self.start_time = time;
902        }
903
904        for i in 0..samples[0].len() {
905            if self.size < WAVEFORM_DOWNSAMPLE {
906                for c in 0..2 {
907                    self.acc[c] += samples[c][i].abs();
908                }
909                self.size += 1;
910            } else {
911                self.flush(mode, looper_length, sender);
912                self.start_time = FrameTime(time.0 + i as i64);
913            }
914        }
915    }
916
917    fn flush(&mut self, mode: LooperMode, looper_length: u64, sender: &mut GuiSender) {
918        let s = [
919            (self.acc[0] / self.size as f64).min(1.0) as f32,
920            (self.acc[1] / self.size as f64).min(1.0) as f32,
921        ];
922        match mode {
923            LooperMode::Recording => {
924                sender.send_update(AddNewSample(self.id, self.start_time, s, looper_length));
925            }
926            LooperMode::Overdubbing => {
927                sender.send_update(AddOverdubSample(self.id, self.start_time, s));
928            }
929            _ => {}
930        }
931
932        self.acc = [0.0, 0.0];
933        self.size = 0;
934    }
935}
936
937enum LooperChange {
938    PushSample,
939    PopSample(Sample),
940    Clear {
941        samples: Vec<Sample>,
942        in_time: FrameTime,
943        out_time: FrameTime,
944        offset: FrameTime,
945    },
946    UnClear,
947}
948
949impl Debug for LooperChange {
950    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
951        match self {
952            LooperChange::PushSample => write!(f, "PushSample"),
953            LooperChange::PopSample(sample) => write!(f, "PopSample<{}>", sample.length()),
954            LooperChange::Clear { samples, .. } => write!(f, "Clear<{}>", samples.len()),
955            LooperChange::UnClear => write!(f, "UnClear"),
956        }
957    }
958}
959
960pub struct LooperBackend {
961    pub id: u32,
962    pub samples: Vec<Sample>,
963    pub mode: Arc<Atomic<LooperMode>>,
964    pub length: Arc<Atomic<u64>>,
965    pub speed: LooperSpeed,
966    pub pan: f32,
967    pub level: f32,
968    pub parts: PartSet,
969    pub deleted: bool,
970
971    offset: FrameTime,
972
973    enable_crossfading: bool,
974
975    out_time: FrameTime,
976    in_time: FrameTime,
977
978    input_buffer: Sample,
979    input_buffer_idx: usize,
980    xfade_samples_left: usize,
981    xfade_sample_idx: usize,
982
983    in_queue: Arc<ArrayQueue<TransferBuf<f32>>>,
984    out_queue: Arc<ArrayQueue<TransferBuf<f64>>>,
985
986    gui_sender: GuiSender,
987
988    // Visible for benchmark
989    pub channel: Receiver<ControlMessage>,
990
991    waveform_generator: WaveformGenerator,
992
993    undo_queue: VecDeque<LooperChange>,
994    redo_queue: VecDeque<LooperChange>,
995
996    should_output: bool,
997    gui_needs_reset: bool,
998}
999
1000impl LooperBackend {
1001    fn start(mut self) {
1002        thread::spawn(move || loop {
1003            match self.channel.recv() {
1004                Ok(msg) => {
1005                    if !self.handle_msg(msg) {
1006                        break;
1007                    }
1008                }
1009                Err(_) => {
1010                    info!("Channel closed, stopping");
1011                    break;
1012                }
1013            }
1014        });
1015    }
1016
1017    pub fn process_until_done(&mut self) {
1018        loop {
1019            let msg = self.channel.try_recv();
1020            match msg {
1021                Ok(msg) => self.handle_msg(msg),
1022                Err(_) => break,
1023            };
1024        }
1025    }
1026
1027    fn current_state(&self) -> LooperState {
1028        LooperState {
1029            mode: self.mode(),
1030            speed: self.speed,
1031            pan: self.pan,
1032            level: self.level,
1033            parts: self.parts,
1034            offset: self.offset,
1035            has_undos: !self.undo_queue.is_empty(),
1036            has_redos: !self.redo_queue.is_empty(),
1037        }
1038    }
1039
1040    pub fn mode(&self) -> LooperMode {
1041        return self.mode.load(Ordering::Relaxed);
1042    }
1043
1044    fn handle_msg(&mut self, msg: ControlMessage) -> bool /* continue */ {
1045        debug!("[{}] got control message: {:?}", self.id, msg);
1046        match msg {
1047            ControlMessage::InputDataReady { id, size } => {
1048                let mut read = 0;
1049                let mut processing = false;
1050                while read < size {
1051                    let buf = self
1052                        .in_queue
1053                        .pop()
1054                        .expect("missing expected data from queue");
1055                    if buf.id == id {
1056                        processing = true;
1057                    } else if processing {
1058                        assert_eq!(read, size, "did not find enough values in input data!");
1059                        break;
1060                    } else {
1061                        warn!(
1062                            "Skipping unexpected input data in looper {}: \
1063                               got {}, but waiting for {}",
1064                            self.id, buf.id, id
1065                        );
1066                    }
1067
1068                    if processing {
1069                        let to_read = (size - read).min(buf.size);
1070                        read += to_read;
1071                        self.handle_input(
1072                            buf.time.0 as u64,
1073                            &[&buf.data[0][0..to_read], &buf.data[1][0..to_read]],
1074                        );
1075                    }
1076                }
1077            }
1078            ControlMessage::TransitionTo(mode) => {
1079                self.transition_to(mode);
1080            }
1081            ControlMessage::Clear => {
1082                self.transition_to(LooperMode::Playing);
1083
1084                let mut samples = vec![];
1085                swap(&mut samples, &mut self.samples);
1086
1087                let change = LooperChange::Clear {
1088                    samples,
1089                    in_time: self.in_time,
1090                    out_time: self.out_time,
1091                    offset: self.offset,
1092                };
1093
1094                self.in_time = FrameTime(0);
1095                self.out_time = FrameTime(0);
1096                self.offset = FrameTime(0);
1097                self.xfade_samples_left = 0;
1098                self.length.store(0, Ordering::Relaxed);
1099                self.gui_sender
1100                    .send_update(GuiCommand::ClearLooper(self.id));
1101
1102                self.add_change(change);
1103            }
1104            ControlMessage::SetTime(time) => {
1105                self.out_time = FrameTime(time.0.max(0));
1106                self.in_time = time;
1107                self.should_output = true;
1108            }
1109            ControlMessage::ReadOutput(time) => {
1110                self.out_time = FrameTime(self.out_time.0.max(time.0));
1111            }
1112            ControlMessage::Shutdown => {
1113                info!("Got shutdown message, stopping");
1114                return false;
1115            }
1116            ControlMessage::Deleted => {
1117                info!("Looper was deleted");
1118                self.gui_sender
1119                    .send_update(GuiCommand::RemoveLooper(self.id));
1120                return false;
1121            }
1122            ControlMessage::Serialize(path, channel) => {
1123                let result = self.serialize(&path);
1124                if let Err(e) = channel.try_send(result) {
1125                    warn!("failed to respond to serialize request: {:?}", e);
1126                }
1127            }
1128            ControlMessage::SetSpeed(speed) => {
1129                self.speed = speed;
1130                self.gui_needs_reset = true;
1131            }
1132            ControlMessage::SetPan(pan) => {
1133                self.pan = pan;
1134                self.gui_sender.send_update(GuiCommand::LooperStateChange(
1135                    self.id,
1136                    self.current_state(),
1137                ));
1138            }
1139            ControlMessage::SetLevel(level) => {
1140                self.level = level;
1141                self.gui_sender.send_update(GuiCommand::LooperStateChange(
1142                    self.id, self.current_state()
1143                ));
1144            }
1145            ControlMessage::SetParts(parts) => {
1146                self.parts = parts;
1147                self.gui_sender.send_update(GuiCommand::LooperStateChange(
1148                    self.id, self.current_state()
1149                ));
1150            },
1151            ControlMessage::Undo => {
1152                info!("Performing Undo on queue: {:?}", self.undo_queue);
1153
1154                if let Some(change) = self.undo_queue.pop_back() {
1155                    if let Some(change) = self.undo_change(change) {
1156                        self.redo_queue.push_back(change);
1157                    }
1158                }
1159                self.gui_sender.send_update(GuiCommand::LooperStateChange(
1160                    self.id, self.current_state()
1161                ));
1162            }
1163            ControlMessage::Redo => {
1164                info!("Performing Redo on queue: {:?}", self.redo_queue);
1165                if let Some(change) = self.redo_queue.pop_back() {
1166                    if let Some(change) = self.undo_change(change) {
1167                        self.undo_queue.push_back(change);
1168                    }
1169                }
1170                self.gui_sender.send_update(GuiCommand::LooperStateChange(
1171                    self.id, self.current_state()
1172                ));
1173            }
1174            ControlMessage::StopOutput => {
1175                self.should_output = false;
1176            }
1177        }
1178
1179        if self.should_output {
1180            self.fill_output();
1181            if self.gui_needs_reset {
1182                self.reset_gui();
1183                self.gui_needs_reset = false;
1184            }
1185        }
1186        true
1187    }
1188
1189    #[inline]
1190    fn time_loop_idx(&self, t: FrameTime, adjust_for_speed: bool) -> usize {
1191        let t = (t - self.offset).0;
1192
1193        if adjust_for_speed {
1194            match self.speed {
1195                LooperSpeed::Half => t / 2,
1196                LooperSpeed::One => t,
1197                LooperSpeed::Double => t * 2,
1198            }
1199        } else {
1200            t
1201        }.rem_euclid(self.length.load(Ordering::Relaxed) as i64) as usize
1202    }
1203
1204    fn fill_output(&mut self) {
1205        let sample_len = self.length_in_samples(true) as usize;
1206        // don't fill the output if we're in record mode, because we don't know our length. the
1207        // timing won't be correct if we wrap around.
1208        if sample_len > 0 && self.mode() != LooperMode::Recording && self.out_time.0 >= 0 {
1209            // make sure we don't pass our input and don't spend too much time doing this
1210            let mut count = 0;
1211            let end = self.in_time.0 + sample_len as i64;
1212            while self.out_time.0 + 1 < end as i64
1213                && count < 32
1214                && self.out_queue.len() < self.out_queue.capacity() / 2
1215            {
1216                let mut buf = TransferBuf {
1217                    id: 0,
1218                    time: self.out_time,
1219                    size: ((end - self.out_time.0) as usize).min(TRANSFER_BUF_SIZE),
1220                    data: [[0f64; TRANSFER_BUF_SIZE]; 2],
1221                };
1222
1223                for sample in &self.samples {
1224                    let b = &sample.buffer;
1225                    if b[0].is_empty() {
1226                        continue;
1227                    }
1228
1229                    for i in 0..2 {
1230                        for t in 0..buf.size {
1231                            buf.data[i][t] +=
1232                                b[i][self.time_loop_idx(self.out_time + FrameTime(t as i64), true)] as f64;
1233                        }
1234                    }
1235                }
1236
1237                if self.out_queue.push(buf).is_err() {
1238                    break;
1239                }
1240
1241                debug!(
1242                    "[OUTPUT {}] t = {} [{}; {}] (in time = {})",
1243                    self.id, self.out_time.0, buf.data[0][0], buf.size, self.in_time.0
1244                );
1245
1246                self.out_time.0 += buf.size as i64;
1247                count += 1;
1248            }
1249        }
1250    }
1251
1252    fn finish_recording(&mut self, _: LooperMode) {
1253        // update our out time to the current input time so that we don't bother outputting a bunch
1254        // of wasted data
1255        self.out_time = self.in_time;
1256
1257        self.add_change(LooperChange::UnClear);
1258
1259        // send our final length to the gui
1260        self.gui_sender
1261            .send_update(GuiCommand::SetLoopLengthAndOffset(
1262                self.id,
1263                self.length_in_samples(false),
1264                self.offset,
1265            ));
1266    }
1267
1268    // state transition functions
1269    fn handle_crossfades(&mut self, _next_state: LooperMode) {
1270        debug!("handling crossfade");
1271        self.xfade_samples_left = CROSS_FADE_SAMPLES;
1272        self.xfade_sample_idx = self.samples.len() - 1;
1273
1274        // handle fading the pre-recorded samples (stored in input buffer) with the _end_ of the
1275        // actual loop
1276        if let Some(s) = self.samples.last_mut() {
1277            let size = self.input_buffer_idx.min(CROSS_FADE_SAMPLES);
1278            if let Some(write_start) = s.length().checked_sub(size as u64) {
1279                // TODO: I'm sure there's a way to do this without allocating
1280                let mut left = vec![0f32; size];
1281                let mut right = vec![0f32; size];
1282
1283                let len = self.input_buffer.length();
1284                let read_start =
1285                    (self.input_buffer_idx as i64 - size as i64).rem_euclid(len as i64) as usize;
1286
1287                for i in 0..size {
1288                    left[i] = self.input_buffer.buffer[0][(i + read_start) % len as usize];
1289                    right[i] = self.input_buffer.buffer[1][(i + read_start) % len as usize];
1290                }
1291
1292                if self.enable_crossfading {
1293                    s.xfade(
1294                        CROSS_FADE_SAMPLES,
1295                        0,
1296                        write_start,
1297                        &[&left, &right],
1298                        XfadeDirection::IN,
1299                        sample::norm,
1300                    );
1301                }
1302            } else {
1303                warn!("Couldn't post crossfade because start was wrong");
1304            }
1305        }
1306
1307        self.input_buffer.clear();
1308        self.input_buffer_idx = 0;
1309    }
1310
1311    fn prepare_for_recording(&mut self, _: LooperMode) {
1312        self.samples.clear();
1313        self.samples.push(Sample::new());
1314        self.length.store(0, Ordering::Relaxed);
1315    }
1316
1317    fn prepare_for_overdubbing(&mut self, _next_state: LooperMode) {
1318        let overdub_sample = Sample::with_size(self.length_in_samples(false) as usize);
1319
1320        // TODO: currently, overdub buffers coming from record are not properly crossfaded until
1321        //       overdubbing is finished
1322        // if we're currently recording, we will start our sample off with a crossfade from
1323        // 0 to the stuff we just recorded. this will be further crossfaded
1324        // if self.mode == LooperMode::Record {
1325        //     if let Some(s) = self.samples.last() {
1326        //         let count = len.min(CROSS_FADE_SAMPLES as u64) as usize;
1327        //         let range = len as usize - count..len as usize;
1328        //         assert_eq!(range.len(), count);
1329        //         self.input_buffer.replace(self.xfade_sample_idx as u64,
1330        //                                   &[&(&s.buffer[0])[range.clone()],
1331        //                                       &(&s.buffer[1])[range]]);
1332        //         self.input_buffer_idx += count;
1333        //     } else {
1334        //         debug!("no previous sample when moving to overdub!");
1335        //     }
1336        // }
1337
1338        self.add_change(LooperChange::PushSample);
1339        self.samples.push(overdub_sample);
1340    }
1341
1342    pub fn transition_to(&mut self, mode: LooperMode) {
1343        debug!("Transition {:?} to {:?}", self.mode, mode);
1344
1345        if self.mode() == mode {
1346            // do nothing if we're not changing state
1347            return;
1348        }
1349
1350        STATE_MACHINE.handle_transition(self, mode);
1351
1352        self.gui_sender.send_update(GuiCommand::LooperStateChange(
1353            self.id,
1354            LooperState {
1355                mode,
1356                speed: self.speed,
1357                pan: self.pan,
1358                level: self.level,
1359                parts: self.parts,
1360                offset: self.offset,
1361                has_undos: !self.undo_queue.is_empty(),
1362                has_redos: !self.redo_queue.is_empty(),
1363            },
1364        ));
1365    }
1366
1367    fn handle_input(&mut self, time_in_samples: u64, inputs: &[&[f32]]) {
1368        if self.mode() == LooperMode::Overdubbing {
1369            // in overdub mode, we add the new samples to our existing buffer
1370            let time_in_loop = self.time_loop_idx(FrameTime(time_in_samples as i64), false);
1371
1372            let s = self
1373                .samples
1374                .last_mut()
1375                .expect("No samples for looper in overdub mode");
1376
1377            s.overdub(time_in_loop as u64, inputs, self.speed);
1378
1379            // TODO: this logic should probably be abstracted out into Sample so it can be reused
1380            //       between here and fill_output
1381            let mut wv = [vec![0f64; inputs[0].len()], vec![0f64; inputs[0].len()]];
1382            for c in 0..2 {
1383                for i in 0..inputs[0].len() {
1384                    for s in &self.samples {
1385                        wv[c][i] += s.buffer[c]
1386                            [self.time_loop_idx(FrameTime(time_in_samples as i64 + i as i64), true)]
1387                            as f64;
1388                    }
1389                }
1390            }
1391            self.waveform_generator.add_buf(
1392                self.mode(),
1393                FrameTime(time_in_samples as i64),
1394                &[&wv[0], &wv[1]],
1395                self.length_in_samples(true),
1396                &mut self.gui_sender,
1397            );
1398        } else if self.mode() == LooperMode::Recording {
1399            // in record mode, we extend the current buffer with the new samples
1400
1401            // if these are the first samples, set the offset to the current time
1402            if self.length_in_samples(false) == 0 {
1403                self.offset = FrameTime(time_in_samples as i64);
1404            }
1405
1406            let s = self
1407                .samples
1408                .last_mut()
1409                .expect("No samples for looper in record mode");
1410            s.record(inputs);
1411
1412            self.length.store(s.length(), Ordering::Relaxed);
1413
1414            // TODO: this allocation isn't really necessary
1415            let mut wv = [vec![0f64; inputs[0].len()], vec![0f64; inputs[0].len()]];
1416            for (c, vs) in inputs.iter().enumerate() {
1417                for (i, v) in vs.iter().enumerate() {
1418                    wv[c][i] = *v as f64;
1419                }
1420            }
1421            self.waveform_generator.add_buf(
1422                self.mode(),
1423                FrameTime(time_in_samples as i64),
1424                &[&wv[0], &wv[1]],
1425                self.length_in_samples(true),
1426                &mut self.gui_sender,
1427            );
1428        } else {
1429            // record to our circular input buffer, which will be used to cross-fade the end
1430            self.input_buffer
1431                .replace(self.input_buffer_idx as u64, inputs);
1432            self.input_buffer_idx += inputs[0].len();
1433        }
1434
1435        // after recording finishes, cross fade some samples with the beginning of the loop to
1436        // reduce popping
1437        if self.xfade_samples_left > 0 {
1438            debug!("crossfading beginning at time {}", time_in_samples);
1439            if let Some(s) = self.samples.get_mut(self.xfade_sample_idx) {
1440                // this assumes that things are sample-aligned
1441                if self.enable_crossfading {
1442                    s.xfade(
1443                        CROSS_FADE_SAMPLES,
1444                        CROSS_FADE_SAMPLES as u64 - self.xfade_samples_left as u64,
1445                        (CROSS_FADE_SAMPLES - self.xfade_samples_left) as u64,
1446                        inputs,
1447                        XfadeDirection::OUT,
1448                        sample::norm,
1449                    );
1450                }
1451                self.xfade_samples_left =
1452                    (self.xfade_samples_left as i64 - inputs[0].len() as i64).max(0) as usize;
1453            } else {
1454                debug!("tried to cross fade but no samples... something is likely wrong");
1455            }
1456        }
1457
1458        self.in_time = FrameTime(time_in_samples as i64 + inputs[0].len() as i64);
1459    }
1460
1461    fn add_change(&mut self, change: LooperChange) {
1462        self.undo_queue.push_back(change);
1463        self.redo_queue.clear();
1464        self.gui_sender.send_update(GuiCommand::LooperStateChange(
1465            self.id, self.current_state()
1466        ));
1467    }
1468
1469    fn reset_gui(&mut self) {
1470        if self.length_in_samples(false) > 0 {
1471            self.gui_sender.send_update(GuiCommand::UpdateLooperWithSamples(
1472                self.id,
1473                self.length_in_samples(true),
1474                Box::new(compute_waveform(&self.samples, WAVEFORM_DOWNSAMPLE)),
1475                self.current_state(),
1476            ));
1477        } else {
1478            self.gui_sender.send_update(GuiCommand::LooperStateChange(
1479                self.id, self.current_state()))
1480        }
1481    }
1482
1483    fn undo_change(&mut self, change: LooperChange) -> Option<LooperChange> {
1484        match change {
1485            LooperChange::PushSample => {
1486                let sample = self.samples.pop()
1487                    .map(|s| LooperChange::PopSample(s));
1488                self.gui_needs_reset = true;
1489                sample
1490            }
1491            LooperChange::PopSample(buffer) => {
1492                self.samples.push(buffer);
1493                self.gui_needs_reset = true;
1494                Some(LooperChange::PushSample)
1495            }
1496            LooperChange::Clear { samples, in_time, out_time, offset } => {
1497                self.samples = samples;
1498                self.in_time = in_time;
1499                self.out_time = out_time;
1500                self.offset = offset;
1501
1502                if !self.samples.is_empty() {
1503                    self.length.store(self.samples[0].length(), Ordering::Relaxed);
1504                }
1505
1506                self.gui_needs_reset = true;
1507
1508                Some(LooperChange::UnClear)
1509            }
1510            LooperChange::UnClear => {
1511                let mut samples = vec![];
1512                swap(&mut samples, &mut self.samples);
1513                let change = Some(LooperChange::Clear {
1514                    samples,
1515                    in_time: self.in_time,
1516                    out_time: self.out_time,
1517                    offset: self.offset,
1518                });
1519                self.in_time = FrameTime(0);
1520                self.out_time = FrameTime(0);
1521                self.offset = FrameTime(0);
1522                self.gui_sender
1523                    .send_update(GuiCommand::ClearLooper(self.id));
1524
1525                change
1526            }
1527        }
1528    }
1529
1530    pub fn length_in_samples(&self, adjust_for_speed: bool) -> u64 {
1531        let len = self.length.load(Ordering::Relaxed);
1532        if adjust_for_speed {
1533            match self.speed {
1534                LooperSpeed::Half => len * 2,
1535                LooperSpeed::One => len,
1536                LooperSpeed::Double => len / 2,
1537            }
1538        } else {
1539            len
1540        }
1541    }
1542
1543    pub fn serialize(&self, path: &Path) -> Result<SavedLooper, SaveLoadError> {
1544        let spec = hound::WavSpec {
1545            channels: 2,
1546            sample_rate: 44100,
1547            bits_per_sample: 32,
1548            sample_format: hound::SampleFormat::Float,
1549        };
1550
1551        let mut saved = SavedLooper {
1552            id: self.id,
1553            mode: self.mode(),
1554            parts: self.parts,
1555            speed: self.speed,
1556            pan: self.pan,
1557            level: self.level,
1558            samples: Vec::with_capacity(self.samples.len()),
1559            offset_samples: self.offset.0,
1560        };
1561
1562        for (i, s) in self.samples.iter().enumerate() {
1563            let name = format!("loop_{}_{}.wav", self.id, i);
1564            let p = path.join(&name);
1565            let mut writer = hound::WavWriter::create(&p, spec.clone())?;
1566
1567            for j in 0..s.length() as usize {
1568                writer.write_sample(s.buffer[0][j])?;
1569                writer.write_sample(s.buffer[1][j])?;
1570            }
1571            writer.finalize()?;
1572            // use the relative path so that the directory can be moved and still be valid
1573            saved.samples.push(PathBuf::from(name));
1574        }
1575
1576        Ok(saved)
1577    }
1578}
1579
1580// The Looper struct encapsulates behavior similar to a single hardware looper. Internally, it is
1581// driven by a state machine, which controls how it responds to input buffers (e.g., by recording
1582// or overdubbing to its internal buffers) and output buffers (e.g., by playing).
1583pub struct Looper {
1584    pub id: u32,
1585    pub deleted: bool,
1586    pub parts: PartSet,
1587    pub pan: f32,
1588    pub level: f32,
1589
1590    pub pan_law: PanLaw,
1591
1592
1593    // this is pretty hacky -- we sometimes need a way to see the mode that has been just set on the
1594    // looper, before it's had a chance to make it to the backend
1595    local_mode: Option<LooperMode>,
1596    mode: Arc<Atomic<LooperMode>>,
1597    length: Arc<Atomic<u64>>,
1598    pub backend: Option<LooperBackend>,
1599    msg_counter: u64,
1600    out_queue: Arc<ArrayQueue<TransferBuf<f32>>>,
1601    in_queue: Arc<ArrayQueue<TransferBuf<f64>>>,
1602    channel: Sender<ControlMessage>,
1603
1604    in_progress_output: Option<TransferBuf<f64>>,
1605
1606    last_time: FrameTime,
1607}
1608
1609impl Looper {
1610    pub fn new(id: u32, parts: PartSet, gui_output: GuiSender) -> Looper {
1611        Self::new_with_samples(
1612            id,
1613            parts,
1614            LooperSpeed::One,
1615            0.0,
1616            1.0,
1617            FrameTime(0),
1618            vec![],
1619            gui_output,
1620        )
1621    }
1622
1623    fn new_with_samples(
1624        id: u32,
1625        parts: PartSet,
1626        speed: LooperSpeed,
1627        pan: f32,
1628        level: f32,
1629        offset: FrameTime,
1630        samples: Vec<Sample>,
1631        mut gui_sender: GuiSender,
1632    ) -> Looper {
1633        debug!("Creating new looper with samples {}", id);
1634        let record_queue = Arc::new(ArrayQueue::new(512 * 1024 / TRANSFER_BUF_SIZE));
1635        let play_queue = Arc::new(ArrayQueue::new(512 * 1024 / TRANSFER_BUF_SIZE));
1636
1637        let (s, r) = bounded(1000);
1638
1639        let length = samples.get(0).map(|s| s.length()).unwrap_or(0);
1640
1641        let state = LooperState {
1642            mode: LooperMode::Playing,
1643            speed,
1644            pan,
1645            level,
1646            parts,
1647            offset,
1648            has_undos: false,
1649            has_redos: false,
1650        };
1651
1652        if samples.is_empty() {
1653            gui_sender.send_update(GuiCommand::AddLooper(id, state));
1654        } else {
1655            gui_sender.send_update(GuiCommand::AddLooperWithSamples(
1656                id,
1657                length,
1658                Box::new(compute_waveform(&samples, WAVEFORM_DOWNSAMPLE)),
1659                state,
1660            ));
1661        }
1662
1663        let mode = Arc::new(Atomic::new(LooperMode::Playing));
1664        let length = Arc::new(Atomic::new(samples.get(0)
1665            .map(|s| s.length())
1666            .unwrap_or(0)));
1667
1668        let backend = LooperBackend {
1669            id,
1670            samples,
1671            mode: mode.clone(),
1672            length: length.clone(),
1673            speed,
1674            pan,
1675            level,
1676            parts,
1677            deleted: false,
1678            offset,
1679            enable_crossfading: true,
1680            out_time: FrameTime(0),
1681            in_time: FrameTime(0),
1682            // input buffer is used to record _before_ actual recording starts, and will be xfaded
1683            // with the end of the actual sample
1684            input_buffer: Sample::with_size(CROSS_FADE_SAMPLES),
1685            input_buffer_idx: 0,
1686            // xfade samples are recorded _after_ actual recording ends, and are xfaded immediately
1687            // with the beginning of the actual sample
1688            xfade_samples_left: 0,
1689            xfade_sample_idx: 0,
1690            in_queue: record_queue.clone(),
1691            out_queue: play_queue.clone(),
1692            gui_sender,
1693            channel: r,
1694            waveform_generator: WaveformGenerator::new(id),
1695            undo_queue: VecDeque::new(),
1696            redo_queue: VecDeque::new(),
1697            should_output: true,
1698            gui_needs_reset: false,
1699        };
1700
1701        Looper {
1702            id,
1703            backend: Some(backend),
1704            parts,
1705            pan,
1706            level,
1707            pan_law: PanLaw::Neg4_5,
1708            deleted: false,
1709            msg_counter: 0,
1710            in_queue: play_queue.clone(),
1711            out_queue: record_queue.clone(),
1712            channel: s,
1713            mode,
1714            length,
1715
1716            in_progress_output: None,
1717
1718            last_time: FrameTime(0),
1719            local_mode: None
1720        }
1721    }
1722
1723    pub fn from_serialized(
1724        state: &SavedLooper,
1725        path: &Path,
1726        gui_output: GuiSender,
1727    ) -> Result<Looper, SaveLoadError> {
1728        let mut samples = vec![];
1729        for sample_path in &state.samples {
1730            let mut reader = hound::WavReader::open(&path.join(sample_path))?;
1731
1732            let mut sample = Sample::new();
1733            let mut left = Vec::with_capacity(reader.len() as usize / 2);
1734            let mut right = Vec::with_capacity(reader.len() as usize / 2);
1735
1736            for (i, s) in reader.samples().enumerate() {
1737                if i % 2 == 0 {
1738                    left.push(s?);
1739                } else {
1740                    right.push(s?);
1741                }
1742            }
1743
1744            sample.record(&[&left, &right]);
1745            samples.push(sample);
1746        }
1747
1748        Ok(Self::new_with_samples(
1749            state.id,
1750            state.parts,
1751            state.speed,
1752            state.pan,
1753            state.level,
1754            FrameTime(state.offset_samples),
1755            samples,
1756            gui_output,
1757        ))
1758    }
1759
1760    pub fn channel(&self) -> Sender<ControlMessage> {
1761        self.channel.clone()
1762    }
1763
1764    pub fn start(mut self) -> Self {
1765        let mut backend: Option<LooperBackend> = None;
1766        std::mem::swap(&mut backend, &mut self.backend);
1767
1768        match backend {
1769            Some(backend) => backend.start(),
1770            _ => warn!("looper already started!"),
1771        }
1772
1773        self
1774    }
1775
1776    fn send_to_backend(&mut self, message: ControlMessage) -> bool {
1777        match self.channel.try_send(message) {
1778            Ok(_) => true,
1779            Err(TrySendError::Full(msg)) => {
1780                error!(
1781                    "Failed to process message {:?} in looper {}: channel is full",
1782                    msg, self.id
1783                );
1784                false
1785            }
1786            Err(TrySendError::Disconnected(_)) => {
1787                error!("Backend channel disconnected in looper {}", self.id);
1788                false
1789            }
1790        }
1791    }
1792
1793    pub fn local_mode(&self) -> LooperMode {
1794        return self.local_mode.unwrap_or(self.mode());
1795    }
1796
1797    pub fn mode(&self) -> LooperMode {
1798        self.mode.load(Ordering::Relaxed)
1799    }
1800
1801    pub fn length(&self) -> u64 {
1802        self.length.load(Ordering::Relaxed)
1803    }
1804
1805    pub fn set_time(&mut self, time: FrameTime) {
1806        loop {
1807            if self.in_queue.pop().is_none() {
1808                break;
1809            }
1810        }
1811        self.in_progress_output = None;
1812
1813        if self.mode() == LooperMode::Recording && time < FrameTime(0) {
1814            // we will clear our buffer
1815            self.send_to_backend(ControlMessage::Clear);
1816        }
1817
1818        self.send_to_backend(ControlMessage::SetTime(time));
1819    }
1820
1821    fn clear_queue(&mut self) {
1822        self.set_time(self.last_time)
1823    }
1824
1825    pub fn handle_command(&mut self, command: LooperCommand) {
1826        use LooperCommand::*;
1827        match command {
1828            Record => self.transition_to(LooperMode::Recording),
1829            Overdub => self.transition_to(LooperMode::Overdubbing),
1830            Play => self.transition_to(LooperMode::Playing),
1831            Mute => self.transition_to(LooperMode::Muted),
1832            Solo => self.transition_to(LooperMode::Soloed),
1833            Clear => {
1834                self.send_to_backend(ControlMessage::Clear);
1835                self.clear_queue();
1836            }
1837
1838            SetSpeed(speed) => {
1839                self.send_to_backend(ControlMessage::StopOutput);
1840                self.send_to_backend(ControlMessage::SetSpeed(speed));
1841                self.clear_queue();
1842            }
1843
1844            SetPan(pan) => {
1845                self.pan = pan;
1846                self.send_to_backend(ControlMessage::SetPan(pan));
1847            }
1848
1849            SetLevel(level) => {
1850                self.level = level;
1851                self.send_to_backend(ControlMessage::SetLevel(level));
1852            }
1853
1854            AddToPart(part) => {
1855                self.parts[part] = true;
1856                self.send_to_backend(ControlMessage::SetParts(self.parts));
1857            }
1858            RemoveFromPart(part) => {
1859                self.parts[part] = false;
1860                if self.parts.is_empty() {
1861                    // don't allow the user to clear all parts
1862                    self.parts[part] = true;
1863                } else {
1864                    self.send_to_backend(ControlMessage::SetParts(self.parts));
1865                }
1866            }
1867            Delete => {
1868                self.deleted = true;
1869                self.send_to_backend(ControlMessage::Deleted);
1870            }
1871            RecordOverdubPlay => {
1872                // TODO: this logic is duplicated in the gui, would be good to unify somehow
1873                if self.length() == 0 {
1874                    self.transition_to(LooperMode::Recording);
1875                } else if self.mode() == LooperMode::Recording || self.mode() == LooperMode::Playing {
1876                    self.transition_to(LooperMode::Overdubbing);
1877                } else {
1878                    self.transition_to(LooperMode::Playing);
1879                }
1880            }
1881            Undo => {
1882                self.send_to_backend(ControlMessage::StopOutput);
1883                self.send_to_backend(ControlMessage::Undo);
1884                self.clear_queue();
1885            }
1886            Redo => {
1887                self.send_to_backend(ControlMessage::StopOutput);
1888                self.send_to_backend(ControlMessage::Redo);
1889                self.clear_queue();
1890            }
1891        }
1892    }
1893
1894    fn output_for_t(&mut self, t: FrameTime) -> Option<(f64, f64)> {
1895        let mut cur = self
1896            .in_progress_output
1897            .or_else(|| self.in_queue.pop())?;
1898        self.in_progress_output = Some(cur);
1899
1900        loop {
1901            if cur.time.0 > t.0 {
1902                error!(
1903                    "data is in future for looper id {} (time is {}, needed {})",
1904                    self.id, cur.time.0, t.0
1905                );
1906                self.clear_queue();
1907                return None;
1908            }
1909
1910            if let Some(o) = cur.get_t(t) {
1911                return Some(o);
1912            }
1913
1914            if let Some(buf) = self.in_queue.pop() {
1915                cur = buf;
1916                self.in_progress_output = Some(buf);
1917            } else {
1918                self.in_progress_output = None;
1919                return None;
1920            }
1921        }
1922    }
1923
1924    fn should_output(&self, part: Part, solo: bool) -> bool {
1925        if !self.parts[part] {
1926            return false
1927        }
1928
1929        if solo && self.mode() != LooperMode::Soloed {
1930            return false
1931        }
1932
1933        return self.mode() == LooperMode::Playing ||
1934            self.mode() == LooperMode::Overdubbing ||
1935            self.mode() == LooperMode::Soloed
1936    }
1937
1938    // In process_output, we modify the specified output buffers according to our internal state. In
1939    // Playing or Overdub mode, we will add our buffer to the output. Otherwise, we do nothing.
1940    //
1941    // If the solo flag is set, we will only output if we are in solo mode.
1942    pub fn process_output(
1943        &mut self,
1944        time: FrameTime,
1945        outputs: &mut [&mut [f64]],
1946        part: Part,
1947        solo: bool,
1948    ) {
1949        if time.0 < 0 || self.length() == 0 {
1950            return;
1951        }
1952
1953        debug!("reading time {}", time.0);
1954
1955        let mut time = time;
1956        let mut out_idx = 0;
1957
1958        let mut missing = 0;
1959        let mut waiting = 1_000;
1960        let backoff = crossbeam_utils::Backoff::new();
1961
1962        // this only really needs to be updated when the pan changes, so we don't need to do this
1963        // for every buffer
1964        let pan_l = self.pan_law.left(self.pan);
1965        let pan_r = self.pan_law.right(self.pan);
1966
1967        while out_idx < outputs[0].len() {
1968            if let Some((l, r)) = self.output_for_t(time) {
1969                if self.should_output(part, solo) {
1970                    outputs[0][out_idx] += l * pan_l as f64 * self.level as f64;
1971                    outputs[1][out_idx] += r * pan_r as f64 * self.level as f64;
1972                }
1973            } else if waiting > 0 && self.mode() != LooperMode::Recording {
1974                backoff.spin();
1975                waiting -= 1;
1976                continue;
1977            } else {
1978                missing += 1;
1979            }
1980            out_idx += 1;
1981            time.0 += 1;
1982        }
1983
1984        self.last_time = time;
1985
1986        if self.mode() != LooperMode::Recording && missing > 0 {
1987            error!(
1988                "needed output but queue was empty in looper {} at {} (missed {} samples)",
1989                self.id, time.0, missing
1990            );
1991        }
1992
1993        match self.channel.try_send(ControlMessage::ReadOutput(time)) {
1994            Err(TrySendError::Disconnected(_)) => panic!("channel closed"),
1995            Err(TrySendError::Full(_)) => warn!("channel full while requesting more output"),
1996            _ => {}
1997        }
1998
1999        self.local_mode = None;
2000    }
2001
2002    // In process_input, we modify our internal buffers based on the input. In Record mode, we
2003    // append the data in the input buffers to our current sample. In Overdub mode, we sum the data
2004    // with whatever is currently in our buffer at the point of time_in_samples.
2005    pub fn process_input(&mut self, time_in_samples: u64, inputs: &[&[f32]], part: Part) {
2006        assert_eq!(2, inputs.len());
2007
2008        debug!("inputting time {}", time_in_samples);
2009
2010        let msg_id = self.msg_counter;
2011        self.msg_counter += 1;
2012
2013        let mut buf = TransferBuf {
2014            id: msg_id,
2015            time: FrameTime(0 as i64),
2016            size: 0,
2017            data: [[0f32; TRANSFER_BUF_SIZE]; 2],
2018        };
2019
2020        let mut time = time_in_samples;
2021        for (l, r) in inputs[0]
2022            .chunks(TRANSFER_BUF_SIZE)
2023            .zip(inputs[1].chunks(TRANSFER_BUF_SIZE))
2024        {
2025            buf.time = FrameTime(time as i64);
2026            buf.size = l.len();
2027
2028            if self.parts[part] {
2029                // if this is not the current part, send 0s
2030                for i in 0..l.len() {
2031                    buf.data[0][i] = l[i];
2032                    buf.data[1][i] = r[i];
2033                }
2034            }
2035
2036            if let Err(_) = self.out_queue.push(buf) {
2037                // TODO: handle error case where our queue is full
2038                error!("queue is full on looper {}", self.id);
2039            }
2040
2041            time += l.len() as u64;
2042        }
2043
2044        self.send_to_backend(ControlMessage::InputDataReady {
2045            id: msg_id,
2046            size: inputs[0].len(),
2047        });
2048    }
2049
2050    pub fn transition_to(&mut self, mode: LooperMode) {
2051        let mut mode = mode;
2052        if self.length() == 0 && mode == LooperMode::Overdubbing {
2053            warn!("trying to move to overdub with 0-length looper");
2054            mode = LooperMode::Recording;
2055        }
2056
2057        self.send_to_backend(ControlMessage::TransitionTo(mode));
2058        self.local_mode = Some(mode);
2059    }
2060}
2061
2062impl Drop for Looper {
2063    fn drop(&mut self) {
2064        if let Err(_) = self.channel.send(ControlMessage::Shutdown) {
2065            warn!("failed to shutdown backend because queue was full");
2066        }
2067    }
2068}