mirror of
https://github.com/transistorfet/moa.git
synced 2024-05-28 13:41:30 +00:00
4cb423d85a
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
117 lines
3.3 KiB
Rust
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)
|
|
});
|
|
}
|
|
|
|
|