1use crate::Region;
9use crate::envelope::Envelope;
10use crate::length::LengthCounter;
11
12pub const NTSC_NOISE_PERIODS: [u16; 16] = [
14 4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068,
15];
16
17pub const PAL_NOISE_PERIODS: [u16; 16] = [
19 4, 7, 14, 30, 60, 88, 118, 148, 188, 236, 354, 472, 708, 944, 1890, 3778,
20];
21
22#[derive(Debug, Clone, Copy)]
24pub struct Noise {
25 pub(crate) lfsr: u16,
27 pub(crate) mode: bool,
29 pub(crate) timer_period: u16,
31 pub(crate) timer: u16,
33 pub envelope: Envelope,
35 pub length: LengthCounter,
37 pub(crate) region: Region,
39}
40
41impl Noise {
42 #[must_use]
44 pub const fn new(region: Region) -> Self {
45 Self {
46 lfsr: 1,
47 mode: false,
48 timer_period: 4,
49 timer: 0,
50 envelope: Envelope {
51 start: false,
52 loop_flag: false,
53 constant: false,
54 volume_or_period: 0,
55 divider: 0,
56 decay: 0,
57 },
58 length: LengthCounter {
59 count: 0,
60 halt: false,
61 new_halt: false,
62 enabled: false,
63 reload_val: 0,
64 previous_count: 0,
65 },
66 region,
67 }
68 }
69
70 pub fn write_ctrl(&mut self, value: u8) {
72 let halt = (value & 0x20) != 0;
73 self.length.set_halt(halt);
76 self.envelope.loop_flag = halt;
77 self.envelope.constant = (value & 0x10) != 0;
78 self.envelope.volume_or_period = value & 0x0F;
79 }
80
81 pub fn write_period(&mut self, value: u8) {
83 self.mode = (value & 0x80) != 0;
84 let idx = (value & 0x0F) as usize;
85 self.timer_period = match self.region {
86 Region::Pal => PAL_NOISE_PERIODS[idx],
87 _ => NTSC_NOISE_PERIODS[idx],
88 };
89 }
90
91 pub fn write_length(&mut self, value: u8) {
93 self.length.load(value);
94 self.envelope.start = true;
95 }
96
97 pub fn clock_timer(&mut self) {
99 if self.timer == 0 {
100 self.timer = self.timer_period;
101 let bit_a = self.lfsr & 1;
103 let bit_b = if self.mode {
104 (self.lfsr >> 6) & 1
105 } else {
106 (self.lfsr >> 1) & 1
107 };
108 let feedback = bit_a ^ bit_b;
109 self.lfsr = (self.lfsr >> 1) | (feedback << 14);
110 } else {
111 self.timer -= 1;
112 }
113 }
114
115 pub fn clock_half_frame(&mut self) {
117 self.length.clock();
118 }
119
120 pub fn clock_quarter_frame(&mut self) {
122 self.envelope.clock();
123 }
124
125 #[must_use]
127 pub fn output(&self) -> u8 {
128 if self.length.count == 0 || (self.lfsr & 1) != 0 {
129 0
130 } else {
131 self.envelope.output()
132 }
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn lfsr_long_mode_taps_bit1() {
142 let mut n = Noise::new(Region::Ntsc);
143 n.timer = 0;
144 n.timer_period = 0;
145 n.mode = false;
146 n.lfsr = 1;
147 n.clock_timer();
148 assert_eq!(n.lfsr, 0x4000);
150 }
151
152 #[test]
153 fn lfsr_short_mode_taps_bit6() {
154 let mut n = Noise::new(Region::Ntsc);
155 n.timer = 0;
156 n.timer_period = 0;
157 n.mode = true;
158 n.lfsr = 1;
159 n.clock_timer();
160 assert_eq!(n.lfsr, 0x4000);
162 }
163}