Compare commits

..

No commits in common. "08bd33b4d4d8af509b352ef9ea701591c065b299" and "192bdffd646571aad437fcf3e33fd3910d3bd7c0" have entirely different histories.

4 changed files with 62 additions and 104 deletions

View File

@ -66,16 +66,12 @@ impl Bus {
self.cartridge.as_ref()?.title() self.cartridge.as_ref()?.title()
} }
pub(crate) fn pass_audio_src(&mut self, sender: AudioSender<f32>) { pub(crate) fn pass_audio_src(&mut self, sender: AudioSender) {
self.snd.set_audio_src(sender) self.snd.set_audio_src(sender)
} }
pub(crate) fn is_full(&self) -> bool { pub(crate) fn is_mpsc_still_full(&mut self) -> bool {
self.snd.is_full() self.snd.is_mpsc_still_full()
}
pub(crate) fn flush_samples(&mut self) {
self.snd.flush_samples()
} }
pub(crate) fn clock(&mut self) { pub(crate) fn clock(&mut self) {

View File

@ -45,7 +45,7 @@ impl Cpu {
}) })
} }
pub fn set_audio_src(&mut self, sender: AudioSender<f32>) { pub fn set_audio_src(&mut self, sender: AudioSender) {
self.bus.pass_audio_src(sender) self.bus.pass_audio_src(sender)
} }
@ -96,6 +96,13 @@ impl Cpu {
} }
pub fn step(&mut self) -> Cycle { pub fn step(&mut self) -> Cycle {
// if !self.bus.boot_enabled() {
// let out = std::io::stdout();
// let handle = out.lock();
// self.log_state(handle).unwrap();
// }
let cycles = match self.halted() { let cycles = match self.halted() {
Some(state) => { Some(state) => {
use HaltState::*; use HaltState::*;
@ -110,10 +117,6 @@ impl Cpu {
self.inc_pc(); self.inc_pc();
let instr = self.decode(opcode); let instr = self.decode(opcode);
// let out = std::io::stdout();
// let _ = self._debug_log(out.lock(), &instr);
let cycles = self.execute(instr); let cycles = self.execute(instr);
self.check_ime(); self.check_ime();
@ -122,17 +125,15 @@ impl Cpu {
} }
}; };
// TODO: With how we currently handle audio // FIXME: Regression, this is not a proper fix,
// this --while being correct-- incurs a performance penalty // the FIFO behaves weirdly using this code
// as our emu is audio-bound.
let mut elapsed = 0x00;
let pending: u32 = cycles.into(); let pending: u32 = cycles.into();
while elapsed < pending { let mut offset = 0;
if !self.bus.is_full() { for _ in 0..(pending + offset) {
if !self.bus.is_mpsc_still_full() {
self.bus.clock(); self.bus.clock();
elapsed += 1;
} else { } else {
self.bus.flush_samples(); offset += 1;
} }
} }

View File

@ -369,15 +369,14 @@ impl Ppu {
} }
SendToFifoTwo => { SendToFifoTwo => {
let palette = &self.monochrome.bg_palette; let palette = &self.monochrome.bg_palette;
self.fetch.send_to_fifo(&mut self.fifo, palette);
if let Ok(()) = self.fetch.send_to_fifo(&mut self.fifo, palette) {
self.fetch.x_pos += 1; self.fetch.x_pos += 1;
self.fetch.back.next(TileNumber); self.fetch.back.next(TileNumber);
self.fetch.back.tile = Default::default(); self.fetch.back.tile = Default::default();
} }
} }
} }
}
if self.fifo.is_enabled() { if self.fifo.is_enabled() {
use RenderPriority::*; use RenderPriority::*;
@ -721,11 +720,7 @@ impl PixelFetcher {
tile_data_addr + (offset * 2) tile_data_addr + (offset * 2)
} }
fn send_to_fifo(&self, fifo: &mut FifoRenderer, palette: &BackgroundPalette) -> Result<(), ()> { fn send_to_fifo(&self, fifo: &mut FifoRenderer, palette: &BackgroundPalette) {
if !fifo.back.is_empty() {
return Err(());
}
let (high, low) = self let (high, low) = self
.back .back
.tile .tile
@ -734,14 +729,14 @@ impl PixelFetcher {
let tbpp = Pixels::from_bytes(high, low); let tbpp = Pixels::from_bytes(high, low);
if fifo.back.is_empty() {
for x in 0..Pixels::PIXEL_COUNT { for x in 0..Pixels::PIXEL_COUNT {
let shade = palette.shade(tbpp.shade_id(x)); let shade = palette.shade(tbpp.shade_id(x));
let fifo_info = BackgroundFifoInfo { shade }; let fifo_info = BackgroundFifoInfo { shade };
fifo.back.push_back(fifo_info); fifo.back.push_back(fifo_info);
} }
}
Ok(())
} }
fn get_obj_addr(attr: &ObjectAttribute, pos: &ScreenPosition, size: ObjectSize) -> u16 { fn get_obj_addr(attr: &ObjectAttribute, pos: &ScreenPosition, size: ObjectSize) -> u16 {

View File

@ -1,5 +1,3 @@
use std::collections::VecDeque;
use bitfield::bitfield; use bitfield::bitfield;
use crossbeam_channel::{Receiver, Sender, TrySendError}; use crossbeam_channel::{Receiver, Sender, TrySendError};
use rodio::Source; use rodio::Source;
@ -9,8 +7,8 @@ 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 = 512; const AUDIO_BUFFER_LEN: usize = 1024;
const CHANNEL_COUNT: usize = 2; 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(Default, Debug, Clone)]
@ -29,10 +27,10 @@ pub(crate) struct Sound {
frame_seq_state: FrameSequencerState, frame_seq_state: FrameSequencerState,
div_prev: Option<u8>, div_prev: Option<u8>,
sender: Option<AudioSender<f32>>, sender: Option<AudioSender>,
sample_counter: u64, sample_counter: u64,
buffer: AudioBuffer<(f32, f32)>, is_mpsc_full: bool,
} }
impl Sound { impl Sound {
@ -72,7 +70,7 @@ impl Sound {
self.div_prev = Some(bit_5); self.div_prev = Some(bit_5);
if self.sender.is_some() && self.sample_counter >= SM83_CLOCK_SPEED { if self.sample_counter >= SM83_CLOCK_SPEED {
self.sample_counter %= SM83_CLOCK_SPEED; self.sample_counter %= SM83_CLOCK_SPEED;
// Sample the APU // Sample the APU
@ -95,33 +93,27 @@ impl Sound {
let left = (ch1_left + ch2_left + ch3_left + ch4_left) / 4.0; let left = (ch1_left + ch2_left + ch3_left + ch4_left) / 4.0;
let right = (ch1_right + ch2_right + ch3_right + ch4_right) / 4.0; let right = (ch1_right + ch2_right + ch3_right + ch4_right) / 4.0;
self.buffer.push_back((left, right)); if let Some(s) = self.sender.as_ref() {
let _ = s.send_samples(left, right).map_err(|e| match e {
TrySendError::Full(_) => self.is_mpsc_full = true,
TrySendError::Disconnected(_) => {
panic!("Audio Sample MPSC Channel Disconnected")
}
});
}
} }
} }
pub(crate) fn set_audio_src(&mut self, sender: AudioSender<f32>) { pub(crate) fn set_audio_src(&mut self, sender: AudioSender) {
self.sender = Some(sender); self.sender = Some(sender);
} }
pub(crate) fn is_full(&self) -> bool { pub(crate) fn is_mpsc_still_full(&mut self) -> bool {
self.buffer.len() >= AUDIO_BUFFER_LEN * CHANNEL_COUNT if let Some(sender) = self.sender.as_ref() {
self.is_mpsc_full = sender.is_full();
} }
pub(crate) fn flush_samples(&mut self) { self.is_mpsc_full
if let Some(sender) = self.sender.as_ref() {
while self.buffer.len() >= CHANNEL_COUNT {
match self.buffer.pop_front() {
Some((left, right)) => {
sender
.send_samples(left, right)
.expect("Successfully sent samples across threads");
}
None => unreachable!(
"While loop ensures that there are at least two items in AudioBuffer"
),
}
}
}
} }
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) {
@ -1183,34 +1175,35 @@ impl From<ChannelControl> for u8 {
pub struct AudioMPSC; pub struct AudioMPSC;
impl AudioMPSC { impl AudioMPSC {
pub fn new() -> (AudioSender<f32>, AudioReceiver<f32>) { pub fn new() -> (AudioSender, AudioReceiver) {
// TODO: Can we provide an upper limit for this? let (send, recv) = crossbeam_channel::bounded(AUDIO_BUFFER_LEN * 2);
// The larger this channel is, the more lag there is between the Audio and
// Emulator
let (send, recv) = crossbeam_channel::unbounded();
(AudioSender { inner: send }, AudioReceiver { inner: recv }) (AudioSender { inner: send }, AudioReceiver { inner: recv })
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct AudioSender<T> { pub struct AudioSender {
inner: Sender<T>, inner: Sender<f32>,
} }
impl<T> AudioSender<T> { impl AudioSender {
fn send_samples(&self, left: T, right: T) -> Result<(), TrySendError<T>> { fn send_samples(&self, left: f32, right: f32) -> Result<(), TrySendError<f32>> {
self.inner.try_send(left).and(self.inner.try_send(right))?; self.inner.try_send(left).and(self.inner.try_send(right))?;
Ok(()) Ok(())
} }
fn is_full(&self) -> bool {
self.inner.is_full()
}
} }
pub struct AudioReceiver<T> { pub struct AudioReceiver {
inner: Receiver<T>, inner: Receiver<f32>,
} }
impl<T> Iterator for AudioReceiver<T> { impl Iterator for AudioReceiver {
type Item = T; type Item = f32;
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?
@ -1218,7 +1211,7 @@ impl<T> Iterator for AudioReceiver<T> {
} }
} }
impl<T: rodio::Sample> Source for AudioReceiver<T> { impl Source for AudioReceiver {
fn current_frame_len(&self) -> Option<usize> { fn current_frame_len(&self) -> Option<usize> {
// A frame changes when the samples rate or // A frame changes when the samples rate or
// number of channels change. This will never happen, so // number of channels change. This will never happen, so
@ -1228,7 +1221,7 @@ impl<T: rodio::Sample> Source for AudioReceiver<T> {
fn channels(&self) -> u16 { fn channels(&self) -> u16 {
// The Gameboy supports two channels // The Gameboy supports two channels
CHANNEL_COUNT as u16 CHANNEL_COUNT
} }
fn sample_rate(&self) -> u32 { fn sample_rate(&self) -> u32 {
@ -1240,30 +1233,3 @@ impl<T: rodio::Sample> Source for AudioReceiver<T> {
None None
} }
} }
#[derive(Debug, Clone)]
struct AudioBuffer<T> {
inner: VecDeque<T>,
}
impl<T> Default for AudioBuffer<T> {
fn default() -> Self {
Self {
inner: VecDeque::with_capacity(AUDIO_BUFFER_LEN * CHANNEL_COUNT),
}
}
}
impl<T> AudioBuffer<T> {
pub fn push_back(&mut self, value: T) {
self.inner.push_back(value)
}
pub fn pop_front(&mut self) -> Option<T> {
self.inner.pop_front()
}
pub fn len(&self) -> usize {
self.inner.len()
}
}