[aud] Use Audio queue
This commit is contained in:
@@ -20,7 +20,7 @@ Chip 8 emulator/interpreter.
|
|||||||
- [X] Timer
|
- [X] Timer
|
||||||
- [X] Super chip8 compatibility.
|
- [X] Super chip8 compatibility.
|
||||||
- [X] Audio
|
- [X] Audio
|
||||||
- Audio seems to be broken on my device. I will check with other devices.
|
- Audio seems to stutter, but working
|
||||||
- [X] Keyboard
|
- [X] Keyboard
|
||||||
|
|
||||||
### More information on CHIP-8
|
### More information on CHIP-8
|
||||||
|
@@ -43,7 +43,7 @@ impl TimerManager {
|
|||||||
*timer_lock -= 1;
|
*timer_lock -= 1;
|
||||||
}
|
}
|
||||||
if *sound_lock > 0 {
|
if *sound_lock > 0 {
|
||||||
log::info!("Beep!");
|
log::trace!("Beep!");
|
||||||
*sound_lock -= 1;
|
*sound_lock -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
25
src/main.rs
25
src/main.rs
@@ -21,7 +21,7 @@ use crate::device::Device;
|
|||||||
use crate::device::keyboard::Keyboard;
|
use crate::device::keyboard::Keyboard;
|
||||||
use crate::util::EmulatorResult;
|
use crate::util::EmulatorResult;
|
||||||
use crate::kb_map::get_key_index;
|
use crate::kb_map::get_key_index;
|
||||||
use crate::sdl_audio_adapter::SquareWave;
|
use crate::sdl_audio_adapter::SdlAudioAdapter;
|
||||||
use crate::sdl_graphics_adapter::SdlGraphicsAdapter;
|
use crate::sdl_graphics_adapter::SdlGraphicsAdapter;
|
||||||
use crate::sdl_keyboard_adapter::SdlKeyboardAdapter;
|
use crate::sdl_keyboard_adapter::SdlKeyboardAdapter;
|
||||||
|
|
||||||
@@ -41,9 +41,11 @@ fn main() -> EmulatorResult<()> {
|
|||||||
let mut timer = TimerManager::new();
|
let mut timer = TimerManager::new();
|
||||||
|
|
||||||
|
|
||||||
let audio_state = timer.start();
|
let (mut canvas, mut event_pump,audio_queue) = try_initiate_sdl(draw_scale)?;
|
||||||
let (mut canvas, mut event_pump) = try_initiate_sdl(audio_state,draw_scale)?;
|
|
||||||
|
|
||||||
|
let audio_state = timer.start();
|
||||||
|
|
||||||
|
let mut sdl_aud_adapter = SdlAudioAdapter::new(audio_state,440.0,0.5,audio_queue);
|
||||||
|
|
||||||
|
|
||||||
let (frame_buffer_for_display, frame_buffer_for_device) = get_frame_buffer_references();
|
let (frame_buffer_for_display, frame_buffer_for_device) = get_frame_buffer_references();
|
||||||
@@ -91,7 +93,7 @@ fn main() -> EmulatorResult<()> {
|
|||||||
sdl_graphics_adapter.draw_screen(lock, &mut canvas)?;
|
sdl_graphics_adapter.draw_screen(lock, &mut canvas)?;
|
||||||
}
|
}
|
||||||
canvas.present();
|
canvas.present();
|
||||||
|
sdl_aud_adapter.process_push_audio()?;
|
||||||
// 60fps - small offset to consider for cpu cycle time
|
// 60fps - small offset to consider for cpu cycle time
|
||||||
thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
|
thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
|
||||||
}
|
}
|
||||||
@@ -139,22 +141,18 @@ fn load_rom(rom_file_location: String) -> [u8; ROM_SIZE] {
|
|||||||
rom_slice
|
rom_slice
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_initiate_sdl(audio_state: Arc<Mutex<u8>>, draw_scale: f32) -> EmulatorResult<(WindowCanvas, EventPump)> {
|
fn try_initiate_sdl(draw_scale: f32) -> EmulatorResult<(WindowCanvas, EventPump, AudioQueue<f32>)> {
|
||||||
let sdl_context = sdl2::init().unwrap();
|
let sdl_context = sdl2::init().unwrap();
|
||||||
let video_subsystem = sdl_context.video().unwrap();
|
let video_subsystem = sdl_context.video().unwrap();
|
||||||
let audio_subsystem = sdl_context.audio().unwrap();
|
let audio_subsystem = sdl_context.audio().unwrap();
|
||||||
let wanted_spec = AudioSpecDesired {
|
let wanted_spec = AudioSpecDesired {
|
||||||
channels: Some(1),
|
channels: Some(1),
|
||||||
samples: None,
|
samples: None,
|
||||||
freq: Some(44100),
|
freq: Some(SdlAudioAdapter::SAMPLING_FREQ),
|
||||||
};
|
};
|
||||||
|
|
||||||
let device = audio_subsystem.open_playback(None, &wanted_spec, |spec| {
|
let audio_queue = audio_subsystem.open_queue::<f32,_>(None, &wanted_spec)?;
|
||||||
// initialize the audio callback
|
|
||||||
SquareWave ::new(audio_state,440.0/spec.freq as f32,0.5)
|
|
||||||
}).unwrap();
|
|
||||||
device.resume();
|
|
||||||
|
|
||||||
let window_width = (Device::FRAME_BUFFER_WIDTH as f32 * draw_scale) as u32;
|
let window_width = (Device::FRAME_BUFFER_WIDTH as f32 * draw_scale) as u32;
|
||||||
let window_height = (Device::FRAME_BUFFER_HEIGHT as f32 * draw_scale) as u32;
|
let window_height = (Device::FRAME_BUFFER_HEIGHT as f32 * draw_scale) as u32;
|
||||||
|
|
||||||
@@ -169,8 +167,7 @@ fn try_initiate_sdl(audio_state: Arc<Mutex<u8>>, draw_scale: f32) -> EmulatorRes
|
|||||||
canvas.clear();
|
canvas.clear();
|
||||||
canvas.present();
|
canvas.present();
|
||||||
let event_pump = sdl_context.event_pump()?;
|
let event_pump = sdl_context.event_pump()?;
|
||||||
Ok((canvas, event_pump
|
Ok((canvas, event_pump,audio_queue))
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,46 +1,59 @@
|
|||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex};
|
||||||
use log::warn;
|
use sdl2::audio::AudioQueue;
|
||||||
use sdl2::audio::AudioCallback;
|
use crate::util::EmulatorResult;
|
||||||
|
|
||||||
pub struct SquareWave {
|
pub struct SdlAudioAdapter {
|
||||||
sound_timer: Arc<Mutex<u8>>,
|
sound_timer: Arc<Mutex<u8>>,
|
||||||
phase_inc: f32,
|
phase_inc: f32,
|
||||||
phase: f32,
|
phase: f32,
|
||||||
volume: f32,
|
volume: f32,
|
||||||
|
audio_queue: AudioQueue<f32>,
|
||||||
|
buf: Vec<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SquareWave {
|
/// An Audio adapter using `AudioQueue`.
|
||||||
|
impl SdlAudioAdapter {
|
||||||
|
pub const SAMPLING_FREQ:i32 = 15360;
|
||||||
|
pub const SAMPLES_PER_FRAME: usize = Self::SAMPLING_FREQ as usize / 60 + 2;
|
||||||
pub fn new(sound_timer: Arc<Mutex<u8>>,
|
pub fn new(sound_timer: Arc<Mutex<u8>>,
|
||||||
phase_inc: f32,
|
freq: f32,
|
||||||
volume: f32)->SquareWave {
|
volume: f32,
|
||||||
SquareWave {
|
audio_queue: AudioQueue<f32>) -> SdlAudioAdapter {
|
||||||
|
audio_queue.resume();
|
||||||
|
SdlAudioAdapter {
|
||||||
sound_timer,
|
sound_timer,
|
||||||
|
buf: vec![0f32; Self::SAMPLES_PER_FRAME],
|
||||||
phase: 0f32,
|
phase: 0f32,
|
||||||
phase_inc,
|
phase_inc: freq/Self::SAMPLING_FREQ as f32,
|
||||||
volume,
|
volume,
|
||||||
|
audio_queue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
pub fn process_push_audio(&mut self) -> EmulatorResult<()> {
|
||||||
|
// fill the audio vector.
|
||||||
|
let sound_timer = {
|
||||||
|
let sound_timer = self.sound_timer.lock().expect("Could not lock to play audio");
|
||||||
|
sound_timer.clone()
|
||||||
|
};
|
||||||
|
if sound_timer>0 {
|
||||||
|
self.fill_audio();
|
||||||
|
self.audio_queue.queue_audio(&self.buf)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
impl AudioCallback for SquareWave {
|
fn fill_audio(&mut self) {
|
||||||
type Channel = f32;
|
let out = &mut self.buf;
|
||||||
|
|
||||||
fn callback(&mut self, out: &mut [f32]) {
|
|
||||||
let sound_timer = self.sound_timer.lock().expect("Could not lock to play audio");
|
|
||||||
let sound_timer = sound_timer.clone();
|
|
||||||
// log::info!("Processing audio buffer length {}",out.len());
|
|
||||||
// Generate a square wave
|
// Generate a square wave
|
||||||
for x in out.iter_mut() {
|
for x in out.iter_mut() {
|
||||||
*x = if sound_timer > 0 {
|
*x = if self.phase <= 0.5 {
|
||||||
if self.phase <= 0.5 {
|
self.volume
|
||||||
self.volume
|
|
||||||
} else {
|
|
||||||
-self.volume
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
0f32
|
-self.volume
|
||||||
};
|
};
|
||||||
|
|
||||||
self.phase = (self.phase + self.phase_inc) % 1.0;
|
self.phase = (self.phase + self.phase_inc) % 1.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user