troubleshooting, experimenting
This commit is contained in:
parent
f936258310
commit
8f3ab6e751
|
@ -60,8 +60,6 @@ impl Apu {
|
|||
pub fn new() -> Self {
|
||||
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();
|
||||
println!("square_table: {:?}", square_table);
|
||||
println!("tnd_table: {:?}", tnd_table);
|
||||
Apu {
|
||||
square1: Square::new(false),
|
||||
square2: Square::new(true),
|
||||
|
|
|
@ -80,7 +80,7 @@ impl Square {
|
|||
// 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.target_period > 0x7FF // overflow from the sweep unit's adder is silencing the channel,
|
||||
|| self.timer_period > 0x7FF // overflow from the sweep unit's adder is silencing the channel,
|
||||
|| self.length_counter == 0 // the length counter is zero, or
|
||||
|| self.timer_period < 8 { // the timer has a value less than eight.
|
||||
0
|
||||
|
@ -126,9 +126,10 @@ impl Square {
|
|||
}
|
||||
|
||||
pub fn clock_sweep(&mut self) {
|
||||
self.calculate_target_period();
|
||||
// When the frame counter sends a half-frame clock (at 120 or 96 Hz), two things happen.
|
||||
// If the divider's counter is zero, the sweep is enabled, and the sweep unit is not muting the channel: The pulse's period is adjusted.
|
||||
if self.sweep_counter == 0 && self.sweep_enabled && !(self.timer_period < 8 || self.target_period > 0x7FF) {
|
||||
if self.sweep_counter == 0 && self.sweep_enabled && !(self.timer_period < 8 || self.timer_period > 0x7FF) {
|
||||
self.timer_period = self.target_period;
|
||||
println!("timer period adjusted to {}", self.timer_period);
|
||||
}
|
||||
|
@ -139,7 +140,10 @@ impl Square {
|
|||
} else {
|
||||
self.sweep_counter -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Whenever the current period changes for any reason, whether by $400x writes or by sweep, the target period also changes.
|
||||
pub fn calculate_target_period(&mut self) {
|
||||
// The sweep unit continuously calculates each channel's target period in this way:
|
||||
// A barrel shifter shifts the channel's 11-bit raw timer period right by the shift count, producing the change amount.
|
||||
let change = self.timer_period >> self.shift_count;
|
||||
|
@ -185,17 +189,21 @@ impl Square {
|
|||
pub fn write_timer_low(&mut self, value: u8) {
|
||||
self.timer_period &= 0b00000111_00000000; // mask off everything but high 3 bits of 11-bit timer
|
||||
self.timer_period |= value as u16; // apply low 8 bits
|
||||
self.calculate_target_period();
|
||||
}
|
||||
|
||||
// $4003/$4007
|
||||
pub fn write_timer_high(&mut self, value: u8) {
|
||||
// LLLL.Lttt Pulse channel 1 length counter load and timer (write)
|
||||
// TODO: thought the below meant that the length counter was only set if the channel was enabled, but apparently not as not having it fixes start game noise in DK.
|
||||
// When the enabled bit is cleared (via $4015), the length counter is forced to 0 and cannot be changed until enabled is set again (the length counter's previous value is lost).
|
||||
if self.enabled {
|
||||
self.length_counter = super::LENGTH_COUNTER_TABLE[value as usize >> 3];
|
||||
}
|
||||
let timer_high = value as u16 & 0b0000_0111;
|
||||
self.timer_period &= 0b11111000_11111111; // mask off high 3 bits of 11-bit timer
|
||||
self.timer_period |= timer_high << 8; // apply high timer bits in their place
|
||||
self.calculate_target_period();
|
||||
// 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;
|
||||
|
|
|
@ -69,7 +69,7 @@ fn main() -> Result<(), String> {
|
|||
match cpu.apu.clock() {
|
||||
Some(sample) => {
|
||||
sps += 1;
|
||||
audio_device.queue(&vec![sample]);
|
||||
if sps < 44100 {audio_device.queue(&vec![sample]);}
|
||||
},
|
||||
None => (),
|
||||
};
|
||||
|
@ -126,8 +126,14 @@ TODO:
|
|||
- remaining APU channels
|
||||
- common mappers
|
||||
- battery-backed RAM solution
|
||||
- fix mysterious Mario pipe non-locations
|
||||
- GUI? drag and drop ROMs?
|
||||
- reset function
|
||||
- save/load/pause functionality
|
||||
|
||||
|
||||
Timing notes:
|
||||
The PPU is throttled to 60Hz by sleeping in the main loop. This locks the CPU to roughly its intended speed, 1.789773MHz NTSC. The APU runs at half that.
|
||||
The SDL audio device samples/outputs at 44,100Hz, so as long as the APU queues up 44,100 samples per second, it works.
|
||||
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue