Check and Windows preview / check (patina) (push) Successful in 2m20s
Check and Windows preview / check (rivet) (push) Successful in 1m38s
Check and Windows preview / previews (push) Successful in 1m6s
Check and Windows preview / windows (push) Successful in 1m50s
Independent plugin release / publish (push) Successful in 8s
Independent plugin release / plan (push) Successful in 7s
Independent plugin release / build (push) Successful in 2m21s
125 lines
3.7 KiB
Rust
125 lines
3.7 KiB
Rust
use rivet_app::{AudioEngine, Shared};
|
|
use rivet_core::{Note, Phrase, PPQ, SECTION};
|
|
|
|
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_section_boundary_and_stop_cancels_it() {
|
|
let shared = Shared::default();
|
|
let mut a = AudioEngine::default();
|
|
a.player.set_sample_rate(8000.).unwrap();
|
|
shared.preview(&clip(60, 2 * SECTION)).unwrap();
|
|
a.begin_block(&shared);
|
|
for _ in 0..100 {
|
|
a.frame(120., true);
|
|
}
|
|
a.end_block(&shared);
|
|
shared.audition(&clip(67, 2 * SECTION)).unwrap();
|
|
a.begin_block(&shared);
|
|
let mut switched = None;
|
|
for index in 100i32..32003 {
|
|
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() - 32000).abs() <= 1);
|
|
a.end_block(&shared);
|
|
shared.audition(&clip(72, SECTION)).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());
|
|
}
|