Add sound timer handling

This commit is contained in:
Michael Kohl 2021-04-05 17:12:05 +07:00
parent 801cbc64df
commit 026aec826e
4 changed files with 89 additions and 8 deletions

55
src/chip8/audio.rs Normal file
View File

@ -0,0 +1,55 @@
use sdl2::audio::{AudioCallback, AudioDevice, AudioSpecDesired};
use sdl2::AudioSubsystem;
pub struct SquareWave {
phase_inc: f32,
phase: f32,
volume: f32,
}
impl AudioCallback for SquareWave {
type Channel = f32;
fn callback(&mut self, out: &mut [f32]) {
for x in out.iter_mut() {
*x = if self.phase <= 0.5 {
self.volume
} else {
-self.volume
};
self.phase = (self.phase + self.phase_inc) % 1.0;
}
}
}
pub struct Speaker {
pub device: AudioDevice<SquareWave>,
}
impl Speaker {
pub fn new(audio_subsystem: &AudioSubsystem) -> Self {
let spec = AudioSpecDesired {
freq: Some(5000),
channels: Some(1),
samples: None,
};
let device = audio_subsystem
.open_playback(None, &spec, |spec| SquareWave {
phase_inc: 440.0 / spec.freq as f32,
phase: 0.0,
volume: 0.25,
})
.expect("Could not initialize audio device");
Speaker { device }
}
pub fn beep(&mut self, status: bool) {
if status {
self.device.resume();
} else {
self.device.pause();
}
}
}

View File

@ -1,33 +1,55 @@
use crate::chip8::audio::Speaker;
use crate::chip8::display::Screen;
use crate::chip8::keyboard::Keyboard;
use crate::chip8::memory::Memory;
use crate::chip8::registers::{Register, Registers};
use crate::chip8::stack::Stack;
use sdl2::AudioSubsystem;
use std::{thread, time::Duration};
pub struct Chip8 {
pub memory: Memory,
pub registers: Registers,
pub stack: Stack,
pub keyboard: Keyboard,
pub screen: Screen,
pub speaker: Speaker,
}
impl Chip8 {
pub fn new() -> Chip8 {
pub fn new(audio_subsystem: &AudioSubsystem) -> Chip8 {
Chip8 {
memory: Memory::new(),
registers: Registers::new(),
stack: Stack::new(),
keyboard: Keyboard::new(),
screen: Screen::new(),
speaker: Speaker::new(audio_subsystem),
}
}
pub fn delay_if_necessary(&mut self) -> () {
pub fn handle_timers(&mut self) -> () {
self.handle_delay_timer();
self.handle_sound_timer();
}
pub fn handle_delay_timer(&mut self) -> () {
let delay_timer = self.registers.get(Register::DT);
if delay_timer > 0 {
::std::thread::sleep(::std::time::Duration::new(0, 1_000_000_000u32 / 60));
thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
self.registers.set(Register::DT, delay_timer - 1);
}
}
pub fn handle_sound_timer(&mut self) {
let sound_timer = self.registers.get(Register::ST);
let status = sound_timer > 0;
self.speaker.beep(status);
if status {
thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
self.registers.set(Register::ST, sound_timer - 1);
}
}
}

View File

@ -1,3 +1,4 @@
pub mod audio;
pub mod display;
pub mod emulator;
pub mod keyboard;

View File

@ -11,13 +11,15 @@ use sdl2::rect::Rect;
const EMULATOR_WINDOW_TITLE: &str = "Rust CHIP-8";
fn main() -> Result<(), String> {
let mut chip8 = Chip8::new();
let sdl_context = sdl2::init()?;
let video_subsystem = sdl_context.video()?;
let audio_subsystem = sdl_context.audio()?;
let mut chip8 = Chip8::new(&audio_subsystem);
chip8.screen.draw_sprite(24, 13, chip8.memory.read(20, 5));
chip8.screen.draw_sprite(29, 13, chip8.memory.read(10, 5));
chip8.screen.draw_sprite(34, 13, chip8.memory.read(40, 5));
let sdl_context = sdl2::init()?;
let video_subsystem = sdl_context.video()?;
chip8.registers.set(chip8::registers::Register::ST, 5);
let window = video_subsystem
.window(
@ -85,7 +87,8 @@ fn main() -> Result<(), String> {
}
canvas.present();
chip8.delay_if_necessary();
chip8.handle_delay_timer();
chip8.handle_sound_timer();
}
Ok(())