should restore from save state... doesn't, but should

This commit is contained in:
Alex Janka 2023-03-15 14:05:19 +11:00
parent 5aa308f695
commit b5fa2e6690
2 changed files with 89 additions and 18 deletions

View file

@ -5,6 +5,7 @@ use gb_emu_lib::{
EmulatorCore, EmulatorCore,
}; };
use nih_plug::prelude::*; use nih_plug::prelude::*;
use nih_plug::{midi::MidiResult::Basic, params::persist::PersistentField};
use std::sync::{ use std::sync::{
mpsc::{channel, Receiver, Sender}, mpsc::{channel, Receiver, Sender},
Arc, Mutex, Arc, Mutex,
@ -13,8 +14,29 @@ use ui::{Emulator, EmulatorRenderer};
mod ui; mod ui;
#[derive(Default)]
struct SaveStateParam {
state: Arc<Mutex<Option<CpuSaveState<[u8; 4]>>>>,
}
impl PersistentField<'_, Option<CpuSaveState<[u8; 4]>>> for SaveStateParam {
fn set(&self, new_value: Option<CpuSaveState<[u8; 4]>>) {
*self.state.lock().unwrap() = new_value;
}
fn map<F, R>(&self, f: F) -> R
where
F: Fn(&Option<CpuSaveState<[u8; 4]>>) -> R,
{
f(&self.state.lock().unwrap())
}
}
#[derive(Params, Default)] #[derive(Params, Default)]
struct EmuParams {} struct EmuParams {
#[persist = "save_state"]
last_save_state: SaveStateParam,
}
struct EmuVars { struct EmuVars {
rx: AsyncHeapConsumer<[f32; 2]>, rx: AsyncHeapConsumer<[f32; 2]>,
@ -27,7 +49,7 @@ pub struct GameboyEmu {
vars: Option<EmuVars>, vars: Option<EmuVars>,
frame_receiver: Arc<FrameReceiver>, frame_receiver: Arc<FrameReceiver>,
key_handler: Arc<JoypadSender>, key_handler: Arc<JoypadSender>,
last_save_state: Option<CpuSaveState<[u8; 4]>>, params: Arc<EmuParams>,
} }
type FrameReceiver = Mutex<Option<Receiver<Vec<[u8; 4]>>>>; type FrameReceiver = Mutex<Option<Receiver<Vec<[u8; 4]>>>>;
@ -72,15 +94,18 @@ impl Plugin for GameboyEmu {
type BackgroundTask = (); type BackgroundTask = ();
fn params(&self) -> Arc<dyn Params> { fn params(&self) -> Arc<dyn Params> {
Arc::new(EmuParams::default()) self.params.clone()
} }
fn process( fn process(
&mut self, &mut self,
buffer: &mut Buffer, buffer: &mut Buffer,
_: &mut AuxiliaryBuffers, _: &mut AuxiliaryBuffers,
_: &mut impl ProcessContext<Self>, _c: &mut impl ProcessContext<Self>,
) -> ProcessStatus { ) -> ProcessStatus {
while let Some(event) = _c.next_event() {
if let Some(Basic(_midi)) = event.as_midi() {}
}
if let Some(ref mut vars) = self.vars { if let Some(ref mut vars) = self.vars {
if buffer.channels() != 2 { if buffer.channels() != 2 {
panic!() panic!()
@ -97,6 +122,7 @@ impl Plugin for GameboyEmu {
} }
vars.emulator_core.run_until_buffer_full(); vars.emulator_core.run_until_buffer_full();
} }
self.update_save_state();
ProcessStatus::KeepAlive ProcessStatus::KeepAlive
} }
@ -148,17 +174,13 @@ impl Plugin for GameboyEmu {
let window = Box::new(renderer); let window = Box::new(renderer);
let mut emulator_core = if let Some(state) = self.last_save_state.take() { let mut emulator_core =
if let Some(state) = self.params.last_save_state.state.lock().unwrap().take() {
EmulatorCore::from_save_state(state, rom, receiver, window, output) EmulatorCore::from_save_state(state, rom, receiver, window, output)
} else { } else {
let options = gb_emu_lib::Options { let options = gb_emu_lib::Options::new(rom)
rom, .with_bootrom(bootrom)
save_path: None, .force_no_save();
no_save: true,
bootrom,
connect_serial: false,
verbose: false,
};
EmulatorCore::init(receiver, options, window, output, None) EmulatorCore::init(receiver, options, window, output, None)
}; };
@ -169,6 +191,7 @@ impl Plugin for GameboyEmu {
sender, sender,
emulator_core, emulator_core,
}); });
self.update_save_state();
} }
true true
@ -176,8 +199,8 @@ impl Plugin for GameboyEmu {
fn deactivate(&mut self) { fn deactivate(&mut self) {
nih_log!("deactivating"); nih_log!("deactivating");
self.update_save_state();
if let Some(ref mut vars) = self.vars { if let Some(ref mut vars) = self.vars {
self.last_save_state = Some(vars.emulator_core.get_save_state());
match vars.sender.send(EmulatorMessage::Stop) { match vars.sender.send(EmulatorMessage::Stop) {
Ok(_) => self.vars = None, Ok(_) => self.vars = None,
Err(e) => nih_log!("error {e} sending message to emulator"), Err(e) => nih_log!("error {e} sending message to emulator"),
@ -186,6 +209,15 @@ impl Plugin for GameboyEmu {
} }
} }
impl GameboyEmu {
fn update_save_state(&mut self) {
if let Some(ref mut vars) = self.vars {
*self.params.last_save_state.state.lock().unwrap() =
Some(vars.emulator_core.get_save_state());
}
}
}
impl Vst3Plugin for GameboyEmu { impl Vst3Plugin for GameboyEmu {
const VST3_CLASS_ID: [u8; 16] = *b"alexjankagbemula"; const VST3_CLASS_ID: [u8; 16] = *b"alexjankagbemula";

View file

@ -22,6 +22,7 @@ mod constants;
mod processor; mod processor;
pub mod util; pub mod util;
#[non_exhaustive]
pub struct Options { pub struct Options {
pub rom: RomFile, pub rom: RomFile,
pub save_path: Option<String>, pub save_path: Option<String>,
@ -31,6 +32,44 @@ pub struct Options {
pub verbose: bool, pub verbose: bool,
} }
impl Options {
pub fn new(rom: RomFile) -> Self {
Self {
rom,
save_path: None,
no_save: false,
bootrom: None,
connect_serial: false,
verbose: false,
}
}
pub fn with_save_path(mut self, path: String) -> Self {
self.save_path = Some(path);
self
}
pub fn force_no_save(mut self) -> Self {
self.no_save = true;
self
}
pub fn with_bootrom(mut self, bootrom: Option<RomFile>) -> Self {
self.bootrom = bootrom;
self
}
pub fn with_serial(mut self) -> Self {
self.connect_serial = true;
self
}
pub fn with_verbose(mut self) -> Self {
self.verbose = true;
self
}
}
static mut PAUSE_ENABLED: bool = false; static mut PAUSE_ENABLED: bool = false;
static mut PAUSE_QUEUED: bool = false; static mut PAUSE_QUEUED: bool = false;