diff --git a/frontends/sdl/src/audio.rs b/frontends/sdl/src/audio.rs index 7b9562cddf987356c2c06e5b795e0d18621a6d0e..7a41d23a81876c034a7d74b9aa51ed674efd4a97 100644 --- a/frontends/sdl/src/audio.rs +++ b/frontends/sdl/src/audio.rs @@ -1,23 +1,27 @@ use sdl2::{ - audio::{AudioCallback, AudioSpecDesired}, + audio::{AudioCallback, AudioDevice, AudioSpecDesired}, AudioSubsystem, Sdl, }; -use std::time::Duration; -struct SquareWave { +pub struct AudioWave { phase_inc: f32, + phase: f32, + volume: f32, + + /// The relative amount of time (as a percentage decimal) the low level + /// is going to be present during a period (cycle). + /// From [Wikipedia](https://en.wikipedia.org/wiki/Duty_cycle). + duty_cycle: f32, } -impl AudioCallback for SquareWave { +impl AudioCallback for AudioWave { type Channel = f32; fn callback(&mut self, out: &mut [f32]) { for x in out.iter_mut() { - // this is a square wave with 50% of down - // and 50% of up values - *x = if self.phase <= 0.5 { + *x = if self.phase < (1.0 - self.duty_cycle) { self.volume } else { -self.volume @@ -28,6 +32,7 @@ impl AudioCallback for SquareWave { } pub struct Audio { + pub device: AudioDevice<AudioWave>, pub audio_subsystem: AudioSubsystem, } @@ -42,10 +47,11 @@ impl Audio { }; let device = audio_subsystem - .open_playback(None, &desired_spec, |spec| SquareWave { + .open_playback(None, &desired_spec, |spec| AudioWave { phase_inc: 440.0 / spec.freq as f32, phase: 0.0, volume: 0.25, + duty_cycle: 0.5, }) .unwrap(); @@ -53,8 +59,9 @@ impl Audio { // device's activity device.resume(); - std::thread::sleep(Duration::from_millis(2000)); - - Self { audio_subsystem } + Self { + device, + audio_subsystem, + } } } diff --git a/src/apu.rs b/src/apu.rs new file mode 100644 index 0000000000000000000000000000000000000000..dc25415c6386c31240670e749bd35283211d5983 --- /dev/null +++ b/src/apu.rs @@ -0,0 +1,24 @@ +pub struct Apu { +} + +impl Apu { + pub fn new() -> Self { + Self {} + } + + pub fn read(&mut self, addr: u16) -> u8 { + match addr { + 0xff26 => 1 as u8, // todo implement this + _ => 0x00 + } + } + + pub fn write(&mut self, addr: u16, value: u8) { + match addr { + 0xff26 => { + // @todo implement the logic here + }, + _ => {} + } + } +} diff --git a/src/gb.rs b/src/gb.rs index 8f7074d82f0fd1a20ce173ee2ffa6bbf03a69b62..e7a1952fb55bd7339d1e1a6da170ec0426b34838 100644 --- a/src/gb.rs +++ b/src/gb.rs @@ -7,7 +7,7 @@ use crate::{ ppu::{Ppu, PpuMode, Tile, FRAME_BUFFER_SIZE}, rom::Cartridge, timer::Timer, - util::read_file, + util::read_file, apu::Apu, }; #[cfg(feature = "wasm")] @@ -57,9 +57,10 @@ impl GameBoy { #[cfg_attr(feature = "wasm", wasm_bindgen(constructor))] pub fn new() -> Self { let ppu = Ppu::new(); + let apu = Apu::new(); let pad = Pad::new(); let timer = Timer::new(); - let mmu = Mmu::new(ppu, pad, timer); + let mmu = Mmu::new(ppu, apu, pad, timer); let cpu = Cpu::new(mmu); Self { cpu } } diff --git a/src/lib.rs b/src/lib.rs index 0bc2f37c3e2d1185f3ecec18c9d1d306b39da464..7decfab2b80948c67ae0c8c3765191dda99b7743 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ #![allow(clippy::uninlined_format_args)] +pub mod apu; pub mod cpu; pub mod data; pub mod gb; diff --git a/src/mmu.rs b/src/mmu.rs index 2f277fbb7b61bdbc2b3c6aaa716a0c6eb6292e42..ed1324b075b8b3e2aae5a49d416e038fea9bfccd 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -1,4 +1,4 @@ -use crate::{debugln, pad::Pad, ppu::Ppu, rom::Cartridge, timer::Timer}; +use crate::{debugln, pad::Pad, ppu::Ppu, rom::Cartridge, timer::Timer, apu::Apu}; pub const BOOT_SIZE: usize = 2304; pub const RAM_SIZE: usize = 8192; @@ -13,6 +13,11 @@ pub struct Mmu { /// some of the access operations. ppu: Ppu, + /// Reference to the APU (Audio Processing Unit) that is going + /// to be used both for register reading/writing and to forward + /// some of the access operations. + apu: Apu, + /// Reference to the Gamepad structure that is going to control /// the I/O access to this device. pad: Pad, @@ -44,9 +49,10 @@ pub struct Mmu { } impl Mmu { - pub fn new(ppu: Ppu, pad: Pad, timer: Timer) -> Self { + pub fn new(ppu: Ppu, apu: Apu, pad: Pad, timer: Timer) -> Self { Self { ppu, + apu, pad, timer, rom: Cartridge::new(),