Skip to content

Commit

Permalink
NES: added the ability to pause and resume emulation
Browse files Browse the repository at this point in the history
  • Loading branch information
Amjad50 committed Aug 20, 2020
1 parent 90eb1d4 commit 6b95da5
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 12 deletions.
27 changes: 19 additions & 8 deletions apu2a03/src/apu2a03.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ pub struct APU2A03 {

filter: Filter,
filter_counter: u8,

player: rodio::Sink,
}

impl APU2A03 {
Expand All @@ -54,6 +56,16 @@ impl APU2A03 {
let noise = Rc::new(RefCell::new(LengthCountedChannel::new(NoiseWave::new())));
let dmc = Rc::new(RefCell::new(Dmc::new()));

let buffered_channel = Arc::new(Mutex::new(BufferedChannel::new()));

let device = rodio::default_output_device().unwrap();
let sink = rodio::Sink::new(&device);

sink.append(APUChannelPlayer::from_clone(buffered_channel.clone()));
sink.set_volume(0.15);

sink.pause();

Self {
square_pulse_1: square_pulse_1.clone(),
square_pulse_2: square_pulse_2.clone(),
Expand All @@ -64,7 +76,7 @@ impl APU2A03 {

dmc: dmc.clone(),

buffered_channel: Arc::new(Mutex::new(BufferedChannel::new())),
buffered_channel,

mixer: Mixer::new(
square_pulse_1.clone(),
Expand All @@ -91,6 +103,8 @@ impl APU2A03 {

filter: Filter::new(),
filter_counter: 0,

player: sink,
}
}

Expand Down Expand Up @@ -416,14 +430,11 @@ impl APU2A03 {
}

pub fn play(&self) {
let device = rodio::default_output_device().unwrap();
let sink = rodio::Sink::new(&device);

sink.append(APUChannelPlayer::from_clone(self.buffered_channel.clone()));
sink.set_volume(0.15);
self.player.play()
}

sink.play();
sink.detach();
pub fn pause(&self) {
self.player.pause();
}

fn length_counter_decrement<S: APUChannel>(channel: &mut Rc<RefCell<LengthCountedChannel<S>>>) {
Expand Down
2 changes: 2 additions & 0 deletions nes_ui_base/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use std::sync::{mpsc::Sender, Arc, Mutex};
pub enum UiEvent {
Exit,
Reset,
Pause,
Resume,
LoadRom(String),
}

Expand Down
8 changes: 8 additions & 0 deletions nes_ui_base/src/nes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,14 @@ impl<P: UiProvider + Send + 'static> NES<P> {
break;
}
}
UiEvent::Pause => {
self.paused = true;
self.apu.borrow_mut().pause();
}
UiEvent::Resume => {
self.paused = false;
self.apu.borrow_mut().play();
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions nes_ui_gtk/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ fn main() {
let args = args().collect::<Vec<String>>();

let mut nes = if args.len() >= 2 {
NES::new(&args[1], GtkProvider {}).expect("")
NES::new(&args[1], GtkProvider::new()).unwrap()
} else {
NES::new_without_file(GtkProvider {})
NES::new_without_file(GtkProvider::new())
};

nes.run();
Expand Down
42 changes: 40 additions & 2 deletions nes_ui_gtk/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use nes_ui_base::{
nes_display::Color as NESColor,
UiEvent, UiProvider,
};
use std::sync::{mpsc::Sender, Arc, Mutex};
use std::sync::{atomic::AtomicBool, atomic::Ordering, mpsc::Sender, Arc, Mutex};

use gdk::enums::key;
use gdk::{keyval_to_upper, DragAction, ModifierType};
Expand All @@ -15,7 +15,17 @@ use gtk::{
FileFilter, Inhibit, MenuItem, ResponseType, TargetEntry, TargetFlags, Window,
};

pub struct GtkProvider {}
pub struct GtkProvider {
paused: Arc<AtomicBool>,
}

impl GtkProvider {
pub fn new() -> Self {
Self {
paused: Arc::new(AtomicBool::new(false)),
}
}
}

impl UiProvider for GtkProvider {
fn get_tv_color_converter() -> fn(&NESColor) -> [u8; 4] {
Expand All @@ -42,6 +52,10 @@ impl UiProvider for GtkProvider {
let menu_action_open = builder.get_object::<MenuItem>("menu_action_open").unwrap();
let menu_action_quit = builder.get_object::<MenuItem>("menu_action_quit").unwrap();
let menu_action_reset = builder.get_object::<MenuItem>("menu_action_reset").unwrap();
let menu_action_pause = builder.get_object::<MenuItem>("menu_action_pause").unwrap();
let menu_action_resume = builder
.get_object::<MenuItem>("menu_action_resume")
.unwrap();

window.show_all();

Expand Down Expand Up @@ -90,6 +104,7 @@ impl UiProvider for GtkProvider {

let ctrl_state_clone = ctrl_state.clone();
let ui_to_nes_sender_clone = ui_to_nes_sender.clone();
let paused_clone = self.paused.clone();
window.connect_key_press_event(move |_, event| {
let mut ctrl = ctrl_state_clone.lock().unwrap();

Expand All @@ -105,6 +120,15 @@ impl UiProvider for GtkProvider {
key::R if event.get_state().intersects(ModifierType::CONTROL_MASK) => {
ui_to_nes_sender_clone.send(UiEvent::Reset).unwrap()
}
key::Escape => {
if paused_clone.load(Ordering::Relaxed) {
ui_to_nes_sender_clone.send(UiEvent::Resume).unwrap();
paused_clone.store(false, Ordering::Relaxed);
} else {
ui_to_nes_sender_clone.send(UiEvent::Pause).unwrap();
paused_clone.store(true, Ordering::Relaxed);
}
}
_ => {}
}

Expand Down Expand Up @@ -162,6 +186,20 @@ impl UiProvider for GtkProvider {
ui_to_nes_sender_clone.send(UiEvent::Reset).unwrap();
});

let ui_to_nes_sender_clone = ui_to_nes_sender.clone();
let paused_clone = self.paused.clone();
menu_action_pause.connect_activate(move |_| {
ui_to_nes_sender_clone.send(UiEvent::Pause).unwrap();
paused_clone.store(true, Ordering::Relaxed);
});

let ui_to_nes_sender_clone = ui_to_nes_sender.clone();
let paused_clone = self.paused.clone();
menu_action_resume.connect_activate(move |_| {
ui_to_nes_sender_clone.send(UiEvent::Resume).unwrap();
paused_clone.store(false, Ordering::Relaxed);
});

let app_clone = app.clone();
menu_action_quit.connect_activate(move |_| app_clone.quit());

Expand Down
16 changes: 16 additions & 0 deletions nes_ui_gtk/ui.glade
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,22 @@
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="menu_action_pause">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Pause</property>
<property name="use_underline">True</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="menu_action_resume">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Resume</property>
<property name="use_underline">True</property>
</object>
</child>
</object>
</child>
</object>
Expand Down

0 comments on commit 6b95da5

Please sign in to comment.