Implement multiplayer #2

Merged
SonicSwordcane merged 21 commits from multiplayer into main 2024-11-30 00:31:10 +00:00
3 changed files with 49 additions and 7 deletions
Showing only changes of commit 4b34d138ac - Show all commits

View File

@ -238,6 +238,18 @@ impl GameWindow {
} }
} }
}); });
ui.menu("Audio", || {
let p1_enabled = self.client.is_audio_enabled(SimId::Player1);
let p2_enabled = self.client.is_audio_enabled(SimId::Player2);
if ui.menu_item_config("Player 1").selected(p1_enabled).build() {
self.client
.send_command(EmulatorCommand::SetAudioEnabled(!p1_enabled, p2_enabled));
}
if ui.menu_item_config("Player 2").selected(p2_enabled).build() {
self.client
.send_command(EmulatorCommand::SetAudioEnabled(p1_enabled, !p2_enabled));
}
});
ui.menu("Input", || { ui.menu("Input", || {
if ui.menu_item("Bind Inputs") { if ui.menu_item("Bind Inputs") {
self.proxy.send_event(UserEvent::OpenInputWindow).unwrap(); self.proxy.send_event(UserEvent::OpenInputWindow).unwrap();

View File

@ -12,8 +12,8 @@ use std::{
use anyhow::Result; use anyhow::Result;
use crate::{audio::Audio, graphics::TextureSink}; use crate::{audio::Audio, graphics::TextureSink};
use shrooms_vb_core::Sim;
pub use shrooms_vb_core::VBKey; pub use shrooms_vb_core::VBKey;
use shrooms_vb_core::{Sim, EXPECTED_FRAME_SIZE};
mod shrooms_vb_core; mod shrooms_vb_core;
@ -23,6 +23,7 @@ pub struct EmulatorBuilder {
sim_count: Arc<AtomicUsize>, sim_count: Arc<AtomicUsize>,
running: Arc<[AtomicBool; 2]>, running: Arc<[AtomicBool; 2]>,
has_game: Arc<[AtomicBool; 2]>, has_game: Arc<[AtomicBool; 2]>,
audio_on: Arc<[AtomicBool; 2]>,
linked: Arc<AtomicBool>, linked: Arc<AtomicBool>,
} }
@ -52,6 +53,7 @@ impl EmulatorBuilder {
sim_count: Arc::new(AtomicUsize::new(0)), sim_count: Arc::new(AtomicUsize::new(0)),
running: Arc::new([AtomicBool::new(false), AtomicBool::new(false)]), running: Arc::new([AtomicBool::new(false), AtomicBool::new(false)]),
has_game: Arc::new([AtomicBool::new(false), AtomicBool::new(false)]), has_game: Arc::new([AtomicBool::new(false), AtomicBool::new(false)]),
audio_on: Arc::new([AtomicBool::new(true), AtomicBool::new(true)]),
linked: Arc::new(AtomicBool::new(false)), linked: Arc::new(AtomicBool::new(false)),
}; };
let client = EmulatorClient { let client = EmulatorClient {
@ -59,6 +61,7 @@ impl EmulatorBuilder {
sim_count: builder.sim_count.clone(), sim_count: builder.sim_count.clone(),
running: builder.running.clone(), running: builder.running.clone(),
has_game: builder.has_game.clone(), has_game: builder.has_game.clone(),
audio_on: builder.audio_on.clone(),
linked: builder.linked.clone(), linked: builder.linked.clone(),
}; };
(builder, client) (builder, client)
@ -77,6 +80,7 @@ impl EmulatorBuilder {
self.sim_count, self.sim_count,
self.running, self.running,
self.has_game, self.has_game,
self.audio_on,
self.linked, self.linked,
)?; )?;
if let Some(path) = self.rom { if let Some(path) = self.rom {
@ -93,6 +97,7 @@ pub struct Emulator {
sim_count: Arc<AtomicUsize>, sim_count: Arc<AtomicUsize>,
running: Arc<[AtomicBool; 2]>, running: Arc<[AtomicBool; 2]>,
has_game: Arc<[AtomicBool; 2]>, has_game: Arc<[AtomicBool; 2]>,
audio_on: Arc<[AtomicBool; 2]>,
linked: Arc<AtomicBool>, linked: Arc<AtomicBool>,
renderers: HashMap<SimId, TextureSink>, renderers: HashMap<SimId, TextureSink>,
} }
@ -103,6 +108,7 @@ impl Emulator {
sim_count: Arc<AtomicUsize>, sim_count: Arc<AtomicUsize>,
running: Arc<[AtomicBool; 2]>, running: Arc<[AtomicBool; 2]>,
has_game: Arc<[AtomicBool; 2]>, has_game: Arc<[AtomicBool; 2]>,
audio_on: Arc<[AtomicBool; 2]>,
linked: Arc<AtomicBool>, linked: Arc<AtomicBool>,
) -> Result<Self> { ) -> Result<Self> {
Ok(Self { Ok(Self {
@ -112,6 +118,7 @@ impl Emulator {
sim_count, sim_count,
running, running,
has_game, has_game,
audio_on,
linked, linked,
renderers: HashMap::new(), renderers: HashMap::new(),
}) })
@ -210,15 +217,28 @@ impl Emulator {
} }
} }
} }
let weight = 1.0 / self.sims.len() as f32; let p1_audio =
for sim in self.sims.iter_mut() { p1_running && self.audio_on[SimId::Player1.to_index()].load(Ordering::Acquire);
sim.read_samples(&mut audio_samples, weight); let p2_audio =
p2_running && self.audio_on[SimId::Player2.to_index()].load(Ordering::Acquire);
let weight = if p1_audio && p2_audio { 0.5 } else { 1.0 };
if p1_audio {
if let Some(sim) = self.sims.get_mut(SimId::Player1.to_index()) {
sim.read_samples(&mut audio_samples, weight);
}
} }
if !audio_samples.is_empty() { if p2_audio {
if let Some(sim) = self.sims.get_mut(SimId::Player2.to_index()) {
sim.read_samples(&mut audio_samples, weight);
}
}
if audio_samples.is_empty() {
audio_samples.resize(EXPECTED_FRAME_SIZE, 0.0);
} else {
idle = false; idle = false;
self.audio.update(&audio_samples);
audio_samples.clear();
} }
self.audio.update(&audio_samples);
audio_samples.clear();
if idle { if idle {
// The game is paused, and we have output all the video/audio we have. // The game is paused, and we have output all the video/audio we have.
// Block the thread until a new command comes in. // Block the thread until a new command comes in.
@ -274,6 +294,10 @@ impl Emulator {
} }
} }
} }
EmulatorCommand::SetAudioEnabled(p1, p2) => {
self.audio_on[SimId::Player1.to_index()].store(p1, Ordering::Release);
self.audio_on[SimId::Player2.to_index()].store(p2, Ordering::Release);
}
EmulatorCommand::Link => { EmulatorCommand::Link => {
self.link_sims(); self.link_sims();
} }
@ -302,6 +326,7 @@ pub enum EmulatorCommand {
StopSecondSim, StopSecondSim,
Pause, Pause,
Resume, Resume,
SetAudioEnabled(bool, bool),
Link, Link,
Unlink, Unlink,
Reset(SimId), Reset(SimId),
@ -314,6 +339,7 @@ pub struct EmulatorClient {
sim_count: Arc<AtomicUsize>, sim_count: Arc<AtomicUsize>,
running: Arc<[AtomicBool; 2]>, running: Arc<[AtomicBool; 2]>,
has_game: Arc<[AtomicBool; 2]>, has_game: Arc<[AtomicBool; 2]>,
audio_on: Arc<[AtomicBool; 2]>,
linked: Arc<AtomicBool>, linked: Arc<AtomicBool>,
} }
@ -330,6 +356,9 @@ impl EmulatorClient {
pub fn are_sims_linked(&self) -> bool { pub fn are_sims_linked(&self) -> bool {
self.linked.load(Ordering::Acquire) self.linked.load(Ordering::Acquire)
} }
pub fn is_audio_enabled(&self, sim_id: SimId) -> bool {
self.audio_on[sim_id.to_index()].load(Ordering::Acquire)
}
pub fn send_command(&self, command: EmulatorCommand) { pub fn send_command(&self, command: EmulatorCommand) {
if let Err(err) = self.queue.send(command) { if let Err(err) = self.queue.send(command) {
eprintln!( eprintln!(

View File

@ -120,6 +120,7 @@ extern "C" fn on_frame(sim: *mut VB) -> i32 {
const AUDIO_CAPACITY_SAMPLES: usize = 834 * 4; const AUDIO_CAPACITY_SAMPLES: usize = 834 * 4;
const AUDIO_CAPACITY_FLOATS: usize = AUDIO_CAPACITY_SAMPLES * 2; const AUDIO_CAPACITY_FLOATS: usize = AUDIO_CAPACITY_SAMPLES * 2;
pub const EXPECTED_FRAME_SIZE: usize = 834 * 2;
struct VBState { struct VBState {
frame_seen: bool, frame_seen: bool,