noise.rsannotatednoise.rssource181 lines · 4.8 KB · raw
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}