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 processor;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
|
@ -31,6 +31,8 @@ pub struct Memory {
|
||||||
|
|
||||||
impl Memory {
|
impl Memory {
|
||||||
pub fn init(bootrom: Vec<u8>, bootrom_enabled: bool, rom: Rom) -> Self {
|
pub fn init(bootrom: Vec<u8>, bootrom_enabled: bool, rom: Rom) -> Self {
|
||||||
|
let mut apu = Apu::default();
|
||||||
|
apu.init();
|
||||||
Self {
|
Self {
|
||||||
bootrom,
|
bootrom,
|
||||||
bootrom_enabled,
|
bootrom_enabled,
|
||||||
|
@ -46,7 +48,7 @@ impl Memory {
|
||||||
io: [0xFF; 76],
|
io: [0xFF; 76],
|
||||||
user_mode: false,
|
user_mode: false,
|
||||||
joypad: Joypad::default(),
|
joypad: Joypad::default(),
|
||||||
apu: Apu::default(),
|
apu,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::sync::RwLock;
|
use std::sync::mpsc::{channel, Sender};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
processor::{
|
processor::{
|
||||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use cpal::{
|
use cpal::{
|
||||||
traits::{DeviceTrait, HostTrait, StreamTrait},
|
traits::{DeviceTrait, HostTrait, StreamTrait},
|
||||||
Stream,
|
Device, Stream, StreamConfig,
|
||||||
};
|
};
|
||||||
use samplerate::{ConverterType, Samplerate};
|
use samplerate::{ConverterType, Samplerate};
|
||||||
|
|
||||||
|
@ -35,10 +35,10 @@ struct Channels {
|
||||||
impl Default for Channels {
|
impl Default for Channels {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
one: PwmChannel::new(true, true, true),
|
one: PwmChannel::new(true),
|
||||||
two: PwmChannel::new(false, true, true),
|
two: PwmChannel::new(false),
|
||||||
three: WaveChannel::new(false, true, false),
|
three: WaveChannel::new(false),
|
||||||
four: NoiseChannel::new(false, true, false),
|
four: NoiseChannel::new(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,20 +49,120 @@ struct VinEnable {
|
||||||
right: bool,
|
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 {
|
pub struct Apu {
|
||||||
mem: [u8; MEM_SIZE],
|
mem: [u8; MEM_SIZE],
|
||||||
apu_enable: bool,
|
apu_enable: bool,
|
||||||
channels: Channels,
|
channels: Channels,
|
||||||
vin: VinEnable,
|
vin: VinEnable,
|
||||||
vol_left: u8,
|
mixer: Mixer,
|
||||||
vol_right: u8,
|
|
||||||
div_apu: u8,
|
div_apu: u8,
|
||||||
buffer: Vec<f32>,
|
buffer: Vec<DacSample>,
|
||||||
converter: Samplerate,
|
// converter: Samplerate,
|
||||||
_stream: Stream,
|
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 {
|
impl Default for Apu {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -81,56 +181,97 @@ impl Default for Apu {
|
||||||
.with_max_sample_rate()
|
.with_max_sample_rate()
|
||||||
.config();
|
.config();
|
||||||
|
|
||||||
let stream = device
|
// config.buffer_size = BufferSize::Fixed(2048 * 2);
|
||||||
.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();
|
|
||||||
|
|
||||||
let converter = Samplerate::new(
|
// let converter = Samplerate::new(
|
||||||
ConverterType::Linear,
|
// ConverterType::Linear,
|
||||||
CLOCK_SPEED as u32,
|
// TARGET_SAMPLERATE,
|
||||||
config.sample_rate.0,
|
// config.sample_rate.0,
|
||||||
1,
|
// 2,
|
||||||
)
|
// )
|
||||||
.unwrap();
|
// .unwrap();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
mem: [0x0; MEM_SIZE],
|
mem: [0x0; MEM_SIZE],
|
||||||
apu_enable: true,
|
apu_enable: true,
|
||||||
channels: Channels::default(),
|
channels: Channels::default(),
|
||||||
vin: VinEnable::default(),
|
vin: VinEnable::default(),
|
||||||
vol_left: 7,
|
mixer: Mixer::default(),
|
||||||
vol_right: 7,
|
|
||||||
div_apu: 0,
|
div_apu: 0,
|
||||||
buffer: vec![],
|
buffer: vec![],
|
||||||
converter,
|
// converter,
|
||||||
_stream: stream,
|
device,
|
||||||
|
config,
|
||||||
|
stream: None,
|
||||||
|
send_buffer: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SCALE: u32 = 4;
|
||||||
|
|
||||||
impl Apu {
|
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) {
|
pub fn div_apu_tick(&mut self) {
|
||||||
self.div_apu = self.div_apu.wrapping_add(1);
|
self.div_apu = self.div_apu.wrapping_add(1);
|
||||||
if self.div_apu % 8 == 0 {
|
if self.div_apu % 8 == 0 {
|
||||||
// envelope sweep
|
// envelope sweep
|
||||||
|
self.channels.one.envelope_tick();
|
||||||
}
|
}
|
||||||
if self.div_apu % 4 == 0 {
|
if self.div_apu % 4 == 0 {
|
||||||
// ch1 frequency sweep
|
// ch1 frequency sweep
|
||||||
|
@ -148,15 +289,20 @@ impl Apu {
|
||||||
.tick(steps)
|
.tick(steps)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.zip(self.channels.two.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(),
|
.collect(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_audio(&mut self) {
|
fn next_audio(&mut self) {
|
||||||
if let Ok(mut audio) = PLAY_BUFFER.try_write() {
|
if let Some(send) = &self.send_buffer {
|
||||||
audio.append(&mut self.converter.process(&self.buffer).unwrap());
|
send.send(
|
||||||
self.buffer.clear();
|
self.buffer
|
||||||
|
.drain(..)
|
||||||
|
.map(|v| v.mixed(&self.mixer))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +331,8 @@ impl Apu {
|
||||||
0xFF19 => self.channels.two.get_control(),
|
0xFF19 => self.channels.two.get_control(),
|
||||||
0xFF24 => {
|
0xFF24 => {
|
||||||
// NR50 - Master volume + VIN panning
|
// 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, 7, self.vin.left);
|
||||||
v = set_or_clear_bit(v, 3, self.vin.right);
|
v = set_or_clear_bit(v, 3, self.vin.right);
|
||||||
v
|
v
|
||||||
|
@ -193,14 +340,14 @@ impl Apu {
|
||||||
0xFF25 => {
|
0xFF25 => {
|
||||||
// NR51 - Panning
|
// NR51 - Panning
|
||||||
let mut v = 0;
|
let mut v = 0;
|
||||||
v = set_or_clear_bit(v, 0, self.channels.one.pan_right);
|
v = set_or_clear_bit(v, 0, self.mixer.ch1.right.bool());
|
||||||
v = set_or_clear_bit(v, 1, self.channels.two.pan_right);
|
v = set_or_clear_bit(v, 1, self.mixer.ch2.right.bool());
|
||||||
v = set_or_clear_bit(v, 2, self.channels.three.pan_right);
|
v = set_or_clear_bit(v, 2, self.mixer.ch3.right.bool());
|
||||||
v = set_or_clear_bit(v, 3, self.channels.four.pan_right);
|
v = set_or_clear_bit(v, 3, self.mixer.ch4.right.bool());
|
||||||
v = set_or_clear_bit(v, 4, self.channels.one.pan_left);
|
v = set_or_clear_bit(v, 4, self.mixer.ch1.left.bool());
|
||||||
v = set_or_clear_bit(v, 5, self.channels.two.pan_left);
|
v = set_or_clear_bit(v, 5, self.mixer.ch2.left.bool());
|
||||||
v = set_or_clear_bit(v, 6, self.channels.three.pan_left);
|
v = set_or_clear_bit(v, 6, self.mixer.ch3.left.bool());
|
||||||
v = set_or_clear_bit(v, 7, self.channels.four.pan_left);
|
v = set_or_clear_bit(v, 7, self.mixer.ch4.left.bool());
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
0xFF26 => {
|
0xFF26 => {
|
||||||
|
@ -250,18 +397,18 @@ impl Apu {
|
||||||
0xFF24 => {
|
0xFF24 => {
|
||||||
self.vin.left = get_bit(data, 7);
|
self.vin.left = get_bit(data, 7);
|
||||||
self.vin.right = get_bit(data, 3);
|
self.vin.right = get_bit(data, 3);
|
||||||
self.vol_left = (data & 0b1110000) >> 4;
|
self.mixer.vol_left = (data & 0b1110000) >> 4;
|
||||||
self.vol_right = data & 0b111;
|
self.mixer.vol_right = data & 0b111;
|
||||||
}
|
}
|
||||||
0xFF25 => {
|
0xFF25 => {
|
||||||
self.channels.one.pan_right = get_bit(data, 0);
|
self.mixer.ch1.right = Volume::from_bool(get_bit(data, 0));
|
||||||
self.channels.two.pan_right = get_bit(data, 1);
|
self.mixer.ch2.right = Volume::from_bool(get_bit(data, 1));
|
||||||
self.channels.three.pan_right = get_bit(data, 2);
|
self.mixer.ch3.right = Volume::from_bool(get_bit(data, 2));
|
||||||
self.channels.four.pan_right = get_bit(data, 3);
|
self.mixer.ch4.right = Volume::from_bool(get_bit(data, 3));
|
||||||
self.channels.one.pan_left = get_bit(data, 4);
|
self.mixer.ch1.left = Volume::from_bool(get_bit(data, 4));
|
||||||
self.channels.two.pan_left = get_bit(data, 5);
|
self.mixer.ch2.left = Volume::from_bool(get_bit(data, 5));
|
||||||
self.channels.three.pan_left = get_bit(data, 6);
|
self.mixer.ch3.left = Volume::from_bool(get_bit(data, 6));
|
||||||
self.channels.four.pan_left = get_bit(data, 7);
|
self.mixer.ch4.left = Volume::from_bool(get_bit(data, 7));
|
||||||
}
|
}
|
||||||
0xFF26 => self.apu_enable = (1 << 7) == (data & 0b10000000),
|
0xFF26 => self.apu_enable = (1 << 7) == (data & 0b10000000),
|
||||||
0xFF11..0xFF1A | 0xFF1B | 0xFF1D..0xFF23 | 0xFF24..0xFF40 => self.mem[reg(addr)] = data,
|
0xFF11..0xFF1A | 0xFF1B | 0xFF1D..0xFF23 | 0xFF24..0xFF40 => self.mem[reg(addr)] = data,
|
||||||
|
|
|
@ -25,17 +25,45 @@ impl Default for Sweep {
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
struct Envelope {
|
struct Envelope {
|
||||||
initial_volume: u8,
|
initial_volume: u8,
|
||||||
|
current_volume: u8,
|
||||||
mode: EnvelopeMode,
|
mode: EnvelopeMode,
|
||||||
rate: u8,
|
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 {
|
impl Default for Envelope {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self::new(0x0, EnvelopeMode::Decrease, 0x0)
|
||||||
initial_volume: 0xF,
|
// Self::new(0xF, EnvelopeMode::Decrease, 0x3)
|
||||||
mode: EnvelopeMode::Decrease,
|
|
||||||
rate: 0x3,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,8 +112,6 @@ impl DutyCycle {
|
||||||
|
|
||||||
pub(super) struct PwmChannel {
|
pub(super) struct PwmChannel {
|
||||||
pub(super) enabled: bool,
|
pub(super) enabled: bool,
|
||||||
pub(super) pan_left: bool,
|
|
||||||
pub(super) pan_right: bool,
|
|
||||||
sweep: Sweep,
|
sweep: Sweep,
|
||||||
duty_cycle: DutyCycle,
|
duty_cycle: DutyCycle,
|
||||||
length_enable: bool,
|
length_enable: bool,
|
||||||
|
@ -98,12 +124,10 @@ pub(super) struct PwmChannel {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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;
|
let wavelength = 0x700;
|
||||||
Self {
|
Self {
|
||||||
enabled,
|
enabled,
|
||||||
pan_left,
|
|
||||||
pan_right,
|
|
||||||
sweep: Sweep::default(),
|
sweep: Sweep::default(),
|
||||||
duty_cycle: DutyCycle::Fifty,
|
duty_cycle: DutyCycle::Fifty,
|
||||||
length_enable: false,
|
length_enable: false,
|
||||||
|
@ -139,7 +163,11 @@ impl PwmChannel {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dac(&self, digital: u8) -> f32 {
|
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) {
|
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) {
|
pub(super) fn update_volume_and_envelope(&mut self, data: u8) {
|
||||||
self.queued_envelope = Envelope {
|
self.queued_envelope = Envelope::new(
|
||||||
initial_volume: (data & 0b11110000) >> 4,
|
(data & 0b11110000) >> 4,
|
||||||
mode: if (data & 0b1000) == 0b1000 {
|
if (data & 0b1000) == 0b1000 {
|
||||||
EnvelopeMode::Increase
|
EnvelopeMode::Increase
|
||||||
} else {
|
} else {
|
||||||
EnvelopeMode::Decrease
|
EnvelopeMode::Decrease
|
||||||
},
|
},
|
||||||
rate: data & 0b111,
|
data & 0b111,
|
||||||
};
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn get_volume_and_envelope(&self) -> u8 {
|
pub(super) fn get_volume_and_envelope(&self) -> u8 {
|
||||||
|
@ -204,37 +232,26 @@ impl PwmChannel {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_wave_timer(wavelength: u16) -> u16 {
|
fn set_wave_timer(wavelength: u16) -> u16 {
|
||||||
(2048 - wavelength) * 4
|
2048 - wavelength
|
||||||
|
// (2048 - wavelength) * 4
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct WaveChannel {
|
pub(super) struct WaveChannel {
|
||||||
pub(super) enabled: bool,
|
pub(super) enabled: bool,
|
||||||
pub(super) pan_left: bool,
|
|
||||||
pub(super) pan_right: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WaveChannel {
|
impl WaveChannel {
|
||||||
pub(super) fn new(enabled: bool, pan_left: bool, pan_right: bool) -> Self {
|
pub(super) fn new(enabled: bool) -> Self {
|
||||||
Self {
|
Self { enabled }
|
||||||
enabled,
|
|
||||||
pan_left,
|
|
||||||
pan_right,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct NoiseChannel {
|
pub(super) struct NoiseChannel {
|
||||||
pub(super) enabled: bool,
|
pub(super) enabled: bool,
|
||||||
pub(super) pan_left: bool,
|
|
||||||
pub(super) pan_right: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NoiseChannel {
|
impl NoiseChannel {
|
||||||
pub(super) fn new(enabled: bool, pan_left: bool, pan_right: bool) -> Self {
|
pub(super) fn new(enabled: bool) -> Self {
|
||||||
Self {
|
Self { enabled }
|
||||||
enabled,
|
|
||||||
pan_left,
|
|
||||||
pan_right,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ impl Cpu {
|
||||||
let clock_cycles = (machine_cycles as usize) * 4;
|
let clock_cycles = (machine_cycles as usize) * 4;
|
||||||
|
|
||||||
self.advance_gpu_clock(clock_cycles);
|
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;
|
self.timers.div_counter += clock_cycles;
|
||||||
let mut div_diff = (self.timers.div_counter / 256) as u8;
|
let mut div_diff = (self.timers.div_counter / 256) as u8;
|
||||||
|
|
Loading…
Reference in a new issue