Add sound timer handling
This commit is contained in:
parent
801cbc64df
commit
026aec826e
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,33 +1,55 @@
|
||||||
|
use crate::chip8::audio::Speaker;
|
||||||
use crate::chip8::display::Screen;
|
use crate::chip8::display::Screen;
|
||||||
use crate::chip8::keyboard::Keyboard;
|
use crate::chip8::keyboard::Keyboard;
|
||||||
use crate::chip8::memory::Memory;
|
use crate::chip8::memory::Memory;
|
||||||
use crate::chip8::registers::{Register, Registers};
|
use crate::chip8::registers::{Register, Registers};
|
||||||
use crate::chip8::stack::Stack;
|
use crate::chip8::stack::Stack;
|
||||||
|
|
||||||
|
use sdl2::AudioSubsystem;
|
||||||
|
|
||||||
|
use std::{thread, time::Duration};
|
||||||
|
|
||||||
pub struct Chip8 {
|
pub struct Chip8 {
|
||||||
pub memory: Memory,
|
pub memory: Memory,
|
||||||
pub registers: Registers,
|
pub registers: Registers,
|
||||||
pub stack: Stack,
|
pub stack: Stack,
|
||||||
pub keyboard: Keyboard,
|
pub keyboard: Keyboard,
|
||||||
pub screen: Screen,
|
pub screen: Screen,
|
||||||
|
pub speaker: Speaker,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Chip8 {
|
impl Chip8 {
|
||||||
pub fn new() -> Chip8 {
|
pub fn new(audio_subsystem: &AudioSubsystem) -> Chip8 {
|
||||||
Chip8 {
|
Chip8 {
|
||||||
memory: Memory::new(),
|
memory: Memory::new(),
|
||||||
registers: Registers::new(),
|
registers: Registers::new(),
|
||||||
stack: Stack::new(),
|
stack: Stack::new(),
|
||||||
keyboard: Keyboard::new(),
|
keyboard: Keyboard::new(),
|
||||||
screen: Screen::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);
|
let delay_timer = self.registers.get(Register::DT);
|
||||||
if delay_timer > 0 {
|
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);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub mod audio;
|
||||||
pub mod display;
|
pub mod display;
|
||||||
pub mod emulator;
|
pub mod emulator;
|
||||||
pub mod keyboard;
|
pub mod keyboard;
|
||||||
|
|
13
src/main.rs
13
src/main.rs
|
@ -11,13 +11,15 @@ use sdl2::rect::Rect;
|
||||||
const EMULATOR_WINDOW_TITLE: &str = "Rust CHIP-8";
|
const EMULATOR_WINDOW_TITLE: &str = "Rust CHIP-8";
|
||||||
|
|
||||||
fn main() -> Result<(), String> {
|
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(24, 13, chip8.memory.read(20, 5));
|
||||||
chip8.screen.draw_sprite(29, 13, chip8.memory.read(10, 5));
|
chip8.screen.draw_sprite(29, 13, chip8.memory.read(10, 5));
|
||||||
chip8.screen.draw_sprite(34, 13, chip8.memory.read(40, 5));
|
chip8.screen.draw_sprite(34, 13, chip8.memory.read(40, 5));
|
||||||
|
chip8.registers.set(chip8::registers::Register::ST, 5);
|
||||||
let sdl_context = sdl2::init()?;
|
|
||||||
let video_subsystem = sdl_context.video()?;
|
|
||||||
|
|
||||||
let window = video_subsystem
|
let window = video_subsystem
|
||||||
.window(
|
.window(
|
||||||
|
@ -85,7 +87,8 @@ fn main() -> Result<(), String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.present();
|
canvas.present();
|
||||||
chip8.delay_if_necessary();
|
chip8.handle_delay_timer();
|
||||||
|
chip8.handle_sound_timer();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in New Issue