2019-11-27 01:11:51 +00:00
mod dmc ;
2020-01-15 02:51:59 +00:00
mod envelope ;
2021-11-22 07:20:04 +00:00
mod noise ;
2020-02-29 23:23:51 +00:00
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
] ;
2020-02-29 23:23:51 +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
2020-01-15 02:51:59 +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 ,
2020-01-15 02:51:59 +00:00
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 ( ) ;
2020-01-15 02:51:59 +00:00
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 ;
2020-01-15 02:51:59 +00:00
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
2020-01-14 05:36:54 +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
}
2020-01-01 21:28:28 +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 ] ;
2020-01-01 21:28:28 +00:00
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
2020-01-01 21:28:28 +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 ) {
2020-01-15 02:51:59 +00:00
if ! ( self . frame_sequence = = 5 & & self . frame_counter = = 3 ) {
2019-12-19 05:35:04 +00:00
// step envelopes
2020-01-15 02:51:59 +00:00
self . square1 . envelope . clock ( ) ;
self . square2 . envelope . clock ( ) ;
2019-12-19 05:35:04 +00:00
self . triangle . clock_linear_counter ( ) ;
2020-01-15 02:51:59 +00:00
self . noise . envelope . clock ( ) ;
2019-12-19 05:35:04 +00:00
}
2020-01-15 02:51:59 +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 ( ) ;
}
2020-01-15 02:51:59 +00:00
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
2020-01-20 23:37:27 +00:00
self . frame_counter = self . frame_counter . wrapping_add ( 1 ) ;
2020-01-15 02:51:59 +00:00
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.
2020-01-15 02:51:59 +00:00
if self . frame_sequence = = 5 {
2019-12-23 23:46:14 +00:00
// Clock envelopes, length counters, and sweep units
2020-01-15 02:51:59 +00:00
self . square1 . envelope . clock ( ) ;
2019-12-23 23:46:14 +00:00
self . square1 . clock_sweep ( ) ;
self . square1 . clock_length_counter ( ) ;
2020-01-15 02:51:59 +00:00
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 ( ) ;
2020-01-15 02:51:59 +00:00
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
}