Files
bass-foundry/plugins/rivet/app/tests/midi.rs
T
nvrl 15853e61ac
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
restructure
2026-11-05 23:58:00 +01:00

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());
}