#![forbid(unsafe_code)]
use oplon::{ChannelPatch, OpPatch, Opl2};
#[test]
fn register_level_tone_and_release() {
let mut opl = Opl2::new(44_100);
for (r, v) in [
(0x20u8, 0x21u8), (0x23, 0x21), (0x40, 0x3F), (0x43, 0x00), (0x60, 0xF0), (0x63, 0xF0),
(0x80, 0x0F), (0x83, 0x0F),
(0xC0, 0x00),
(0xA0, 0x98),
(0xB0, 0x31), ] {
opl.write_reg(r, v);
}
let mut peak = 0i32;
for _ in 0..8820 {
let (l, _r) = opl.render_frame();
peak = peak.max(l.abs());
}
assert!(peak > 100, "silent tone (peak={peak})");
assert!(opl.any_active());
opl.write_reg(0xB0, 0x11);
for _ in 0..88_200 {
opl.render_frame();
if !opl.any_active() {
break;
}
}
assert!(!opl.any_active(), "did not release to silence");
}
#[test]
fn structured_patch_api() {
let mut opl = Opl2::new(48_000);
let patch = ChannelPatch {
modulator: OpPatch {
mul: 1,
tl: 63,
attack: 15,
release: 7,
sustaining: true,
..Default::default()
},
carrier: OpPatch {
mul: 1,
attack: 15,
release: 7,
sustaining: true,
..Default::default()
},
..Default::default()
};
opl.set_patch(0, &patch);
opl.set_frequency(0, 0x2AE, 4);
opl.key_on(0);
let mut peak = 0i32;
for _ in 0..4800 {
let (l, _r) = opl.render_frame();
peak = peak.max(l.abs());
}
assert!(peak > 100, "structured-patch tone silent (peak={peak})");
assert_eq!(opl.channel_count(), oplon::OPL2_CHANNELS);
}
#[test]
fn stereo_panning_routes_per_side() {
let mut opl = Opl2::new(44_100);
for (r, v) in [(0x43u8, 0x00u8), (0x63, 0xF0), (0xA0, 0x98), (0xB0, 0x31)] {
opl.write_reg(r, v);
}
opl.set_pan(0, true, false);
let (mut lpk, mut rpk) = (0i32, 0i32);
for _ in 0..8820 {
let (l, r) = opl.render_frame();
lpk = lpk.max(l.abs());
rpk = rpk.max(r.abs());
}
assert!(lpk > 100, "left silent (peak={lpk})");
assert_eq!(rpk, 0, "right should be muted, got {rpk}");
}
#[test]
fn random_register_writes_never_panic() {
let mut s: u32 = 0xDEAD_BEEF;
let mut rng = || {
s = s.wrapping_mul(1664525).wrapping_add(1013904223);
s
};
for &rate in &[8_000u32, 44_100, 48_000, 192_000] {
let mut opl = Opl2::new(rate);
for i in 0..20_000u32 {
let r = rng();
let (reg, val) = ((r & 0xFF) as u8, ((r >> 8) & 0xFF) as u8);
if (r >> 16) & 1 == 0 {
opl.write_reg(reg, val);
} else {
opl.write_reg_high(reg, val);
}
if i % 3 == 0 {
let _ = opl.render_frame();
}
}
}
}