its getting there
This commit is contained in:
parent
0d48a58525
commit
ffdd458fbb
|
@ -1,4 +1,4 @@
|
|||
#![feature(exclusive_range_pattern, let_chains)]
|
||||
#![feature(exclusive_range_pattern, let_chains, slice_flatten)]
|
||||
|
||||
mod processor;
|
||||
mod util;
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue