its getting there

This commit is contained in:
Alex Janka 2023-02-16 15:03:07 +11:00
parent 0d48a58525
commit ffdd458fbb
5 changed files with 269 additions and 103 deletions

View file

@ -1,4 +1,4 @@
#![feature(exclusive_range_pattern, let_chains)]
#![feature(exclusive_range_pattern, let_chains, slice_flatten)]
mod processor;
mod util;

View file

@ -31,6 +31,8 @@ pub struct Memory {
impl Memory {
pub fn init(bootrom: Vec<u8>, bootrom_enabled: bool, rom: Rom) -> Self {
let mut apu = Apu::default();
apu.init();
Self {
bootrom,
bootrom_enabled,
@ -46,7 +48,7 @@ impl Memory {
io: [0xFF; 76],
user_mode: false,
joypad: Joypad::default(),
apu: Apu::default(),
apu,
}
}

View file

@ -1,4 +1,4 @@
use std::sync::RwLock;
use std::sync::mpsc::{channel, Sender};
use crate::{
processor::{
@ -10,7 +10,7 @@ use crate::{
};
use cpal::{
traits::{DeviceTrait, HostTrait, StreamTrait},
Stream,
Device, Stream, StreamConfig,
};
use samplerate::{ConverterType, Samplerate};
@ -35,10 +35,10 @@ struct Channels {
impl Default for Channels {
fn default() -> Self {
Self {
one: PwmChannel::new(true, true, true),
two: PwmChannel::new(false, true, true),
three: WaveChannel::new(false, true, false),
four: NoiseChannel::new(false, true, false),
one: PwmChannel::new(true),
two: PwmChannel::new(false),
three: WaveChannel::new(false),
four: NoiseChannel::new(false),
}
}
}
@ -49,20 +49,120 @@ struct VinEnable {
right: bool,
}
enum Volume {
Muted,
Enabled,
}
impl Volume {
fn scale(&self) -> f32 {
match self {
Volume::Muted => 0.,
Volume::Enabled => 1.,
}
}
fn bool(&self) -> bool {
match self {
Volume::Muted => false,
Volume::Enabled => true,
}
}
fn from_bool(val: bool) -> Self {
if val {
Self::Enabled
} else {
Self::Muted
}
}
}
struct ChannelVol {
left: Volume,
right: Volume,
}
impl Default for ChannelVol {
fn default() -> Self {
Self {
left: Volume::Muted,
right: Volume::Muted,
}
}
}
struct Mixer {
vol_left: u8,
vol_right: u8,
ch1: ChannelVol,
ch2: ChannelVol,
ch3: ChannelVol,
ch4: ChannelVol,
}
impl Default for Mixer {
fn default() -> Self {
Self {
vol_left: 7,
vol_right: 7,
ch1: Default::default(),
ch2: Default::default(),
ch3: Default::default(),
ch4: Default::default(),
}
}
}
// impl Mixer {
// fn mix(&self, sample: DacSample) -> [f32; 2] {
// sample.mixed(self.vol_left, self.vol_right)
// }
// }
#[derive(Clone, Copy)]
struct DacSample {
one: f32,
two: f32,
}
impl Default for DacSample {
fn default() -> Self {
Self { one: 0., two: 0. }
}
}
impl DacSample {
fn mixed(&self, mixer: &Mixer) -> [f32; 2] {
let left = (self.one * mixer.ch1.left.scale()) + (self.two * mixer.ch2.left.scale());
let right = (self.one * mixer.ch1.right.scale()) + (self.two * mixer.ch2.right.scale());
[
self.mix_channel(left, mixer.vol_left),
self.mix_channel(right, mixer.vol_right),
]
}
fn mix_channel(&self, sums: f32, volume: u8) -> f32 {
sums * ((volume + 1) as f32 / (8. * 4.))
}
}
pub struct Apu {
mem: [u8; MEM_SIZE],
apu_enable: bool,
channels: Channels,
vin: VinEnable,
vol_left: u8,
vol_right: u8,
mixer: Mixer,
div_apu: u8,
buffer: Vec<f32>,
converter: Samplerate,
_stream: Stream,
buffer: Vec<DacSample>,
// converter: Samplerate,
device: Device,
config: StreamConfig,
stream: Option<Stream>,
send_buffer: Option<Sender<Vec<[f32; 2]>>>,
}
static PLAY_BUFFER: RwLock<Vec<f32>> = RwLock::new(vec![]);
// const TARGET_SAMPLERATE: u32 = 192000;
impl Default for Apu {
fn default() -> Self {
@ -81,56 +181,97 @@ impl Default for Apu {
.with_max_sample_rate()
.config();
let stream = device
.build_output_stream(
&config,
move |data: &mut [f32], _info: &cpal::OutputCallbackInfo| {
// react to stream events and read or write stream data here.
if let Ok(mut audio) = PLAY_BUFFER.try_write() {
if audio.len() >= data.len() {
let b = audio.split_off(data.len());
data.copy_from_slice(&audio);
*audio = b;
}
}
},
move |err| {
// react to errors here.
println!("audio error: {err}");
},
None, // None=blocking, Some(Duration)=timeout
)
.unwrap();
stream.play().unwrap();
// config.buffer_size = BufferSize::Fixed(2048 * 2);
let converter = Samplerate::new(
ConverterType::Linear,
CLOCK_SPEED as u32,
config.sample_rate.0,
1,
)
.unwrap();
// let converter = Samplerate::new(
// ConverterType::Linear,
// TARGET_SAMPLERATE,
// config.sample_rate.0,
// 2,
// )
// .unwrap();
Self {
mem: [0x0; MEM_SIZE],
apu_enable: true,
channels: Channels::default(),
vin: VinEnable::default(),
vol_left: 7,
vol_right: 7,
mixer: Mixer::default(),
div_apu: 0,
buffer: vec![],
converter,
_stream: stream,
// converter,
device,
config,
stream: None,
send_buffer: None,
}
}
}
const SCALE: u32 = 4;
impl Apu {
pub fn init(&mut self) {
let sample_rate = self.config.sample_rate.0;
let ratio = (CLOCK_SPEED as f32) / ((sample_rate as f32) * 4.);
let (tx, rx) = channel::<Vec<[f32; 2]>>();
let other = tx.clone();
self.send_buffer = Some(tx);
let stream = self
.device
.build_output_stream(
&self.config,
move |data: &mut [f32], _info: &cpal::OutputCallbackInfo| {
let buf_length = data.len() / 2;
let gbspeed_buf_length = (ratio * (buf_length as f32)) as usize;
let mut audio = vec![];
while let Ok(mut e) = rx.recv() {
audio.append(&mut e);
if audio.len() >= gbspeed_buf_length {
break;
}
}
other.send(audio.split_off(gbspeed_buf_length)).unwrap();
let target = sample_rate * SCALE;
let converter =
Samplerate::new(ConverterType::Linear, target, sample_rate, 2).unwrap();
let naive_buf_length = buf_length * (SCALE as usize);
let mut downsampled = vec![[0.; 2]; naive_buf_length];
let target_step = audio.len() as f64 / naive_buf_length as f64;
let mut index = 0.;
for val in &mut downsampled {
(*val).clone_from(&audio[index as usize]);
index += target_step;
}
data.copy_from_slice(
&converter
.process(&downsampled.into_iter().flatten().collect::<Vec<_>>())
.unwrap(),
);
},
move |err| {
// react to errors here.
println!("audio error: {err}");
},
None,
)
.unwrap();
stream.play().unwrap();
self.stream = Some(stream);
}
pub fn div_apu_tick(&mut self) {
self.div_apu = self.div_apu.wrapping_add(1);
if self.div_apu % 8 == 0 {
// envelope sweep
self.channels.one.envelope_tick();
}
if self.div_apu % 4 == 0 {
// ch1 frequency sweep
@ -148,15 +289,20 @@ impl Apu {
.tick(steps)
.into_iter()
.zip(self.channels.two.tick(steps).into_iter())
.map(|(one, two)| (one + two) / 2.)
.map(|(one, two)| DacSample { one, two })
.collect(),
);
}
fn next_audio(&mut self) {
if let Ok(mut audio) = PLAY_BUFFER.try_write() {
audio.append(&mut self.converter.process(&self.buffer).unwrap());
self.buffer.clear();
if let Some(send) = &self.send_buffer {
send.send(
self.buffer
.drain(..)
.map(|v| v.mixed(&self.mixer))
.collect(),
)
.unwrap();
}
}
@ -185,7 +331,8 @@ impl Apu {
0xFF19 => self.channels.two.get_control(),
0xFF24 => {
// NR50 - Master volume + VIN panning
let mut v = ((self.vol_left << 4) & 0b1110000) | (self.vol_right & 0b111);
let mut v =
((self.mixer.vol_left << 4) & 0b1110000) | (self.mixer.vol_right & 0b111);
v = set_or_clear_bit(v, 7, self.vin.left);
v = set_or_clear_bit(v, 3, self.vin.right);
v
@ -193,14 +340,14 @@ impl Apu {
0xFF25 => {
// NR51 - Panning
let mut v = 0;
v = set_or_clear_bit(v, 0, self.channels.one.pan_right);
v = set_or_clear_bit(v, 1, self.channels.two.pan_right);
v = set_or_clear_bit(v, 2, self.channels.three.pan_right);
v = set_or_clear_bit(v, 3, self.channels.four.pan_right);
v = set_or_clear_bit(v, 4, self.channels.one.pan_left);
v = set_or_clear_bit(v, 5, self.channels.two.pan_left);
v = set_or_clear_bit(v, 6, self.channels.three.pan_left);
v = set_or_clear_bit(v, 7, self.channels.four.pan_left);
v = set_or_clear_bit(v, 0, self.mixer.ch1.right.bool());
v = set_or_clear_bit(v, 1, self.mixer.ch2.right.bool());
v = set_or_clear_bit(v, 2, self.mixer.ch3.right.bool());
v = set_or_clear_bit(v, 3, self.mixer.ch4.right.bool());
v = set_or_clear_bit(v, 4, self.mixer.ch1.left.bool());
v = set_or_clear_bit(v, 5, self.mixer.ch2.left.bool());
v = set_or_clear_bit(v, 6, self.mixer.ch3.left.bool());
v = set_or_clear_bit(v, 7, self.mixer.ch4.left.bool());
v
}
0xFF26 => {
@ -250,18 +397,18 @@ impl Apu {
0xFF24 => {
self.vin.left = get_bit(data, 7);
self.vin.right = get_bit(data, 3);
self.vol_left = (data & 0b1110000) >> 4;
self.vol_right = data & 0b111;
self.mixer.vol_left = (data & 0b1110000) >> 4;
self.mixer.vol_right = data & 0b111;
}
0xFF25 => {
self.channels.one.pan_right = get_bit(data, 0);
self.channels.two.pan_right = get_bit(data, 1);
self.channels.three.pan_right = get_bit(data, 2);
self.channels.four.pan_right = get_bit(data, 3);
self.channels.one.pan_left = get_bit(data, 4);
self.channels.two.pan_left = get_bit(data, 5);
self.channels.three.pan_left = get_bit(data, 6);
self.channels.four.pan_left = get_bit(data, 7);
self.mixer.ch1.right = Volume::from_bool(get_bit(data, 0));
self.mixer.ch2.right = Volume::from_bool(get_bit(data, 1));
self.mixer.ch3.right = Volume::from_bool(get_bit(data, 2));
self.mixer.ch4.right = Volume::from_bool(get_bit(data, 3));
self.mixer.ch1.left = Volume::from_bool(get_bit(data, 4));
self.mixer.ch2.left = Volume::from_bool(get_bit(data, 5));
self.mixer.ch3.left = Volume::from_bool(get_bit(data, 6));
self.mixer.ch4.left = Volume::from_bool(get_bit(data, 7));
}
0xFF26 => self.apu_enable = (1 << 7) == (data & 0b10000000),
0xFF11..0xFF1A | 0xFF1B | 0xFF1D..0xFF23 | 0xFF24..0xFF40 => self.mem[reg(addr)] = data,

View file

@ -25,17 +25,45 @@ impl Default for Sweep {
#[derive(Clone, Copy, PartialEq)]
struct Envelope {
initial_volume: u8,
current_volume: u8,
mode: EnvelopeMode,
rate: u8,
counter: u8,
}
impl Envelope {
fn new(initial_volume: u8, mode: EnvelopeMode, rate: u8) -> Self {
Self {
initial_volume,
current_volume: initial_volume,
mode,
rate,
counter: 0,
}
}
fn tick(&mut self) {
if self.rate == 0 {
return;
}
self.counter += 1;
if self.counter % self.rate == 0 {
self.counter = 0;
match self.mode {
EnvelopeMode::Increase => {
self.current_volume = self.current_volume.saturating_add(1)
}
EnvelopeMode::Decrease => {
self.current_volume = self.current_volume.saturating_sub(1)
}
}
}
}
}
impl Default for Envelope {
fn default() -> Self {
Self {
initial_volume: 0xF,
mode: EnvelopeMode::Decrease,
rate: 0x3,
}
Self::new(0x0, EnvelopeMode::Decrease, 0x0)
// Self::new(0xF, EnvelopeMode::Decrease, 0x3)
}
}
@ -84,8 +112,6 @@ impl DutyCycle {
pub(super) struct PwmChannel {
pub(super) enabled: bool,
pub(super) pan_left: bool,
pub(super) pan_right: bool,
sweep: Sweep,
duty_cycle: DutyCycle,
length_enable: bool,
@ -98,12 +124,10 @@ pub(super) struct PwmChannel {
}
impl PwmChannel {
pub(super) fn new(enabled: bool, pan_left: bool, pan_right: bool) -> Self {
pub(super) fn new(enabled: bool) -> Self {
let wavelength = 0x700;
Self {
enabled,
pan_left,
pan_right,
sweep: Sweep::default(),
duty_cycle: DutyCycle::Fifty,
length_enable: false,
@ -139,7 +163,11 @@ impl PwmChannel {
}
fn dac(&self, digital: u8) -> f32 {
((digital as f32) * (-2.)) + 1.
(((digital as f32) * (-2.)) + 1.) * ((self.envelope.current_volume as f32) / 15.)
}
pub(super) fn envelope_tick(&mut self) {
self.envelope.tick();
}
pub(super) fn update_sweep(&mut self, pace: u8, mode: EnvelopeMode, slope: u8) {
@ -166,15 +194,15 @@ impl PwmChannel {
}
pub(super) fn update_volume_and_envelope(&mut self, data: u8) {
self.queued_envelope = Envelope {
initial_volume: (data & 0b11110000) >> 4,
mode: if (data & 0b1000) == 0b1000 {
self.queued_envelope = Envelope::new(
(data & 0b11110000) >> 4,
if (data & 0b1000) == 0b1000 {
EnvelopeMode::Increase
} else {
EnvelopeMode::Decrease
},
rate: data & 0b111,
};
data & 0b111,
);
}
pub(super) fn get_volume_and_envelope(&self) -> u8 {
@ -204,37 +232,26 @@ impl PwmChannel {
}
fn set_wave_timer(wavelength: u16) -> u16 {
(2048 - wavelength) * 4
2048 - wavelength
// (2048 - wavelength) * 4
}
pub(super) struct WaveChannel {
pub(super) enabled: bool,
pub(super) pan_left: bool,
pub(super) pan_right: bool,
}
impl WaveChannel {
pub(super) fn new(enabled: bool, pan_left: bool, pan_right: bool) -> Self {
Self {
enabled,
pan_left,
pan_right,
}
pub(super) fn new(enabled: bool) -> Self {
Self { enabled }
}
}
pub(super) struct NoiseChannel {
pub(super) enabled: bool,
pub(super) pan_left: bool,
pub(super) pan_right: bool,
}
impl NoiseChannel {
pub(super) fn new(enabled: bool, pan_left: bool, pan_right: bool) -> Self {
Self {
enabled,
pan_left,
pan_right,
}
pub(super) fn new(enabled: bool) -> Self {
Self { enabled }
}
}

View file

@ -30,7 +30,7 @@ impl Cpu {
let clock_cycles = (machine_cycles as usize) * 4;
self.advance_gpu_clock(clock_cycles);
self.advance_apu_clock(clock_cycles);
self.advance_apu_clock(machine_cycles as usize);
self.timers.div_counter += clock_cycles;
let mut div_diff = (self.timers.div_counter / 256) as u8;