#![forbid(unsafe_code)]
use std::time::Instant;
use oplon::Opl2;
fn main() {
let rate: u32 = std::env::args()
.nth(1)
.and_then(|s| s.parse().ok())
.unwrap_or(48_000);
let mut opl = Opl2::new(rate);
opl.set_opl3_enabled(true);
opl.write_reg_high(0x04, 0x01 | 0x08);
for bank in 0..2u8 {
for ch in 0u8..9 {
let grp = ch / 3;
let idx = ch % 3;
let mod_off = grp * 8 + idx;
let car_off = grp * 8 + 3 + idx;
for (n, off) in [mod_off, car_off].into_iter().enumerate() {
let mul = 1 + ((ch + n as u8) & 0x0F);
let w = |opl: &mut Opl2, r: u8, v: u8| {
if bank == 0 { opl.write_reg(r, v) } else { opl.write_reg_high(r, v) }
};
w(&mut opl, 0x20 + off, 0xE0 | mul); w(&mut opl, 0x40 + off, 0x80 | 0x10); w(&mut opl, 0x60 + off, 0xF4); w(&mut opl, 0x80 + off, 0x2F); w(&mut opl, 0xE0 + off, (ch + n as u8) & 0x07); }
let w = |opl: &mut Opl2, r: u8, v: u8| {
if bank == 0 { opl.write_reg(r, v) } else { opl.write_reg_high(r, v) }
};
w(&mut opl, 0xC0 + ch, 0x30 | 0x0E); w(&mut opl, 0xA0 + ch, 0x80 + ch);
w(&mut opl, 0xB0 + ch, 0x20 | ((3 + (ch & 3)) << 2) | 0x01); }
}
for _ in 0..rate {
let _ = opl.render_frame();
}
let seconds = 60u32;
let frames = (rate * seconds) as u64;
let t0 = Instant::now();
let mut acc = 0i64;
for _ in 0..frames {
let (l, r) = opl.render_frame();
acc = acc.wrapping_add(l as i64).wrapping_add(r as i64);
}
let dt = t0.elapsed().as_secs_f64();
let fps = frames as f64 / dt;
println!("rendered {frames} frames in {dt:.3} s");
println!(" {:.2} M frames/s", fps / 1e6);
println!(" {:.1}× real time (at {rate} Hz)", fps / rate as f64);
println!(" {:.2} ns/frame", dt * 1e9 / frames as f64);
println!(" (checksum {acc})");
}