tetanes_core/apu/
noise.rs1use crate::{
6 apu::{
7 Channel,
8 envelope::Envelope,
9 length_counter::LengthCounter,
10 timer::{Timer, TimerCycle},
11 },
12 common::{Clock, NesRegion, Regional, Reset, ResetKind, Sample},
13};
14use serde::{Deserialize, Serialize};
15
16#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)]
18pub enum ShiftMode {
19 Zero,
21 One,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
29#[must_use]
30pub struct Noise {
31 pub region: NesRegion,
32 pub timer: Timer,
33 pub shift: u16,
34 pub shift_mode: ShiftMode,
35 pub length: LengthCounter,
36 pub envelope: Envelope,
37 pub force_silent: bool,
38}
39
40impl Default for Noise {
41 fn default() -> Self {
42 Self::new(NesRegion::Ntsc)
43 }
44}
45
46impl Noise {
47 const PERIOD_TABLE_NTSC: [u64; 16] = [
48 4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068,
49 ];
50 const PERIOD_TABLE_PAL: [u64; 16] = [
51 4, 8, 14, 30, 60, 88, 118, 148, 188, 236, 354, 472, 708, 944, 1890, 3778,
52 ];
53
54 pub const fn new(region: NesRegion) -> Self {
55 Self {
56 region,
57 timer: Timer::new(Self::period(region, 0)),
58 shift: 1, shift_mode: ShiftMode::Zero,
60 length: LengthCounter::new(Channel::Noise),
61 envelope: Envelope::new(),
62 force_silent: false,
63 }
64 }
65
66 #[must_use]
67 pub const fn is_muted(&self) -> bool {
68 (self.shift & 0x01) == 0x01 || self.silent()
69 }
70
71 #[must_use]
72 pub const fn silent(&self) -> bool {
73 self.force_silent
74 }
75
76 pub const fn set_silent(&mut self, silent: bool) {
77 self.force_silent = silent;
78 }
79
80 const fn period(region: NesRegion, val: u8) -> u64 {
81 let index = (val & 0x0F) as usize;
82 match region {
83 NesRegion::Auto | NesRegion::Ntsc | NesRegion::Dendy => {
84 Self::PERIOD_TABLE_NTSC[index] - 1
85 }
86 NesRegion::Pal => Self::PERIOD_TABLE_PAL[index] - 1,
87 }
88 }
89
90 pub fn clock_quarter_frame(&mut self) {
91 self.envelope.clock();
92 }
93
94 pub fn clock_half_frame(&mut self) {
95 self.clock_quarter_frame();
96 self.length.clock();
97 }
98
99 pub const fn write_ctrl(&mut self, val: u8) {
101 self.length.write_ctrl((val & 0x20) == 0x20); self.envelope.write_ctrl(val);
103 }
104
105 pub const fn write_timer(&mut self, val: u8) {
107 self.timer.period = Self::period(self.region, val);
108 self.shift_mode = if (val & 0x80) == 0x80 {
109 ShiftMode::One
110 } else {
111 ShiftMode::Zero
112 };
113 }
114
115 pub const fn write_length(&mut self, val: u8) {
117 self.length.write(val >> 3);
118 self.envelope.restart();
119 }
120
121 pub const fn set_enabled(&mut self, enabled: bool) {
122 self.length.set_enabled(enabled);
123 }
124
125 pub const fn volume(&self) -> u8 {
126 if self.length.counter > 0 {
127 self.envelope.volume()
128 } else {
129 0
130 }
131 }
132}
133
134impl Sample for Noise {
135 fn output(&self) -> f32 {
136 if self.is_muted() {
137 0f32
138 } else {
139 f32::from(self.volume())
140 }
141 }
142}
143
144impl TimerCycle for Noise {
145 fn cycle(&self) -> u64 {
146 self.timer.cycle
147 }
148}
149
150impl Clock for Noise {
151 fn clock(&mut self) -> u64 {
156 if self.timer.clock() > 0 {
157 let shift_by = if self.shift_mode == ShiftMode::One {
158 6
159 } else {
160 1
161 };
162 let feedback = (self.shift & 0x01) ^ ((self.shift >> shift_by) & 0x01);
163 self.shift >>= 1;
164 self.shift |= feedback << 14;
165 1
166 } else {
167 0
168 }
169 }
170}
171
172impl Regional for Noise {
173 fn region(&self) -> NesRegion {
174 self.region
175 }
176
177 fn set_region(&mut self, region: NesRegion) {
178 self.region = region;
179 }
180}
181
182impl Reset for Noise {
183 fn reset(&mut self, kind: ResetKind) {
184 self.timer.reset(kind);
185 self.timer.period = Self::period(self.region, 0);
186 self.length.reset(kind);
187 self.envelope.reset(kind);
188 self.shift = 1;
189 self.shift_mode = ShiftMode::Zero;
190 }
191}