nesfuzz/src/apu/mod.rs

264 lines
9.5 KiB
Rust
Raw Normal View History

2019-11-27 01:11:51 +00:00
mod dmc;
mod envelope;
2021-11-22 07:20:04 +00:00
mod noise;
pub mod serialize;
2021-11-22 07:20:04 +00:00
mod square;
mod triangle;
2019-11-27 01:11:51 +00:00
2021-11-22 07:20:04 +00:00
use dmc::DMC;
2019-12-17 04:06:00 +00:00
use noise::Noise;
use square::Square;
use triangle::Triangle;
2019-12-10 06:34:21 +00:00
// APU clock ticks every other CPU cycle.
// Frame counter only ticks every 3728.5 APU ticks, and in audio frames of 4 or 5.
// Length counter controls note durations.
2019-12-23 23:46:14 +00:00
const FRAME_COUNTER_STEPS: [usize; 5] = [3728, 7456, 11185, 14914, 18640];
const LENGTH_COUNTER_TABLE: [u8; 32] = [
2021-11-22 07:20:04 +00:00
10, 254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14, 12, 16, 24, 18, 48, 20, 96, 22,
192, 24, 72, 26, 16, 28, 32, 30,
2019-12-23 23:46:14 +00:00
];
#[derive(serde::Serialize, serde::Deserialize, Clone)]
2019-11-27 01:11:51 +00:00
pub struct Apu {
2021-11-22 07:20:04 +00:00
square1: Square,
square2: Square,
2019-11-27 01:11:51 +00:00
triangle: Triangle,
2021-11-22 07:20:04 +00:00
noise: Noise,
pub dmc: DMC,
2020-01-30 06:00:12 +00:00
2019-11-27 04:23:18 +00:00
square_table: Vec<f32>,
tnd_table: Vec<f32>,
2019-12-10 03:22:53 +00:00
frame_sequence: u8,
2019-12-10 03:22:53 +00:00
frame_counter: u8,
2019-12-20 00:13:48 +00:00
interrupt_inhibit: bool,
2019-12-15 00:15:06 +00:00
frame_interrupt: bool,
2019-12-19 05:35:04 +00:00
cycle: usize,
2019-12-20 00:13:48 +00:00
pub trigger_irq: bool,
2019-11-27 01:11:51 +00:00
}
impl Apu {
2019-12-10 03:22:53 +00:00
pub fn new() -> Self {
2021-11-22 07:20:04 +00:00
let square_table = (0..31)
.map(|x| 95.52 / ((8128.0 / x as f32) + 100.0))
.collect();
let tnd_table = (0..203)
.map(|x| 163.67 / ((24329.0 / x as f32) + 100.0))
.collect();
2019-11-27 01:11:51 +00:00
Apu {
2021-11-22 07:20:04 +00:00
square1: Square::new(true),
square2: Square::new(false),
2019-11-27 01:11:51 +00:00
triangle: Triangle::new(),
2021-11-22 07:20:04 +00:00
noise: Noise::new(),
dmc: DMC::new(),
2019-11-27 04:23:18 +00:00
square_table: square_table,
tnd_table: tnd_table,
frame_sequence: 0,
2019-12-10 03:22:53 +00:00
frame_counter: 0,
2019-12-20 00:13:48 +00:00
interrupt_inhibit: false,
2019-12-15 00:15:06 +00:00
frame_interrupt: false,
2019-12-19 05:35:04 +00:00
cycle: 0,
2019-12-20 00:13:48 +00:00
trigger_irq: false,
2019-11-27 01:11:51 +00:00
}
}
2020-08-08 16:25:31 +00:00
pub fn clock(&mut self, sample_byte: u8) -> f32 {
2020-01-02 02:51:08 +00:00
// Clock each channel
2019-12-26 03:51:54 +00:00
self.square1.clock();
self.square2.clock();
self.triangle.clock();
self.triangle.clock(); // hacky. clocking triangle twice because it runs every CPU cycle
2019-12-26 03:51:54 +00:00
self.noise.clock();
2020-08-08 16:25:31 +00:00
self.dmc.clock(sample_byte);
2019-12-26 03:51:54 +00:00
2020-01-02 02:51:08 +00:00
// Step frame counter if necessary
if FRAME_COUNTER_STEPS.contains(&self.cycle) {
self.clock_frame_counter();
}
2019-12-19 05:35:04 +00:00
self.cycle += 1;
if (self.frame_sequence == 4 && self.cycle == 14915) || self.cycle == 18641 {
2019-12-19 05:35:04 +00:00
self.cycle = 0;
}
2019-12-20 00:13:48 +00:00
// Send all samples to buffer, let the SDL2 audio callback take what it needs
self.mix()
2019-12-10 06:34:21 +00:00
}
fn mix(&self) -> f32 {
let square_out = self.square_table[(self.square1.sample + self.square2.sample) as usize];
2021-11-22 07:20:04 +00:00
let tnd_out = self.tnd_table
[((3 * self.triangle.sample) + (2 * self.noise.sample) + self.dmc.sample) as usize];
square_out + tnd_out
}
2019-12-15 00:15:06 +00:00
pub fn write_reg(&mut self, address: usize, value: u8) {
2019-11-27 01:11:51 +00:00
match address {
2019-12-22 00:02:32 +00:00
0x4000 => self.square1.write_duty(value),
0x4001 => self.square1.write_sweep(value),
0x4002 => self.square1.write_timer_low(value),
0x4003 => self.square1.write_timer_high(value),
0x4004 => self.square2.write_duty(value),
0x4005 => self.square2.write_sweep(value),
0x4006 => self.square2.write_timer_low(value),
0x4007 => self.square2.write_timer_high(value),
0x4008 => self.triangle.write_counter(value),
2019-12-17 05:43:10 +00:00
0x4009 => (),
2019-12-22 00:02:32 +00:00
0x400A => self.triangle.write_timer_low(value),
0x400B => self.triangle.write_timer_high(value),
0x400C => self.noise.write_envelope(value),
2019-11-27 01:11:51 +00:00
0x400D => (),
2019-12-22 00:02:32 +00:00
0x400E => self.noise.write_loop_noise(value),
0x400F => self.noise.write_length_counter(value),
0x4010 => self.dmc.write_control(value),
2019-11-27 01:11:51 +00:00
0x4011 => self.dmc.direct_load(value),
2019-12-22 00:02:32 +00:00
0x4012 => self.dmc.write_sample_address(value),
0x4013 => self.dmc.write_sample_length(value),
2019-11-27 01:11:51 +00:00
0x4014 => (),
2019-12-22 00:02:32 +00:00
0x4015 => self.write_control(value),
2019-11-27 01:11:51 +00:00
0x4016 => (),
2019-12-23 23:46:14 +00:00
0x4017 => self.write_frame_counter(value),
2019-12-05 02:57:05 +00:00
_ => panic!("bad address written: 0x{:X}", address),
2019-11-27 01:11:51 +00:00
}
}
2019-11-27 04:23:18 +00:00
// mode 0: mode 1: function
2019-12-20 00:13:48 +00:00
// --------- ----------- -----------------------------
// - - - f - - - - - IRQ (if bit 6 is clear)
// - l - l - l - - l Length counter and sweep
// e e e e e e e - e Envelope and linear counter
2019-12-19 05:35:04 +00:00
fn clock_frame_counter(&mut self) {
if !(self.frame_sequence == 5 && self.frame_counter == 3) {
2019-12-19 05:35:04 +00:00
// step envelopes
self.square1.envelope.clock();
self.square2.envelope.clock();
2019-12-19 05:35:04 +00:00
self.triangle.clock_linear_counter();
self.noise.envelope.clock();
2019-12-19 05:35:04 +00:00
}
if (self.frame_counter == 1)
|| (self.frame_sequence == 4 && self.frame_counter == 3)
|| (self.frame_sequence == 5 && self.frame_counter == 4)
2020-01-02 03:50:20 +00:00
{
2019-12-19 05:35:04 +00:00
// step length counters and sweep units
2019-12-22 04:14:47 +00:00
self.square1.clock_sweep();
self.square2.clock_sweep();
2019-12-19 05:35:04 +00:00
self.square1.clock_length_counter();
self.square2.clock_length_counter();
self.triangle.clock_length_counter();
self.noise.clock_length_counter();
}
if self.frame_sequence == 4 && self.frame_counter == 3 && !self.interrupt_inhibit {
2019-12-20 00:13:48 +00:00
self.trigger_irq = true;
2019-12-19 05:35:04 +00:00
}
// advance counter
self.frame_counter = self.frame_counter.wrapping_add(1);
if self.frame_counter == self.frame_sequence {
self.frame_counter = 0;
2019-12-18 03:29:00 +00:00
}
}
2019-12-23 23:46:14 +00:00
// CPU writes to $4015
2019-12-22 00:02:32 +00:00
fn write_control(&mut self, value: u8) {
2019-12-15 00:15:06 +00:00
// Writing to this register clears the DMC interrupt flag.
self.dmc.interrupt = false;
// Writing a zero to any of the channel enable bits will silence that channel and immediately set its length counter to 0.
2021-11-22 07:20:04 +00:00
if value & (1 << 0) != 0 {
2019-12-15 00:15:06 +00:00
self.square1.enabled = true;
} else {
self.square1.enabled = false;
self.square1.length_counter = 0;
}
2021-11-22 07:20:04 +00:00
if value & (1 << 1) != 0 {
2019-12-15 00:15:06 +00:00
self.square2.enabled = true;
} else {
self.square2.enabled = false;
self.square2.length_counter = 0;
}
2021-11-22 07:20:04 +00:00
if value & (1 << 2) != 0 {
2019-12-15 00:15:06 +00:00
self.triangle.enabled = true;
} else {
self.triangle.enabled = false;
self.triangle.length_counter = 0;
}
2021-11-22 07:20:04 +00:00
if value & (1 << 3) != 0 {
2019-12-15 00:15:06 +00:00
self.noise.enabled = true;
} else {
self.noise.enabled = false;
self.noise.length_counter = 0;
}
2021-11-22 07:20:04 +00:00
if value & (1 << 4) != 0 {
2019-12-15 00:15:06 +00:00
self.dmc.enabled = true;
// If the DMC bit is set, the DMC sample will be restarted only if its bytes remaining is 0.
// If there are bits remaining in the 1-byte sample buffer, these will finish playing before the next sample is fetched.
2020-08-09 17:10:11 +00:00
if self.dmc.bytes_remaining == 0 {
self.dmc.current_address = self.dmc.sample_address;
self.dmc.bytes_remaining = self.dmc.sample_length;
2019-12-15 00:15:06 +00:00
}
} else {
self.dmc.enabled = false;
// If the DMC bit is clear, the DMC bytes remaining will be set to 0 and the DMC will silence when it empties.
self.dmc.bytes_remaining = 0;
}
}
2019-12-23 23:46:14 +00:00
// CPU reads from $4015
2019-12-15 00:15:06 +00:00
pub fn read_status(&mut self) -> u8 {
// IF-D NT21: DMC interrupt (I), frame interrupt (F), DMC active (D), length counter > 0 (N/T/2/1)
let mut val = 0;
// N/T/2/1 will read as 1 if the corresponding length counter is greater than 0. For the triangle channel, the status of the linear counter is irrelevant.
if self.square1.length_counter != 0 {
2021-11-22 07:20:04 +00:00
val |= 1 << 0;
2019-12-15 00:15:06 +00:00
}
if self.square2.length_counter != 0 {
2021-11-22 07:20:04 +00:00
val |= 1 << 1;
2019-12-15 00:15:06 +00:00
}
if self.triangle.length_counter != 0 {
2021-11-22 07:20:04 +00:00
val |= 1 << 2;
2019-12-15 00:15:06 +00:00
}
if self.noise.length_counter != 0 {
2021-11-22 07:20:04 +00:00
val |= 1 << 3;
2019-12-15 00:15:06 +00:00
}
// D will read as 1 if the DMC bytes remaining is more than 0.
if self.dmc.bytes_remaining != 0 {
2021-11-22 07:20:04 +00:00
val |= 1 << 4;
2019-12-15 00:15:06 +00:00
}
if self.frame_interrupt {
2021-11-22 07:20:04 +00:00
val |= 1 << 6;
2019-12-15 00:15:06 +00:00
}
if self.dmc.interrupt {
2021-11-22 07:20:04 +00:00
val |= 1 << 7;
2019-12-15 00:15:06 +00:00
}
// Reading this register clears the frame interrupt flag (but not the DMC interrupt flag).
self.frame_interrupt = false;
// TODO: If an interrupt flag was set at the same moment of the read, it will read back as 1 but it will not be cleared.
val
2019-12-05 02:57:05 +00:00
}
2019-12-18 03:29:00 +00:00
2019-12-23 23:46:14 +00:00
// $4017
fn write_frame_counter(&mut self, value: u8) {
// 0 selects 4-step sequence, 1 selects 5-step sequence
2021-11-22 07:20:04 +00:00
self.frame_sequence = if value & (1 << 7) == 0 { 4 } else { 5 };
2020-01-30 06:00:12 +00:00
// If set, the frame interrupt flag is cleared, otherwise it is unaffected.
2021-11-22 07:20:04 +00:00
if value & (1 << 6) != 0 {
2019-12-23 23:46:14 +00:00
self.interrupt_inhibit = false;
}
// If the mode flag is set, then both "quarter frame" and "half frame" signals are also generated.
if self.frame_sequence == 5 {
2019-12-23 23:46:14 +00:00
// Clock envelopes, length counters, and sweep units
self.square1.envelope.clock();
2019-12-23 23:46:14 +00:00
self.square1.clock_sweep();
self.square1.clock_length_counter();
self.square2.envelope.clock();
2019-12-23 23:46:14 +00:00
self.square2.clock_sweep();
self.square2.clock_length_counter();
self.triangle.clock_linear_counter();
self.triangle.clock_length_counter();
self.noise.envelope.clock();
2019-12-23 23:46:14 +00:00
self.noise.clock_length_counter();
}
}
2019-11-27 01:11:51 +00:00
}