use rivet_app::{AudioEngine, Shared}; use rivet_core::{Note, Phrase, BAR, PPQ}; fn clip(pitch: u8, length: u32) -> Phrase { Phrase { length, notes: vec![Note { start: 0, duration: length, pitch, velocity: 90, ..Default::default() }], } } #[test] fn looping_and_mode_changes_release_and_retrigger_notes() { let shared = Shared::default(); let mut a = AudioEngine::default(); a.player.set_sample_rate(8000.).unwrap(); shared.preview(&clip(60, PPQ)).unwrap(); a.begin_block(&shared); let first = a.frame(120., true); assert_eq!(first.on, Some((60, 90))); assert_eq!(first.off, None); let mut repeated = false; for _ in 0..4001 { let frame = a.frame(120., true); if frame.off.is_some() { assert_eq!(frame.off, Some(60)); assert_eq!(frame.on, Some((60, 90))); repeated = true; break; } } assert!(repeated); let muted = a.frame(120., false); assert_eq!(muted.off, Some(60)); assert_eq!(muted.on, None); assert_eq!(a.frame(120., true).on, Some((60, 90))); shared.stop(); a.begin_block(&shared); let stopped = a.frame(120., true); assert_eq!(stopped.off, Some(60)); assert_eq!(stopped.on, None); } #[test] fn adjacent_same_pitch_notes_have_separate_sample_accurate_attacks() { let shared = Shared::default(); shared .looping .store(false, std::sync::atomic::Ordering::Release); let mut a = AudioEngine::default(); a.player.set_sample_rate(8000.).unwrap(); let p = Phrase { length: PPQ, notes: vec![ Note { start: 0, duration: PPQ / 2, pitch: 60, velocity: 90, ..Default::default() }, Note { start: PPQ / 2, duration: PPQ / 2, pitch: 60, velocity: 70, ..Default::default() }, ], }; shared.preview(&p).unwrap(); a.begin_block(&shared); let mut events = Vec::new(); for frame in 0i32..4003 { let e = a.frame(120., true); if e.off.is_some() || e.on.is_some() { events.push((frame, e.off, e.on)); } } assert_eq!(events.len(), 3); assert_eq!(events[0], (0, None, Some((60, 90)))); assert!((events[1].0 - 2000).abs() <= 1); assert_eq!(events[1].1, Some(60)); assert_eq!(events[1].2, Some((60, 70))); assert!((events[2].0 - 4000).abs() <= 1); assert_eq!(events[2].1, Some(60)); assert_eq!(events[2].2, None); } #[test] fn queued_audition_switches_at_the_next_bar_line_and_stop_cancels_it() { let shared = Shared::default(); let mut a = AudioEngine::default(); a.player.set_sample_rate(8000.).unwrap(); shared.preview(&clip(60, 4 * BAR)).unwrap(); a.begin_block(&shared); for _ in 0..100 { a.frame(120., true); } a.end_block(&shared); shared.audition(&clip(67, 4 * BAR)).unwrap(); a.begin_block(&shared); let mut switched = None; for index in 100i32..16003 { let f = a.frame(120., true); if f.on == Some((67, 90)) { assert_eq!(f.off, Some(60)); switched = Some(index); break; } } assert!((switched.unwrap() - 16000).abs() <= 1); a.end_block(&shared); shared.audition(&clip(72, 2 * BAR)).unwrap(); a.begin_block(&shared); shared.stop(); a.begin_block(&shared); let f = a.frame(120., true); assert_eq!(f.off, Some(67)); assert_eq!(f.on, None); assert!(!a.player.is_playing()); }