[aud] Add audio subsystem
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
.idea
|
.idea
|
||||||
/target
|
/target
|
||||||
|
/roms
|
||||||
|
@@ -14,10 +14,10 @@ Screenshot program author: [Javamannen](https://esolangs.org/wiki/User:Javamanne
|
|||||||
- [X] Outer loop - 60fps display loop
|
- [X] Outer loop - 60fps display loop
|
||||||
- [X] Display adapter
|
- [X] Display adapter
|
||||||
- [X] SDL2 adapter
|
- [X] SDL2 adapter
|
||||||
- [ ] Keyboard
|
- [X] Keyboard
|
||||||
- [ ] Audio
|
- [X] Audio
|
||||||
- [ ] Load/Save memory
|
- [ ] Load/Save memory
|
||||||
- [ ] Load a ROM
|
- [X] Load a ROM
|
||||||
|
|
||||||
## Usage instructions
|
## Usage instructions
|
||||||
|
|
||||||
|
@@ -0,0 +1,48 @@
|
|||||||
|
use sdl2::audio::AudioQueue;
|
||||||
|
|
||||||
|
use crate::emu::memory::RamMemory;
|
||||||
|
use crate::misc::endian::read_big_endian_u16;
|
||||||
|
use crate::misc::error::DeviceType::AUDIO;
|
||||||
|
use crate::misc::error::EmulatorError;
|
||||||
|
use crate::misc::result::EmulatorResult;
|
||||||
|
|
||||||
|
pub const AUDIO_BUFFER_SIZE: usize = 256;
|
||||||
|
|
||||||
|
|
||||||
|
pub struct AudioProcessor<'a> {
|
||||||
|
ram: &'a RamMemory,
|
||||||
|
frame_buffer: Box<[u8; AUDIO_BUFFER_SIZE]>,
|
||||||
|
audio_queue: &'a AudioQueue<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> AudioProcessor<'a> {
|
||||||
|
pub fn try_new(ram: &'a RamMemory, audio_queue: &'a AudioQueue<u8>) -> EmulatorResult<AudioProcessor<'a>> {
|
||||||
|
let frame_buffer = vec![0u8; AUDIO_BUFFER_SIZE].into_boxed_slice()
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| {
|
||||||
|
EmulatorError::AllocationFailure(AUDIO, "Failed to allocate graphics")
|
||||||
|
})?;
|
||||||
|
Ok(AudioProcessor {
|
||||||
|
ram,
|
||||||
|
audio_queue,
|
||||||
|
frame_buffer,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> AudioProcessor<'a> {
|
||||||
|
pub fn queue(&mut self) -> EmulatorResult<()> {
|
||||||
|
let audio_base_reg = (self.get_audio_base_reg() as u32) << 8;
|
||||||
|
let fb = self.frame_buffer.as_mut();
|
||||||
|
if self.audio_queue.size() == 0 {
|
||||||
|
log::warn!("Detected Queue empty!");
|
||||||
|
}
|
||||||
|
self.ram.try_copy_block(audio_base_reg, fb)?;
|
||||||
|
self.audio_queue.queue_audio(fb).map_err(|s| { EmulatorError::OtherError(Some(AUDIO), s) })
|
||||||
|
}
|
||||||
|
fn get_audio_base_reg(&self) -> u16 {
|
||||||
|
let data = self.ram.get_data_ref();
|
||||||
|
let audio_base_reg = data.get(6..8).unwrap();
|
||||||
|
read_big_endian_u16(audio_base_reg.try_into().unwrap())
|
||||||
|
}
|
||||||
|
}
|
20
src/main.rs
20
src/main.rs
@@ -2,6 +2,7 @@ use std::fs::File;
|
|||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use sdl2::audio::{AudioQueue, AudioSpecDesired};
|
||||||
use sdl2::event::Event;
|
use sdl2::event::Event;
|
||||||
use sdl2::EventPump;
|
use sdl2::EventPump;
|
||||||
use sdl2::keyboard::Keycode;
|
use sdl2::keyboard::Keycode;
|
||||||
@@ -9,6 +10,7 @@ use sdl2::pixels::Color;
|
|||||||
use sdl2::render::{BlendMode, WindowCanvas};
|
use sdl2::render::{BlendMode, WindowCanvas};
|
||||||
use simple_logger::SimpleLogger;
|
use simple_logger::SimpleLogger;
|
||||||
use crate::args::BytePusherArgs;
|
use crate::args::BytePusherArgs;
|
||||||
|
use crate::emu::audio::AudioProcessor;
|
||||||
use crate::emu::cpu::Cpu;
|
use crate::emu::cpu::Cpu;
|
||||||
use crate::emu::graphics::GraphicsProcessor;
|
use crate::emu::graphics::GraphicsProcessor;
|
||||||
use crate::emu::keyboard::Keyboard;
|
use crate::emu::keyboard::Keyboard;
|
||||||
@@ -30,11 +32,12 @@ fn main() -> EmulatorResult<()> {
|
|||||||
let (file_bytes, x) = try_load_rom(&file_name)?;
|
let (file_bytes, x) = try_load_rom(&file_name)?;
|
||||||
assert!(x < MEM_LENGTH);
|
assert!(x < MEM_LENGTH);
|
||||||
|
|
||||||
let (mut canvas, mut event_pump) = initiate_sdl();
|
let (mut canvas, mut event_pump, mut audio_queue) = initiate_sdl();
|
||||||
|
|
||||||
|
|
||||||
let ram = RamMemory::try_from(file_bytes.as_slice())?;
|
let ram = RamMemory::try_from(file_bytes.as_slice())?;
|
||||||
let graphics_processor = GraphicsProcessor::try_new(&ram)?;
|
let graphics_processor = GraphicsProcessor::try_new(&ram)?;
|
||||||
|
let mut audio_processor = AudioProcessor::try_new(&ram,&audio_queue)?;
|
||||||
let mut keyboard = Keyboard::new(&ram);
|
let mut keyboard = Keyboard::new(&ram);
|
||||||
let cpu = Cpu::new(&ram, &graphics_processor);
|
let cpu = Cpu::new(&ram, &graphics_processor);
|
||||||
|
|
||||||
@@ -70,6 +73,7 @@ fn main() -> EmulatorResult<()> {
|
|||||||
// draw graphics
|
// draw graphics
|
||||||
sdl2_graphics_adapter.draw(&mut canvas)?;
|
sdl2_graphics_adapter.draw(&mut canvas)?;
|
||||||
// TODO render audio
|
// TODO render audio
|
||||||
|
audio_processor.queue()?;
|
||||||
|
|
||||||
canvas.present();
|
canvas.present();
|
||||||
|
|
||||||
@@ -115,12 +119,22 @@ fn try_load_rom(file_name_option: &Option<String>) -> EmulatorResult<(Vec<u8>, u
|
|||||||
Ok((file_bytes, bytes_read))
|
Ok((file_bytes, bytes_read))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initiate_sdl() -> (WindowCanvas, EventPump) {
|
fn initiate_sdl() -> (WindowCanvas, EventPump, AudioQueue<u8>) {
|
||||||
const BASE_RESOLUTION: u32 = 256;
|
const BASE_RESOLUTION: u32 = 256;
|
||||||
const DRAW_FACTOR: u32 = 4;
|
const DRAW_FACTOR: u32 = 4;
|
||||||
const WINDOW_RESOLUTION: u32 = BASE_RESOLUTION * DRAW_FACTOR;
|
const WINDOW_RESOLUTION: u32 = BASE_RESOLUTION * DRAW_FACTOR;
|
||||||
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();
|
||||||
|
// TODO audio subsystem
|
||||||
|
let audio_subsystem = sdl_context.audio().unwrap();
|
||||||
|
let wanted_spec = AudioSpecDesired{
|
||||||
|
channels: Some(1),
|
||||||
|
samples: Some(256),
|
||||||
|
freq: Some(15360),
|
||||||
|
};
|
||||||
|
let audio_queue = audio_subsystem.open_queue::<u8,_>(None, &wanted_spec).unwrap();
|
||||||
|
audio_queue.resume();
|
||||||
|
|
||||||
|
|
||||||
let window = video_subsystem.window("byte-pusher-emu", WINDOW_RESOLUTION, WINDOW_RESOLUTION)
|
let window = video_subsystem.window("byte-pusher-emu", WINDOW_RESOLUTION, WINDOW_RESOLUTION)
|
||||||
.position_centered()
|
.position_centered()
|
||||||
@@ -136,5 +150,5 @@ fn initiate_sdl() -> (WindowCanvas, EventPump) {
|
|||||||
canvas.set_blend_mode(BlendMode::None);
|
canvas.set_blend_mode(BlendMode::None);
|
||||||
canvas.present();
|
canvas.present();
|
||||||
let event_pump = sdl_context.event_pump().unwrap();
|
let event_pump = sdl_context.event_pump().unwrap();
|
||||||
(canvas, event_pump)
|
(canvas, event_pump, audio_queue)
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,7 @@ pub enum EmulatorError {
|
|||||||
AllocationFailure(DeviceType, &'static str),
|
AllocationFailure(DeviceType, &'static str),
|
||||||
UnreachableMemory(DeviceType, u32),
|
UnreachableMemory(DeviceType, u32),
|
||||||
EmulatorIOError(Error),
|
EmulatorIOError(Error),
|
||||||
|
OtherError(Option<DeviceType>,String)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TryFromSliceError> for EmulatorError {
|
impl From<TryFromSliceError> for EmulatorError {
|
||||||
|
Reference in New Issue
Block a user