moa/emulator/frontends/minifb/src/bin/moa-synth.rs
transistor 4cb423d85a Fixed minifb frame updater to allow slower framerates
If the sim is running slower than 60Hz, it was using the frame limiter
to not apply because no frame was drawn, and so it would end up running
at full speed.  Minifb can save the last frame without cloning it, and
redraw the same frame if no new frame is ready, which allows the limiter
to still delay the next frame, so slower speeds work.  This was also
preventing things that didn't update the screen from allowing inputs
including escape to have any effect
2022-10-02 13:07:15 -07:00

117 lines
3.3 KiB
Rust

use std::sync::mpsc;
use moa_minifb;
use moa_peripherals_yamaha::{Ym2612, Sn76489};
use moa_core::host::gfx::{Frame, FrameQueue};
use moa_core::host::{Host, WindowUpdater, KeyboardUpdater, Key};
use moa_core::{System, Error, ClockElapsed, Address, Addressable, Steppable, Transmutable, TransmutableBox, wrap_transmutable};
pub struct SynthControlsUpdater(mpsc::Sender<(Key, bool)>);
impl KeyboardUpdater for SynthControlsUpdater {
fn update_keyboard(&mut self, key: Key, state: bool) {
self.0.send((key, state)).unwrap();
}
}
struct SynthControl {
queue: FrameQueue,
receiver: mpsc::Receiver<(Key, bool)>,
}
impl SynthControl {
pub fn new(queue: FrameQueue, receiver: mpsc::Receiver<(Key, bool)>) -> Self {
Self {
queue,
receiver,
}
}
}
impl Steppable for SynthControl {
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
if let Ok((key, state)) = self.receiver.try_recv() {
match key {
Key::Enter => {
system.get_bus().write_u8(0x00, 0x28)?;
system.get_bus().write_u8(0x01, if state { 0xF0 } else { 0x00 })?;
},
Key::A => {
system.get_bus().write_u8(0x10, 0x84)?;
system.get_bus().write_u8(0x10, 0x0F)?;
system.get_bus().write_u8(0x10, if state { 0x90 } else { 0x9F })?;
},
_ => { },
}
}
let size = self.queue.max_size();
let frame = Frame::new(size.0, size.1);
self.queue.add(system.clock, frame);
Ok(33_000_000)
}
}
impl Transmutable for SynthControl {
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
Some(self)
}
}
fn set_register(device: &mut dyn Addressable, bank: u8, reg: u8, data: u8) -> Result<(), Error> {
let addr = (bank as Address) * 2;
device.write_u8(addr, reg)?;
device.write_u8(addr + 1, data)?;
Ok(())
}
fn initialize_ym(ym_sound: TransmutableBox) -> Result<(), Error> {
let mut borrow = ym_sound.borrow_mut();
let device = borrow.as_addressable().unwrap();
set_register(device, 0, 0x30, 0x71)?;
set_register(device, 0, 0x34, 0x0D)?;
set_register(device, 0, 0x38, 0x33)?;
set_register(device, 0, 0x3C, 0x00)?;
set_register(device, 0, 0xA4, 0x22)?;
set_register(device, 0, 0xA0, 0x69)?;
set_register(device, 0, 0xB0, 0x30)?;
Ok(())
}
fn main() {
let matches = moa_minifb::new("YM2612 Tester/Synth")
.get_matches();
moa_minifb::run(matches, |host| {
let mut system = System::new();
let queue = FrameQueue::new(384, 128);
let (sender, receiver) = mpsc::channel();
let control = wrap_transmutable(SynthControl::new(queue.clone(), receiver));
system.add_device("control", control)?;
let ym_sound = wrap_transmutable(Ym2612::create(host)?);
initialize_ym(ym_sound.clone())?;
system.add_addressable_device(0x00, ym_sound)?;
let sn_sound = wrap_transmutable(Sn76489::create(host)?);
system.add_addressable_device(0x10, sn_sound)?;
host.add_window(Box::new(queue.clone()))?;
host.register_keyboard(Box::new(SynthControlsUpdater(sender)))?;
Ok(system)
});
}