Compare commits
No commits in common. "b13444c88591ea6fd6d467b01dd7955aebf7a9da" and "db421c58f84f41a6bd0096f57fde733a3ee1734a" have entirely different histories.
b13444c885
...
db421c58f8
|
@ -70,10 +70,6 @@ impl Bus {
|
||||||
self.snd.set_audio_src(sender)
|
self.snd.set_audio_src(sender)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_mpsc_still_full(&mut self) -> bool {
|
|
||||||
self.snd.is_mpsc_still_full()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn clock(&mut self) {
|
pub(crate) fn clock(&mut self) {
|
||||||
self.ppu.clock();
|
self.ppu.clock();
|
||||||
self.timer.clock();
|
self.timer.clock();
|
||||||
|
|
|
@ -183,7 +183,7 @@ impl Mbc1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _mbcm_zero_bank(&self) -> u8 {
|
fn mbcm_zero_bank(&self) -> u8 {
|
||||||
use BankCount::*;
|
use BankCount::*;
|
||||||
|
|
||||||
match self.bank_count {
|
match self.bank_count {
|
||||||
|
|
|
@ -126,13 +126,8 @@ impl Cpu {
|
||||||
};
|
};
|
||||||
|
|
||||||
let pending: u32 = cycles.into();
|
let pending: u32 = cycles.into();
|
||||||
let mut offset = 0;
|
for _ in 0..pending {
|
||||||
for _ in 0..(pending + offset) {
|
self.bus.clock();
|
||||||
if !self.bus.is_mpsc_still_full() {
|
|
||||||
self.bus.clock();
|
|
||||||
} else {
|
|
||||||
offset += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.handle_interrupts();
|
self.handle_interrupts();
|
||||||
|
|
10
src/emu.rs
10
src/emu.rs
|
@ -11,7 +11,6 @@ pub const SM83_CYCLE_TIME: Duration = Duration::from_nanos(1_000_000_000 / SM83_
|
||||||
pub const CYCLES_IN_FRAME: Cycle = Cycle::new(456 * 154); // 456 Cycles times 154 scanlines
|
pub const CYCLES_IN_FRAME: Cycle = Cycle::new(456 * 154); // 456 Cycles times 154 scanlines
|
||||||
pub(crate) const SM83_CLOCK_SPEED: u64 = 0x40_0000; // Hz which is 4.194304Mhz
|
pub(crate) const SM83_CLOCK_SPEED: u64 = 0x40_0000; // Hz which is 4.194304Mhz
|
||||||
const DEFAULT_TITLE: &str = "DMG-01 Emulator";
|
const DEFAULT_TITLE: &str = "DMG-01 Emulator";
|
||||||
const GAMEPAD_ENABLED: bool = false;
|
|
||||||
|
|
||||||
pub fn init(boot_path: Option<&str>, rom_path: &str) -> Result<SM83> {
|
pub fn init(boot_path: Option<&str>, rom_path: &str) -> Result<SM83> {
|
||||||
let mut cpu = match boot_path {
|
let mut cpu = match boot_path {
|
||||||
|
@ -45,13 +44,12 @@ pub fn run(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_unsynced(game_boy: &mut SM83, gamepad: &mut Gilrs, input: &WinitInputHelper) -> Cycle {
|
pub fn run_unsynced(game_boy: &mut SM83, gamepad: &mut Gilrs, input: &WinitInputHelper) -> Cycle {
|
||||||
if GAMEPAD_ENABLED {
|
if let Some(event) = gamepad.next_event() {
|
||||||
if let Some(event) = gamepad.next_event() {
|
joypad::handle_gamepad_input(game_boy.joypad_mut(), event);
|
||||||
joypad::handle_gamepad_input(game_boy.joypad_mut(), event);
|
} else {
|
||||||
}
|
joypad::handle_keyboard_input(game_boy.joypad_mut(), input);
|
||||||
}
|
}
|
||||||
|
|
||||||
joypad::handle_keyboard_input(game_boy.joypad_mut(), input);
|
|
||||||
game_boy.step()
|
game_boy.step()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
55
src/sound.rs
55
src/sound.rs
|
@ -1,17 +1,14 @@
|
||||||
use bitfield::bitfield;
|
use bitfield::bitfield;
|
||||||
use crossbeam_channel::{Receiver, Sender, TrySendError};
|
use crossbeam_channel::{Receiver, Sender};
|
||||||
use rodio::Source;
|
use rodio::Source;
|
||||||
|
|
||||||
use crate::emu::SM83_CLOCK_SPEED;
|
use crate::emu::SM83_CLOCK_SPEED;
|
||||||
|
|
||||||
const WAVE_PATTERN_RAM_LEN: usize = 0x10;
|
const WAVE_PATTERN_RAM_LEN: usize = 0x10;
|
||||||
|
|
||||||
const SAMPLE_RATE: u32 = 48000; // Hz
|
const SAMPLE_RATE: u32 = 48000; // Hz
|
||||||
const AUDIO_BUFFER_LEN: usize = 1024;
|
|
||||||
const CHANNEL_COUNT: u16 = 2;
|
|
||||||
const SAMPLE_INCREMENT: u64 = SAMPLE_RATE as u64;
|
const SAMPLE_INCREMENT: u64 = SAMPLE_RATE as u64;
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub(crate) struct Sound {
|
pub(crate) struct Sound {
|
||||||
pub(crate) ctrl: SoundControl,
|
pub(crate) ctrl: SoundControl,
|
||||||
/// Tone & Sweep
|
/// Tone & Sweep
|
||||||
|
@ -29,8 +26,6 @@ pub(crate) struct Sound {
|
||||||
|
|
||||||
sender: Option<SampleSender>,
|
sender: Option<SampleSender>,
|
||||||
sample_counter: u64,
|
sample_counter: u64,
|
||||||
|
|
||||||
is_mpsc_full: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sound {
|
impl Sound {
|
||||||
|
@ -90,16 +85,11 @@ impl Sound {
|
||||||
let ch4_left = self.ctrl.output.ch4_left() as u8 as f32 * ch4_amplitude;
|
let ch4_left = self.ctrl.output.ch4_left() as u8 as f32 * ch4_amplitude;
|
||||||
let ch4_right = self.ctrl.output.ch4_right() as u8 as f32 * ch4_amplitude;
|
let ch4_right = self.ctrl.output.ch4_right() as u8 as f32 * ch4_amplitude;
|
||||||
|
|
||||||
let left = (ch1_left + ch2_left + ch3_left + ch4_left) / 4.0;
|
let left_sample = (ch1_left + ch2_left + ch3_left + ch4_left) / 4.0;
|
||||||
let right = (ch1_right + ch2_right + ch3_right + ch4_right) / 4.0;
|
let right_sample = (ch1_right + ch2_right + ch3_right + ch4_right) / 4.0;
|
||||||
|
|
||||||
if let Some(s) = self.sender.as_ref() {
|
if let Some(send) = self.sender.as_ref() {
|
||||||
let _ = s.send_samples(left, right).map_err(|e| match e {
|
send.add_sample(left_sample, right_sample);
|
||||||
TrySendError::Full(_) => self.is_mpsc_full = true,
|
|
||||||
TrySendError::Disconnected(_) => {
|
|
||||||
panic!("Audio Sample MPSC Channel Disconnected")
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,14 +98,6 @@ impl Sound {
|
||||||
self.sender = Some(sender);
|
self.sender = Some(sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_mpsc_still_full(&mut self) -> bool {
|
|
||||||
if let Some(sender) = self.sender.as_ref() {
|
|
||||||
self.is_mpsc_full = sender.is_full();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.is_mpsc_full
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clock_length(freq_hi: &FrequencyHigh, length_timer: &mut u16, enabled: &mut bool) {
|
fn clock_length(freq_hi: &FrequencyHigh, length_timer: &mut u16, enabled: &mut bool) {
|
||||||
if freq_hi.idk() && *length_timer > 0 {
|
if freq_hi.idk() && *length_timer > 0 {
|
||||||
*length_timer -= 1;
|
*length_timer -= 1;
|
||||||
|
@ -1176,30 +1158,31 @@ pub struct AudioSenderReceiver;
|
||||||
|
|
||||||
impl AudioSenderReceiver {
|
impl AudioSenderReceiver {
|
||||||
pub fn new() -> (SampleSender, SampleReceiver) {
|
pub fn new() -> (SampleSender, SampleReceiver) {
|
||||||
let (send, recv) = crossbeam_channel::bounded(AUDIO_BUFFER_LEN * 2);
|
let (send, recv) = crossbeam_channel::unbounded();
|
||||||
|
|
||||||
(SampleSender { inner: send }, SampleReceiver { inner: recv })
|
(SampleSender { send }, SampleReceiver { recv })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SampleSender {
|
pub struct SampleSender {
|
||||||
inner: Sender<f32>,
|
send: Sender<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SampleSender {
|
impl SampleSender {
|
||||||
fn send_samples(&self, left: f32, right: f32) -> Result<(), TrySendError<f32>> {
|
fn add_sample(&self, left: f32, right: f32) {
|
||||||
self.inner.try_send(left).and(self.inner.try_send(right))?;
|
self.send
|
||||||
Ok(())
|
.send(left)
|
||||||
}
|
.expect("Send audio sample across threads");
|
||||||
|
|
||||||
fn is_full(&self) -> bool {
|
self.send
|
||||||
self.inner.is_full()
|
.send(right)
|
||||||
|
.expect("Send audio sample across threads");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SampleReceiver {
|
pub struct SampleReceiver {
|
||||||
inner: Receiver<f32>,
|
recv: Receiver<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for SampleReceiver {
|
impl Iterator for SampleReceiver {
|
||||||
|
@ -1207,7 +1190,7 @@ impl Iterator for SampleReceiver {
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
// TODO: Should this never return none?
|
// TODO: Should this never return none?
|
||||||
self.inner.recv().ok()
|
self.recv.recv().ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1221,7 +1204,7 @@ impl Source for SampleReceiver {
|
||||||
|
|
||||||
fn channels(&self) -> u16 {
|
fn channels(&self) -> u16 {
|
||||||
// The Gameboy supports two channels
|
// The Gameboy supports two channels
|
||||||
CHANNEL_COUNT
|
2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sample_rate(&self) -> u32 {
|
fn sample_rate(&self) -> u32 {
|
||||||
|
|
Loading…
Reference in New Issue