From 060dbde966a7d8d5cfb109ed3374160a8562f191 Mon Sep 17 00:00:00 2001 From: Franco Colmenarez Date: Sat, 18 Dec 2021 18:00:42 -0500 Subject: [PATCH] Some progress on sound I guess --- src/bus.rs | 8 ++- src/cpu.rs | 2 +- src/emulator.rs | 5 +- src/ppu.rs | 4 +- src/render.rs | 2 +- src/sound.rs | 141 +++++++++++++++++++++++++++++++++++++++++++++++- src/timer.rs | 2 +- 7 files changed, 150 insertions(+), 14 deletions(-) diff --git a/src/bus.rs b/src/bus.rs index ece0e1b..8e0baac 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -1,15 +1,13 @@ use std::ops::RangeInclusive; -use crate::utils::{ - join_bytes -}; +use crate::utils::join_bytes; use crate::rom::{ROM, load_rom}; use crate::ppu::{ PPU, DMA_ADDRESS, }; -use crate::timer::{Timer}; +use crate::timer::Timer; use crate::joypad::{Joypad, JOYPAD_ADDRESS}; -use crate::sound::{Sound}; +use crate::sound::Sound; use crate::interrupts::{ Interrupts, INTERRUPT_ENABLE_ADDRESS, diff --git a/src/cpu.rs b/src/cpu.rs index 7f468b5..8eb594f 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -8,7 +8,7 @@ use crate::utils::{ sub_half_carry, add_half_carry_16bit, }; -use crate::bus::{Bus}; +use crate::bus::Bus; use crate::interrupts::{ Interrupt, INTERRUPT_ENABLE_ADDRESS, diff --git a/src/emulator.rs b/src/emulator.rs index fd12dd3..53f328c 100644 --- a/src/emulator.rs +++ b/src/emulator.rs @@ -1,11 +1,11 @@ // use std::{thread, time}; use winit_input_helper::WinitInputHelper; -use winit::event::{VirtualKeyCode}; +use winit::event::VirtualKeyCode; use crate::cpu::{CPU, Cycles}; use crate::interrupts::Interrupt; use crate::bus::Bus; -use crate::joypad::{Button}; +use crate::joypad::Button; #[cfg(not(test))] use crate::rom::{save_file}; @@ -111,6 +111,7 @@ impl Emulator { let cycles = self.cpu.get_last_op_cycles().to_t(); self.bus.ppu.do_cycles(&mut self.bus.interrupts, cycles, frame_buffer); self.bus.timer.do_cycles(&mut self.bus.interrupts, cycles); + self.bus.sound.do_cycles(cycles); // 1 CPU cycle = 238.42ns // thread::sleep(time::Duration::from_nanos((self.cpu.get_last_op_cycles().0 * 238).try_into().unwrap())); diff --git a/src/ppu.rs b/src/ppu.rs index 4c2c60b..5625afb 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -3,8 +3,8 @@ use crate::utils::{ get_bit, set_bit, }; -use crate::bus::{SPRITE_ATTRIBUTE_TABLE}; -use crate::cpu::{Cycles}; +use crate::bus::SPRITE_ATTRIBUTE_TABLE; +use crate::cpu::Cycles; use crate::interrupts::{Interrupts, Interrupt}; pub const LCD_WIDTH: u32 = 160; diff --git a/src/render.rs b/src/render.rs index 5257f75..642b053 100644 --- a/src/render.rs +++ b/src/render.rs @@ -1,6 +1,6 @@ use crate::emulator::Emulator; use crate::frames::Frames; -use crate::cpu::{Cycles}; +use crate::cpu::Cycles; use crate::ppu::{WIDTH, HEIGHT}; use log::error; diff --git a/src/sound.rs b/src/sound.rs index 5b2cc5c..1ea7cce 100644 --- a/src/sound.rs +++ b/src/sound.rs @@ -1,5 +1,10 @@ +use std::env; use std::ops::RangeInclusive; +use std::sync::{Arc, Mutex}; +use cpal::{Stream, StreamConfig, Device, Sample}; +use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use crate::cpu::Cycles; +use crate::utils::join_bytes; pub const NR10_ADDRESS: u16 = 0xFF10; pub const NR11_ADDRESS: u16 = 0xFF11; @@ -29,17 +34,144 @@ pub const NR52_ADDRESS: u16 = 0xFF26; pub const WAVE_PATTERN_RAM: RangeInclusive = 0xFF30..=0xFF3F; +const WAVE_DUTY_PATTERNS: [[u8; 8]; 4] = [ + [0, 0, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 0, 0, 1, 1], + [0, 0, 0, 0, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 0, 0], +]; + +struct ChannelTwo { + #[allow(dead_code)] + stream: Stream, + buffer: Arc>>, + frequency_timer: u16, + duty_position: usize, + sample_timer: usize, + sample_rate: usize, + buffer_pos: usize, +} + +impl ChannelTwo { + pub fn new(device: &Device, config: &StreamConfig, sample_rate: usize) -> Self { + let mut count: usize = 0; + // let mut count: f32 = 0.0; + let buffer = Arc::new(Mutex::new(vec![0.0; sample_rate])); + let buffer_clone = buffer.clone(); + let stream = device.build_output_stream(&config, move |data: &mut [f32], _| { + /* for sample in data.iter_mut() { + let y: f32 = ((count / (sample_rate as f32)) * 440.0 * 2.0 * 3.14159).sin().clamp(-1.0, 1.0); + *sample = Sample::from(&y); + count += 1.0; + if count >= sample_rate as f32 { + count = 0.0; + } + } */ + let b = buffer_clone.lock().unwrap(); + for sample in data.iter_mut() { + *sample = Sample::from(&b[count]); + count += 1; + if count >= b.len() { + count = 0; + } + } + }, |err| eprintln!("An error occurred on the channel two: {}", err)).unwrap(); + stream.play().unwrap(); + + Self { + stream, + frequency_timer: 0, + duty_position: 0, + sample_timer: 0, + buffer_pos: 0, + sample_rate, + buffer, + } + } + + pub fn update_buffer(&mut self, duty_pattern: u8) { + let sample = match WAVE_DUTY_PATTERNS[duty_pattern as usize][self.duty_position as usize] { + 0 => -1.0, + 1 => 1.0, + _ => unreachable!(), + }; + let clone = self.buffer.clone(); + let mut buffer = clone.lock().unwrap(); + buffer[self.buffer_pos] = sample; + + self.buffer_pos += 1; + if self.buffer_pos >= buffer.len() { + self.buffer_pos = 0; + } + } + + pub fn cycle(&mut self, duty: u8, frequency: u16) { + self.frequency_timer = self.frequency_timer.saturating_sub(1); + if self.frequency_timer == 0 { + self.frequency_timer = (2048 - frequency) * 4; + self.duty_position += 1; + if self.duty_position > 7 { + self.duty_position = 0; + } + } + self.sample_timer = self.sample_timer.saturating_add(self.sample_rate); + if self.sample_timer >= 4194304 { + self.update_buffer(duty); + self.sample_timer = 0; + } + } +} + pub struct Sound { io_registers: [u8; 48], + channel_two: Option, } + +/* Sine Wave +let channel_two = device.build_output_stream(&config, move |data: &mut [f32], _: &cpal::OutputCallbackInfo| { + for sample in data.iter_mut() { + let y: f32 = ((sound.count / (sample_rate as f32)) * 440.0 * 2.0 * 3.14159).sin().clamp(-1.0, 1.0); + *sample = Sample::from(&y); + sound.count += 1.0; + } +}, err_fn).unwrap(); +channel_two.play().unwrap(); +sound.channel_two = Some(channel_two); */ + impl Sound { pub fn new() -> Self { + if !env::var("SOUND_ENABLE").is_err() { + let host = cpal::default_host(); + let device = host.default_output_device().expect("no output device available"); + let mut supported_configs_range = device.supported_output_configs() + .expect("error while querying configs"); + let supported_config = supported_configs_range.next() + .expect("no supported config?!") + .with_max_sample_rate(); + // let err_fn = |err| eprintln!("an error occurred on the output audio stream: {}", err); + let sample_rate = supported_config.sample_rate().0; + let config: StreamConfig = supported_config.into(); + return Self { + io_registers: [0; 48], + channel_two: Some(ChannelTwo::new(&device, &config, sample_rate as usize)), + }; + } + Self { io_registers: [0; 48], + channel_two: None, } } + pub fn channel_two_duty(&self) -> u8 { + (self.get_register(NR21_ADDRESS) >> 6) & 0b11 + } + + pub fn channel_two_frequency(&self) -> u16 { + join_bytes(self.get_register(NR24_ADDRESS), self.get_register(NR23_ADDRESS)) & 0x7F + } + pub fn is_io_register(address: u16) -> bool { address >= 0xFF10 && address <= 0xFF3F } @@ -52,7 +184,7 @@ impl Sound { self.io_registers[(address - 0xFF10) as usize] = data; } - pub fn do_cycles(&self, cycles: Cycles) { + pub fn do_cycles(&mut self, cycles: Cycles) { let mut count = 0; while count < cycles.0 { self.cycle(); @@ -60,6 +192,11 @@ impl Sound { } } - fn cycle(&self) { + fn cycle(&mut self) { + if self.channel_two.is_some() { + let duty = self.channel_two_duty(); + let frequency = self.channel_two_frequency(); + self.channel_two.as_mut().unwrap().cycle(duty, frequency); + } } } diff --git a/src/timer.rs b/src/timer.rs index 8079607..e5b29a2 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,4 +1,4 @@ -use crate::cpu::{Cycles}; +use crate::cpu::Cycles; use crate::interrupts::{Interrupt, Interrupts}; use crate::utils::{ BitIndex,