1use crate::apu::components::{Envelope, StandardLengthCounter}; 2use bincode::{Decode, Encode}; 3use jgenesis_common::num::GetBit; 4 5#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)] 6enum LfsrWidthBits { 7 Seven, 8 #[default] 9 Fifteen, 10} 11 12impl LfsrWidthBits { 13 fn from_bit(bit: bool) -> Self { 14 if bit { Self::Seven } else { Self::Fifteen } 15 } 16 17 fn to_bit(self) -> bool { 18 self == Self::Seven 19 } 20} 21 22#[derive(Debug, Clone, Encode, Decode)] 23pub struct NoiseChannel { 24 counter: u32, 25 clock_divider: u8, 26 clock_shift: u8, 27 lfsr: u16, 28 lfsr_width: LfsrWidthBits, 29 length_counter: StandardLengthCounter, 30 envelope: Envelope, 31 channel_enabled: bool, 32 dac_enabled: bool, 33} 34 35impl Default for NoiseChannel { 36 fn default() -> Self { 37 Self::new() 38 } 39} 40 41impl NoiseChannel { 42 #[must_use] 43 pub fn new() -> Self { 44 Self { 45 counter: 2, 46 clock_divider: 0, 47 clock_shift: 0, 48 lfsr: 0, 49 lfsr_width: LfsrWidthBits::default(), 50 length_counter: StandardLengthCounter::new(), 51 envelope: Envelope::new(), 52 channel_enabled: false, 53 dac_enabled: false, 54 } 55 } 56 57 pub fn write_register_1(&mut self, value: u8) { 58 // NR41: Noise length counter reload 59 self.length_counter.load(value); 60 61 log::trace!("NR41 write, length counter: {}", self.length_counter.counter); 62 } 63 64 #[must_use] 65 pub fn read_register_2(&self) -> u8 { 66 self.envelope.read_register() 67 } 68 69 pub fn write_register_2(&mut self, value: u8) { 70 // NR42: Noise envelope control 71 self.envelope.write_register(value); 72 self.dac_enabled = value & 0xF8 != 0; 73 74 if !self.dac_enabled { 75 self.channel_enabled = false; 76 } 77 78 log::trace!("NR42 write"); 79 log::trace!(" Envelope: {:?}", self.envelope); 80 log::trace!(" DAC enabled: {}", self.dac_enabled); 81 } 82 83 #[must_use] 84 pub fn read_register_3(&self) -> u8 { 85 (self.clock_shift << 4) | (u8::from(self.lfsr_width.to_bit()) << 3) | self.clock_divider 86 } 87 88 pub fn write_register_3(&mut self, value: u8) { 89 // NR43: Noise frequency + LFSR size (7-bit vs. 15-bit) 90 self.clock_shift = value >> 4; 91 self.lfsr_width = LfsrWidthBits::from_bit(value.bit(3)); 92 self.clock_divider = value & 0x07; 93 94 log::trace!("NR43 write"); 95 log::trace!(" Shift: {}", self.clock_shift); 96 log::trace!(" LFSR bits: {:?}", self.lfsr_width); 97 log::trace!(" Divider code: {}", self.clock_divider); 98 } 99 100 #[must_use] 101 pub fn read_register_4(&self) -> u8 { 102 0xBF | (u8::from(self.length_counter.enabled) << 6) 103 } 104 105 pub fn write_register_4(&mut self, value: u8, frame_sequencer_step: u8) { 106 // NR44: Noise length counter enabled + trigger 107 self.length_counter.set_enabled( 108 value.bit(6), 109 frame_sequencer_step, 110 &mut self.channel_enabled, 111 ); 112 113 if value.bit(7) { 114 // Channel triggered 115 self.length_counter.trigger(frame_sequencer_step); 116 self.envelope.trigger(); 117 self.lfsr = 0x7FFF; 118 self.counter = compute_clock_period(self.clock_divider, self.clock_shift); 119 120 self.channel_enabled = self.dac_enabled; 121 } 122 123 log::trace!("NR44 write"); 124 log::trace!(" Length counter enabled: {}", self.length_counter.enabled); 125 log::trace!(" Triggered: {}", value.bit(7)); 126 } 127 128 pub fn tick_m_cycle(&mut self) { 129 self.counter -= 1; 130 if self.counter == 0 { 131 self.counter = compute_clock_period(self.clock_divider, self.clock_shift); 132 133 let new_bit = self.lfsr.bit(0) ^ self.lfsr.bit(1); 134 self.lfsr = (self.lfsr >> 1) | (u16::from(new_bit) << 14); 135 136 if self.lfsr_width == LfsrWidthBits::Seven { 137 self.lfsr = (self.lfsr & !(1 << 6)) | (u16::from(new_bit) << 6); 138 } 139 } 140 } 141 142 pub fn clock_length_counter(&mut self) { 143 self.length_counter.clock(&mut self.channel_enabled); 144 } 145 146 pub fn clock_envelope(&mut self) { 147 self.envelope.clock(); 148 } 149 150 #[must_use] 151 pub fn sample(&self) -> Option<u8> { 152 if !self.dac_enabled { 153 return None; 154 } 155 156 if !self.channel_enabled { 157 return Some(0); 158 } 159 160 Some(u8::from(!self.lfsr.bit(0)) * self.envelope.volume) 161 } 162 163 #[must_use] 164 pub fn volume(&self) -> u8 { 165 if !self.dac_enabled || !self.channel_enabled { 166 return 0; 167 } 168 169 self.envelope.volume 170 } 171 172 #[must_use] 173 pub fn enabled(&self) -> bool { 174 self.channel_enabled 175 } 176} 177 178fn compute_clock_period(divider: u8, shift: u8) -> u32 { 179 let base_divisor = if divider == 0 { 8 } else { 16 * u32::from(divider) }; 180 (base_divisor << shift) / 4 181}