Add 3 additional audio channels for a total of 4

This commit is contained in:
Ry 2022-08-09 01:37:21 -07:00
parent 881b9c1620
commit ad6f402179
3 changed files with 124 additions and 54 deletions

View File

@ -1,17 +1,70 @@
// audio.rs
pub struct Audio {
pub current_buffer_is_0: bool,
use crate::Interrupt;
use crate::memory::Memory;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::Sender;
use std::{thread, time};
use rodio::{OutputStream, buffer::SamplesBuffer, Sink};
const AUDIO_BUFFER_0_ADDRESS: usize = 0x0212C000;
const AUDIO_BUFFER_1_ADDRESS: usize = 0x02134000;
const AUDIO_BUFFER_2_ADDRESS: usize = 0x02290000;
const AUDIO_BUFFER_3_ADDRESS: usize = 0x02298000;
const AUDIO_BUFFER_SIZE: usize = 0x8000;
const AUDIO_CHANNEL_0_INTERRUPT: u8 = 0xFE;
const AUDIO_CHANNEL_1_INTERRUPT: u8 = 0xFD;
const AUDIO_CHANNEL_2_INTERRUPT: u8 = 0xFC;
const AUDIO_CHANNEL_3_INTERRUPT: u8 = 0xFB;
pub struct AudioChannel {
pub id: u8,
pub playing: bool,
pub sample_rate: u32,
}
impl Audio {
pub fn new() -> Self {
Audio {
current_buffer_is_0: true,
impl AudioChannel {
pub fn new(id: u8) -> Self {
AudioChannel {
id,
playing: false,
sample_rate: 0,
}
}
// this is terrible
pub fn spawn_thread(this: Arc<Mutex<Self>>, interrupt_sender: Sender<Interrupt>, memory: Memory) {
let (audio_buffer_address, audio_channel_interrupt) = match this.lock().unwrap().id {
0 => (AUDIO_BUFFER_0_ADDRESS, AUDIO_CHANNEL_0_INTERRUPT),
1 => (AUDIO_BUFFER_1_ADDRESS, AUDIO_CHANNEL_1_INTERRUPT),
2 => (AUDIO_BUFFER_2_ADDRESS, AUDIO_CHANNEL_2_INTERRUPT),
3 => (AUDIO_BUFFER_3_ADDRESS, AUDIO_CHANNEL_3_INTERRUPT),
_ => unreachable!(),
};
let builder = thread::Builder::new().name("audio".to_string());
builder.spawn({
move || {
let (_stream, stream_handle) = OutputStream::try_default().unwrap();
let channel = Sink::try_new(&stream_handle).unwrap();
loop {
// every `sleep` number of ms, play what is in the audio buffer
let self_lock = this.lock().unwrap();
if self_lock.playing {
let audio_buffer: Vec<i16> = memory.ram()[audio_buffer_address..audio_buffer_address+AUDIO_BUFFER_SIZE]
.to_vec()
.chunks_exact(2)
.map(|x| ((x[1] as i16) << 8) | x[0] as i16)
.collect();
// 1 Hz = 1000 ms
let sleep: f32 = (1000 as f32 / self_lock.sample_rate as f32) * (AUDIO_BUFFER_SIZE as f32 / 2.0);
channel.append(SamplesBuffer::new(1, self_lock.sample_rate, audio_buffer));
interrupt_sender.send(Interrupt::Request(audio_channel_interrupt)).unwrap();
thread::sleep(time::Duration::from_millis(sleep as u64));
}
}
}
}).unwrap();
}
}

View File

@ -1,6 +1,6 @@
// bus.rs
use crate::{Memory, Audio, DiskController, Keyboard, Mouse, Overlay};
use crate::{Memory, AudioChannel, DiskController, Keyboard, Mouse, Overlay};
use std::sync::{Arc, Mutex};
use std::io::{Write, stdout};
@ -10,7 +10,10 @@ pub struct Bus {
pub disk_controller: DiskController,
pub audio: Arc<Mutex<Audio>>,
pub audio_channel_0: Arc<Mutex<AudioChannel>>,
pub audio_channel_1: Arc<Mutex<AudioChannel>>,
pub audio_channel_2: Arc<Mutex<AudioChannel>>,
pub audio_channel_3: Arc<Mutex<AudioChannel>>,
pub keyboard: Arc<Mutex<Keyboard>>,
pub mouse: Arc<Mutex<Mouse>>,
@ -84,9 +87,27 @@ impl Bus {
let mut keyboard_lock = self.keyboard.lock().expect("failed to lock the keyboard mutex");
keyboard_lock.pop() as u32
}
0x80000600 => { // audio port
let audio_lock = self.audio.lock().unwrap();
audio_lock.playing as u32
0x80000600..=0x80000603 => { // audio port
let channel = (port & 0x000000FF) as u8;
match channel {
0 => {
let audio_lock = self.audio_channel_0.lock().unwrap();
audio_lock.sample_rate
},
1 => {
let audio_lock = self.audio_channel_1.lock().unwrap();
audio_lock.sample_rate
},
2 => {
let audio_lock = self.audio_channel_2.lock().unwrap();
audio_lock.sample_rate
},
3 => {
let audio_lock = self.audio_channel_3.lock().unwrap();
audio_lock.sample_rate
},
_ => panic!("invalid audio channel"),
}
}
0x80001000..=0x80002003 => { // disk controller port
let id = port as u8;
@ -171,11 +192,31 @@ impl Bus {
_ => panic!("invalid mouse control port"),
}
}
0x80000600 => { // audio port
let mut audio_lock = self.audio.lock().unwrap();
0x80000600..=0x80000603 => { // audio port
let channel = (port & 0x000000FF) as u8;
match channel {
0 => {
let mut audio_lock = self.audio_channel_0.lock().unwrap();
audio_lock.playing = word != 0;
audio_lock.sample_rate = word;
audio_lock.current_buffer_is_0 = false; // the first buffer refill interrupt will invert this to true
},
1 => {
let mut audio_lock = self.audio_channel_1.lock().unwrap();
audio_lock.playing = word != 0;
audio_lock.sample_rate = word;
},
2 => {
let mut audio_lock = self.audio_channel_2.lock().unwrap();
audio_lock.playing = word != 0;
audio_lock.sample_rate = word;
},
3 => {
let mut audio_lock = self.audio_channel_3.lock().unwrap();
audio_lock.playing = word != 0;
audio_lock.sample_rate = word;
},
_ => panic!("invalid audio channel"),
};
}
0x80001000..=0x80005003 => { // disk controller port
let id = port as u8;

View File

@ -8,7 +8,7 @@ pub mod keyboard;
pub mod mouse;
pub mod disk;
use audio::Audio;
use audio::AudioChannel;
use bus::Bus;
use cpu::{Cpu, Interrupt};
use keyboard::Keyboard;
@ -18,7 +18,6 @@ use memory::{MEMORY_RAM_START, MEMORY_ROM_START, MemoryRam, Memory};
use std::sync::{Arc, mpsc, Mutex};
use std::thread;
use std::time;
use std::process::exit;
use std::env;
use std::fs::{File, read};
@ -26,7 +25,6 @@ use std::fs::{File, read};
use image;
use log::error;
use pixels::{Pixels, SurfaceTexture};
use rodio::{OutputStream, buffer::SamplesBuffer, Sink};
use winit::dpi::LogicalSize;
use winit::event::{ElementState, Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
@ -37,9 +35,6 @@ const WIDTH: usize = 640;
const HEIGHT: usize = 480;
const FRAMEBUFFER_ADDRESS: usize = 0x02000000;
const AUDIO_BUFFER_0_ADDRESS: usize = 0x0212C000;
const AUDIO_BUFFER_1_ADDRESS: usize = 0x02134000;
const AUDIO_BUFFER_SIZE: usize = 0x8000;
pub struct Display {
background: Vec<u8>,
@ -84,12 +79,18 @@ fn main() {
let keyboard = Arc::new(Mutex::new(Keyboard::new()));
let mouse = Arc::new(Mutex::new(Mouse::new()));
let audio = Arc::new(Mutex::new(Audio::new()));
let audio_channel_0 = Arc::new(Mutex::new(AudioChannel::new(0)));
let audio_channel_1 = Arc::new(Mutex::new(AudioChannel::new(1)));
let audio_channel_2 = Arc::new(Mutex::new(AudioChannel::new(2)));
let audio_channel_3 = Arc::new(Mutex::new(AudioChannel::new(3)));
let memory = Memory::new(read_rom().as_slice());
let mut bus = Bus {
memory: memory.clone(),
audio: audio.clone(),
audio_channel_0: audio_channel_0.clone(),
audio_channel_1: audio_channel_1.clone(),
audio_channel_2: audio_channel_2.clone(),
audio_channel_3: audio_channel_3.clone(),
disk_controller: DiskController::new(),
keyboard: keyboard.clone(),
mouse: mouse.clone(),
@ -104,7 +105,6 @@ fn main() {
}
}
let memory_audio = memory.clone();
let memory_cpu = memory.clone();
let memory_eventloop = memory.clone();
@ -145,6 +145,11 @@ fn main() {
let (interrupt_sender, interrupt_receiver) = mpsc::channel::<Interrupt>();
let (exit_sender, exit_receiver) = mpsc::channel::<bool>();
AudioChannel::spawn_thread(audio_channel_0, interrupt_sender.clone(), memory.clone());
AudioChannel::spawn_thread(audio_channel_1, interrupt_sender.clone(), memory.clone());
AudioChannel::spawn_thread(audio_channel_2, interrupt_sender.clone(), memory.clone());
AudioChannel::spawn_thread(audio_channel_3, interrupt_sender.clone(), memory.clone());
let builder = thread::Builder::new().name("cpu".to_string());
builder.spawn({
move || {
@ -180,35 +185,6 @@ fn main() {
}
}).unwrap();
let interrupt_sender_audio = interrupt_sender.clone();
let builder = thread::Builder::new().name("audio".to_string());
builder.spawn({
move || {
let (_stream, stream_handle) = OutputStream::try_default().unwrap();
let sink = Sink::try_new(&stream_handle).unwrap();
loop {
// every `sleep` number of ms, play what is in the audio buffer and tell fox32 to swap them
let mut audio_lock = audio.lock().unwrap();
if audio_lock.playing {
let current_buffer: Vec<i16> = if audio_lock.current_buffer_is_0 {
audio_lock.current_buffer_is_0 = false;
memory_audio.ram()[AUDIO_BUFFER_0_ADDRESS..AUDIO_BUFFER_0_ADDRESS+AUDIO_BUFFER_SIZE].to_vec().chunks_exact(2).map(|x| ((x[1] as i16) << 8) | x[0] as i16).collect()
} else {
audio_lock.current_buffer_is_0 = true;
memory_audio.ram()[AUDIO_BUFFER_1_ADDRESS..AUDIO_BUFFER_1_ADDRESS+AUDIO_BUFFER_SIZE].to_vec().chunks_exact(2).map(|x| ((x[1] as i16) << 8) | x[0] as i16).collect()
};
let buffer = SamplesBuffer::new(1, audio_lock.sample_rate, current_buffer);
// 1 Hz = 1000 ms
let sleep: f32 = (1000 as f32 / audio_lock.sample_rate as f32) * (AUDIO_BUFFER_SIZE as f32 / 2.0);
sink.append(buffer);
drop(audio_lock);
interrupt_sender_audio.send(Interrupt::Request(0xFE)).unwrap(); // audio interrupt, swap audio buffers
thread::sleep(time::Duration::from_millis(sleep as u64));
}
}
}
}).unwrap();
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Poll;