2019-12-18 02:38:15 +00:00
const DUTY_CYCLE_SEQUENCES : [ [ u8 ; 8 ] ; 4 ] = [
2019-12-17 04:06:00 +00:00
[ 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 ] ,
[ 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 ] ,
[ 0 , 1 , 1 , 1 , 1 , 0 , 0 , 0 ] ,
[ 1 , 0 , 0 , 1 , 1 , 1 , 1 , 1 ] ,
] ;
pub struct Square {
pub sample : u16 ,
2019-12-22 00:02:32 +00:00
divider : u16 ,
pub enabled : bool ,
2019-12-17 04:06:00 +00:00
duty_cycle : [ u8 ; 8 ] ,
2019-12-22 00:02:32 +00:00
duty_counter : usize ,
envelope : u16 ,
start : bool ,
decay_counter : u16 ,
2019-12-17 04:06:00 +00:00
constant_volume_flag : bool , // (0: use volume from envelope; 1: use constant volume)
2019-12-22 00:02:32 +00:00
length_counter_halt : bool , // (this bit is also the envelope's loop flag)
2019-12-18 02:38:15 +00:00
pub length_counter : u8 ,
2019-12-22 00:02:32 +00:00
timer : u16 ,
timer_period : u16 ,
2019-12-18 02:38:15 +00:00
sweep : u8 ,
2019-12-22 00:02:32 +00:00
sweep_divider : u8 ,
shift_count : u8 ,
sweep_adder_overflow : bool ,
sweep_enabled : bool ,
sweep_negate : bool ,
sweep_reload : bool ,
2019-12-17 04:06:00 +00:00
}
impl Square {
2019-11-27 01:11:51 +00:00
pub fn new ( ) -> Self {
2019-12-17 04:06:00 +00:00
Square {
2019-12-22 00:02:32 +00:00
sample : 0 ,
divider : 0 ,
enabled : false ,
2019-12-18 02:38:15 +00:00
duty_cycle : DUTY_CYCLE_SEQUENCES [ 0 ] ,
2019-12-17 04:06:00 +00:00
duty_counter : 0 ,
2019-12-22 00:02:32 +00:00
envelope : 0 ,
start : false ,
decay_counter : 0 ,
2019-11-27 01:11:51 +00:00
constant_volume_flag : false ,
2019-12-22 00:02:32 +00:00
2019-11-27 01:11:51 +00:00
timer : 0 ,
2019-12-22 00:02:32 +00:00
timer_period : 0 ,
2019-11-27 01:11:51 +00:00
sweep : 0 ,
2019-12-22 00:02:32 +00:00
sweep_divider : 0 ,
shift_count : 0 ,
sweep_adder_overflow : false ,
sweep_enabled : false ,
sweep_negate : false ,
sweep_reload : false ,
length_counter : 0 ,
length_counter_halt : false ,
2019-11-27 01:11:51 +00:00
}
}
2019-12-05 02:57:05 +00:00
pub fn clock ( & mut self ) {
2019-12-22 00:02:32 +00:00
// The sequencer is clocked by an 11-bit timer. Given the timer value t = HHHLLLLLLLL formed by timer high and timer low, this timer is updated every APU cycle
// (i.e., every second CPU cycle), and counts t, t-1, ..., 0, t, t-1, ..., clocking the waveform generator when it goes from 0 to t.
if self . timer = = 0 {
self . timer = self . timer_period ;
self . duty_counter = ( self . duty_counter + 1 ) % 8 ;
} else {
self . timer - = 1 ;
}
// Update volume for this channel
// The mixer receives the current envelope volume except when
self . sample = if self . duty_cycle [ self . duty_counter ] = = 0 // The sequencer output is zero, or
| | self . sweep_adder_overflow // overflow from the sweep unit's adder is silencing the channel,
| | self . length_counter = = 0 // the length counter is zero, or
| | self . timer < 8 { // the timer has a value less than eight.
0
} else {
self . decay_counter
} ;
2019-12-17 05:43:10 +00:00
}
pub fn clock_envelope ( & mut self ) {
2019-12-18 02:38:15 +00:00
// When clocked by the frame counter, one of two actions occurs:
// if the start flag is clear, the divider is clocked,
if ! self . start {
self . clock_divider ( ) ;
2019-12-17 05:43:10 +00:00
} else {
2019-12-18 02:38:15 +00:00
self . start = false ; // otherwise the start flag is cleared,
self . decay_counter = 15 ; // the decay level counter is loaded with 15,
self . divider = self . envelope ; // and the divider's period is immediately reloaded
}
}
2019-12-19 05:35:04 +00:00
pub fn clock_length_counter ( & mut self ) {
}
2019-12-17 05:43:10 +00:00
2019-12-18 02:38:15 +00:00
fn clock_divider ( & mut self ) {
// When the divider is clocked while at 0, it is loaded with V and clocks the decay level counter.
if self . divider = = 0 {
self . divider = self . envelope ;
// Then one of two actions occurs: If the counter is non-zero, it is decremented,
if self . decay_counter ! = 0 {
self . decay_counter - = 1 ;
} else if self . length_counter_halt {
// otherwise if the loop flag is set, the decay level counter is loaded with 15.
self . decay_counter = 15 ;
}
} else {
self . divider - = 1 ;
2019-12-17 05:43:10 +00:00
}
}
2019-12-22 00:02:32 +00:00
pub fn clock_sweep ( & mut self ) {
}
2019-12-17 05:43:10 +00:00
// $4000/$4004
2019-12-22 00:02:32 +00:00
pub fn write_duty ( & mut self , value : u8 ) {
// TODO: The duty cycle is changed (see table below), but the sequencer's current position isn't affected.
2019-12-18 02:38:15 +00:00
self . duty_cycle = DUTY_CYCLE_SEQUENCES [ ( value > > 6 ) as usize ] ;
2019-12-17 04:06:00 +00:00
self . length_counter_halt = value & ( 1 < < 5 ) ! = 0 ;
self . constant_volume_flag = value & ( 1 < < 4 ) ! = 0 ;
2019-12-17 05:43:10 +00:00
if self . constant_volume_flag {
2019-12-22 00:02:32 +00:00
self . envelope = value as u16 & 0b1111 ;
2019-12-17 05:43:10 +00:00
} else {
self . envelope = self . decay_counter ;
}
2019-12-05 02:57:05 +00:00
}
2019-12-17 05:43:10 +00:00
// $4001/$4005
2019-12-22 00:02:32 +00:00
pub fn write_sweep ( & mut self , value : u8 ) {
self . sweep_enabled = value > > 7 = = 1 ;
self . sweep_divider = value > > 4 & 0b111 ;
self . sweep_negate = value & 0b1000 ! = 0 ;
self . shift_count = value & 0b111 ;
2019-12-05 02:57:05 +00:00
}
2019-12-17 05:43:10 +00:00
// $4002/$4006
2019-12-22 00:02:32 +00:00
pub fn write_timer_low ( & mut self , value : u8 ) {
self . timer & = 0b11111111_00000000 ;
self . timer | = value as u16 ;
2019-12-05 02:57:05 +00:00
}
2019-12-17 05:43:10 +00:00
// $4003/$4007
2019-12-22 00:02:32 +00:00
pub fn write_timer_high ( & mut self , value : u8 ) {
// LLLL.Lttt Pulse channel 1 length counter load and timer (write)
self . length_counter = value > > 3 ;
let timer_high = value as u16 & 0b0000_0111 ;
self . timer & = 0b11111000_11111111 ; // mask off high 3 bits of 11-bit timer
self . timer | = timer_high < < 8 ; // apply high timer bits in their place
// The sequencer is immediately restarted at the first value of the current sequence. The envelope is also restarted. The period divider is not reset.
self . duty_counter = 0 ;
self . start = true ;
2019-12-05 02:57:05 +00:00
}
2019-12-10 03:22:53 +00:00
}