2020-08-09 17:10:11 +00:00
// number of CPU cycles between sample output level being adjusted
2021-11-22 07:20:04 +00:00
pub const SAMPLE_RATES : [ u16 ; 16 ] = [
428 , 380 , 340 , 320 , 286 , 254 , 226 , 214 , 190 , 160 , 142 , 128 , 106 , 84 , 72 , 54 ,
] ;
2020-08-08 16:25:31 +00:00
2020-02-29 23:23:51 +00:00
#[ derive(serde::Serialize, serde::Deserialize, Clone) ]
2019-12-17 04:06:00 +00:00
pub struct DMC {
2020-08-09 17:10:11 +00:00
pub sample : u16 , // "output value" that goes to the mixer
2020-09-02 23:33:17 +00:00
pub enabled : bool ,
2020-08-09 17:36:47 +00:00
irq_enabled : bool ,
2019-12-17 04:06:00 +00:00
pub interrupt : bool ,
2020-08-09 17:10:11 +00:00
loop_flag : bool ,
2020-08-09 04:30:41 +00:00
pub cpu_stall : bool ,
2020-08-09 17:10:11 +00:00
rate_index : usize ,
cpu_cycles_left : u16 ,
2020-08-08 16:25:31 +00:00
// Memory reader
sample_byte : u8 , // passed in every APU clock cycle, need to think of a better way to read CPU from APU
2020-08-09 04:30:41 +00:00
sample_buffer : Option < u8 > , // buffer that the output unit draws into its shift register, wrapped in Option to denote 'emptiness'
2020-08-09 17:10:11 +00:00
pub sample_address : usize , // start of sample in memory
pub sample_length : usize , // number of bytes starting from sample_address that constitute the sample. each byte has 8 bits that can raise or lower the output level, at a speed determined by rate_index
2020-08-08 16:25:31 +00:00
pub current_address : usize , // address of the next byte of the sample to play
pub bytes_remaining : usize , // bytes left in the sample
// Output unit
2020-08-09 04:30:41 +00:00
shift_register : u8 ,
bits_remaining : usize ,
2019-12-17 04:06:00 +00:00
}
impl DMC {
2019-11-27 01:11:51 +00:00
pub fn new ( ) -> Self {
2019-12-17 04:06:00 +00:00
DMC {
2019-12-05 02:57:05 +00:00
sample : 0 ,
2019-12-15 00:15:06 +00:00
enabled : false ,
2020-08-09 17:36:47 +00:00
irq_enabled : false ,
2019-12-15 00:15:06 +00:00
interrupt : false ,
2020-08-08 16:25:31 +00:00
loop_flag : false ,
2020-08-09 04:30:41 +00:00
cpu_stall : false ,
2020-08-08 16:25:31 +00:00
rate_index : 0 ,
cpu_cycles_left : 0 ,
sample_byte : 0 ,
sample_buffer : None ,
sample_address : 0 ,
sample_length : 0 ,
current_address : 0 ,
bytes_remaining : 0 ,
2020-08-09 04:30:41 +00:00
shift_register : 0 ,
bits_remaining : 0 ,
2019-11-27 01:11:51 +00:00
}
}
2019-12-05 02:57:05 +00:00
2020-08-08 16:25:31 +00:00
pub fn clock ( & mut self , sample_byte : u8 ) {
2020-12-31 01:18:17 +00:00
if self . enabled {
self . clock_memory_reader ( sample_byte ) ;
self . clock_output_unit ( ) ;
}
2020-08-08 16:25:31 +00:00
}
fn clock_memory_reader ( & mut self , sample_byte : u8 ) {
// When a sample is (re)started, the current address is set to the sample address, and bytes remaining is set to the sample length.
if self . bytes_remaining = = 0 & & self . loop_flag {
self . current_address = self . sample_address ;
self . bytes_remaining = self . sample_length ;
}
// Any time the sample buffer is in an empty state and bytes remaining is not zero (including just after a write to $4015 that enables the channel,
// regardless of where that write occurs relative to the bit counter mentioned below), the following occur:
if self . sample_buffer . is_none ( ) & & self . bytes_remaining ! = 0 {
// The CPU is stalled for up to 4 CPU cycles to allow the longest possible write (the return address and write after an IRQ) to finish.
// If OAM DMA is in progress, it is paused for two cycles. The sample fetch always occurs on an even CPU cycle due to its alignment with the APU.
2020-08-09 04:30:41 +00:00
self . cpu_stall = true ;
2020-08-08 16:25:31 +00:00
// The sample buffer is filled with the next sample byte read from the current address, subject to whatever mapping hardware is present.
self . sample_buffer = Some ( sample_byte ) ;
// The address is incremented; if it exceeds $FFFF, it is wrapped around to $8000.
if self . current_address = = 0xFFFF {
self . current_address = 0x8000
} else {
self . current_address + = 1 ;
}
2020-08-09 17:36:47 +00:00
// The bytes remaining counter is decremented; if it becomes zero and the loop flag is set, the sample is restarted (see above);
// otherwise, if the bytes remaining counter becomes zero and the IRQ enabled flag is set, the interrupt flag is set.
2020-08-08 16:25:31 +00:00
self . bytes_remaining - = 1 ;
2020-08-09 17:36:47 +00:00
} else if self . sample_buffer . is_none ( ) & & self . irq_enabled {
self . interrupt = true ;
2020-08-09 04:30:41 +00:00
}
2019-12-26 03:51:54 +00:00
}
2020-08-09 04:30:41 +00:00
fn clock_output_unit ( & mut self ) {
// When the timer outputs a clock, the following actions occur in order:
// If the silence flag is clear, the output level changes based on bit 0 of the shift register.
// If the bit is 1, add 2; otherwise, subtract 2. But if adding or subtracting 2 would cause the output level to leave the 0-127 range,
// leave the output level unchanged. This means subtract 2 only if the current level is at least 2, or add 2 only if the current level is at most 125.
// The right shift register is clocked.
// As stated above, the bits-remaining counter is decremented. If it becomes zero, a new output cycle is started.
2020-12-31 01:18:17 +00:00
if self . cpu_cycles_left > 0 {
self . cpu_cycles_left - = 2 ;
}
2020-08-09 04:30:41 +00:00
if self . cpu_cycles_left = = 0 {
self . cpu_cycles_left = SAMPLE_RATES [ self . rate_index ] ;
2020-09-02 23:33:17 +00:00
if self . enabled {
2020-08-09 04:30:41 +00:00
match self . shift_register & 1 {
2021-11-22 07:20:04 +00:00
0 = > {
if self . sample > = 2 {
self . sample - = 2
}
}
1 = > {
if self . sample < = 125 {
self . sample + = 2
}
}
2020-08-09 17:10:11 +00:00
_ = > panic! ( " uh oh! magical bits! " ) ,
2020-08-09 04:30:41 +00:00
}
2020-09-02 23:33:17 +00:00
} else {
self . sample = 0 ;
2020-08-09 04:30:41 +00:00
}
self . shift_register > > = 1 ;
2020-12-31 01:18:17 +00:00
if self . bits_remaining > 0 {
self . bits_remaining - = 1 ;
}
2020-08-09 04:30:41 +00:00
// When an output cycle ends, a new cycle is started as follows:
// The bits-remaining counter is loaded with 8.
// If the sample buffer is empty, then the silence flag is set; otherwise, the silence flag is cleared and the sample buffer is emptied into the shift register.
if self . bits_remaining = = 0 {
self . bits_remaining = 8 ;
match self . sample_buffer {
Some ( s ) = > {
2020-09-02 23:33:17 +00:00
self . enabled = true ;
2020-08-09 04:30:41 +00:00
self . shift_register = s ;
self . sample_buffer = None ;
2021-11-22 07:20:04 +00:00
}
2020-09-02 23:33:17 +00:00
None = > self . enabled = false ,
2020-08-09 04:30:41 +00:00
}
}
}
}
2019-12-22 00:02:32 +00:00
pub fn write_control ( & mut self , value : u8 ) {
2020-08-08 16:25:31 +00:00
// $4010 IL--.RRRR Flags and Rate (write)
2020-08-09 17:36:47 +00:00
self . irq_enabled = value & 0b1000_0000 ! = 0 ;
if ! self . irq_enabled {
self . interrupt = false ;
}
2020-08-09 17:10:11 +00:00
self . loop_flag = value & 0b0100_0000 ! = 0 ;
self . rate_index = value as usize & 0b0000_1111 ;
2019-12-05 02:57:05 +00:00
}
2021-11-22 07:20:04 +00:00
2019-12-05 02:57:05 +00:00
pub fn direct_load ( & mut self , value : u8 ) {
2020-08-09 17:10:11 +00:00
// $4011 -DDD.DDDD Direct load (write)
self . sample = value as u16 & 0b0111_1111 ;
2019-12-05 02:57:05 +00:00
}
2021-11-22 07:20:04 +00:00
2019-12-22 00:02:32 +00:00
pub fn write_sample_address ( & mut self , value : u8 ) {
2020-08-09 17:10:11 +00:00
// $4012 AAAA.AAAA Sample address (write)
// bits 7-0 AAAA.AAAA Sample address = %11AAAAAA.AA000000 = $C000 + (A * 64)
self . sample_address = ( ( value as usize ) < < 6 ) + 0xC000 ;
2019-12-05 02:57:05 +00:00
}
2021-11-22 07:20:04 +00:00
2019-12-22 00:02:32 +00:00
pub fn write_sample_length ( & mut self , value : u8 ) {
2020-08-09 17:10:11 +00:00
// $4013 LLLL.LLLL Sample length (write)
// bits 7-0 LLLL.LLLL Sample length = %LLLL.LLLL0001 = (L * 16) + 1 bytes
self . sample_length = ( ( value as usize ) < < 4 ) + 1 ;
2019-12-05 02:57:05 +00:00
}
2020-08-09 17:37:11 +00:00
}