padme_core/apu/
modulation.rs1const WAVE_DUTY_PATTERNS: [[u8; 8]; 4] = [
5 [0, 0, 0, 0, 0, 0, 0, 1],
7 [1, 0, 0, 0, 0, 0, 0, 1],
9 [1, 0, 0, 0, 0, 1, 1, 1],
11 [0, 1, 1, 1, 1, 1, 1, 0]
13];
14
15pub trait DigitalAmplitude {
16 fn digital_amplitude(&self) -> u8;
17}
18
19pub trait Clock {
24 fn frequency(&self) -> u32;
25
26 fn frequency_timer(&self) -> u32;
27
28 fn set_frequency_timer(&mut self, value: u32);
29
30 fn set_frequency(&mut self, _value: u32) {
31 }
32
33 fn reset_frequency_timer(&mut self) {
34 let timer = (0x800 - self.frequency()) * 4;
35 self.set_frequency_timer(timer);
36 }
37}
38
39pub trait Sample {
40 fn sample(&self) -> u8;
41}
42
43pub trait Step {
44 fn step(&mut self);
45}
46
47pub trait Channel: DigitalAmplitude + Clock + Sample + Step {
48 fn is_enabled(&self) -> bool;
49
50 fn set_enabled(&mut self, enabled: bool);
51
52 fn is_dac_enabled(&self) -> bool;
53
54 fn trigger(&mut self);
55
56 fn dac_output(&self) -> f32 {
57 if self.is_enabled() && self.is_dac_enabled() {
58 (self.digital_amplitude() as f32 / 7.5) - 1.0
60 } else {
61 0.0
62 }
63 }
64}
65
66pub trait EnvelopeModulation {
67 fn envelope_register(&self) -> u8;
68
69 fn envelope_timer(&mut self) -> &mut u8;
70
71 fn envelope_volume(&self) -> u8;
72
73 fn set_envelope_volume(&mut self, value: u8);
74
75 fn envelope_init_volume(&self) -> u8 {
76 self.envelope_register() >> 4
77 }
78
79 fn is_envelope_increasing(&self) -> bool {
80 is_set!(self.envelope_register(), 0b0000_1000)
81 }
82
83 fn envelope_period(&self) -> u8 {
84 self.envelope_register() & 0b0000_0111
85 }
86
87 fn reset_envelope(&mut self) {
88 let init_volume = self.envelope_init_volume();
89 self.set_envelope_volume(init_volume);
90 *self.envelope_timer() = self.envelope_period();
91 }
92
93 fn volume_step(&mut self) {
94 let period = self.envelope_period();
95 if period == 0 {
96 return;
97 }
98
99 let env_timer = self.envelope_timer();
100 if *env_timer > 0 {
101 *env_timer -= 1;
102
103 if *env_timer == 0 {
105 *env_timer = period;
106 let increasing = self.is_envelope_increasing();
107 let volume = self.envelope_volume();
108 if volume < 0xF && increasing {
109 self.set_envelope_volume(volume + 1);
110 } else if volume > 0x0 && !increasing {
111 self.set_envelope_volume(volume - 1);
112 }
113 }
114 }
115 }
116}
117
118pub trait LengthModulation: Channel {
119 fn is_length_enabled(&self) -> bool;
120
121 fn length_counter(&self) -> u16;
122
123 fn set_length_counter(&mut self, value: u16);
124
125 fn set_half_length_period(&mut self, half: bool);
126
127 fn length_step(&mut self) {
128 let mut counter = self.length_counter();
129
130 if self.is_length_enabled() && counter > 0 {
131 counter -= 1;
132 self.set_length_counter(counter);
133 if counter == 0 {
134 self.set_enabled(false);
135 }
136 }
137 }
138}
139
140pub trait SweepModulation: Channel + WaveModulation {
141 fn sweep_register(&self) -> u8;
142
143 fn sweep_timer(&mut self) -> &mut u8;
144
145 fn shadow_frequency(&mut self) -> &mut u16;
146
147 fn is_sweep_enabled(&self) -> bool;
148
149 fn set_sweep_enabled(&mut self, enabled: bool);
150
151 fn set_sweep_was_decreasing(&mut self, decreasing: bool);
152
153 #[inline]
154 fn sweep_period(&self) -> u8 {
155 (self.sweep_register() >> 4) & 0b0000_0111
156 }
157
158 #[inline]
159 fn is_sweep_decreasing(&self) -> bool {
160 is_set!(self.sweep_register(), 0b0000_1000)
161 }
162
163 #[inline]
164 fn sweep_shift(&self) -> u8 {
165 self.sweep_register() & 0b0000_0111
166 }
167
168 fn reset_sweep(&mut self) {
169 self.set_sweep_was_decreasing(false);
170 *self.shadow_frequency() = self.frequency() as u16;
171 let period = self.sweep_period();
172 let period_timer = self.sweep_timer();
173 *period_timer = if period > 0 {
174 period
175 } else {
176 8
177 };
178 let sweep_shift = self.sweep_shift();
179
180 self.set_sweep_enabled(period != 0 || sweep_shift != 0);
181
182 if sweep_shift > 0 {
183 self.calculate_sweep_frequency();
184 }
185 }
186
187 fn calculate_sweep_frequency(&mut self) -> u16 {
188 let shadow_frequency = *self.shadow_frequency();
189 let new_frequency = shadow_frequency >> self.sweep_shift();
190
191 let new_frequency = if self.is_sweep_decreasing() {
192 self.set_sweep_was_decreasing(true);
193 shadow_frequency - new_frequency
194 } else {
195 shadow_frequency + new_frequency
196 };
197
198 if new_frequency > 0x7FF {
200 self.set_enabled(false);
201 }
202
203 new_frequency
204 }
205
206 fn sweep_step(&mut self) {
207 let period = self.sweep_period();
208 let timer = self.sweep_timer();
209 if *timer > 0 {
210 *timer -= 1;
211 }
212
213 if *timer == 0 {
214 *timer = if period > 0 {
215 period
216 } else {
217 8
218 };
219
220 if self.is_sweep_enabled() && self.sweep_period() > 0 {
221 let new_frequency = self.calculate_sweep_frequency();
222 if new_frequency <= 0x7FF && self.sweep_shift() != 0 {
223 *self.shadow_frequency() = new_frequency;
224 self.set_frequency(new_frequency as u32);
225 self.calculate_sweep_frequency();
226 }
227 }
228 }
229 }
230}
231
232pub trait WaveModulation {
233 fn wave_cursor(&self) -> u8;
234
235 fn wave_duty(&self) -> u8;
236
237 fn set_wave_cursor(&mut self, value: u8);
238
239 fn inc_wave_cursor(&mut self) {
240 let wave_cursor = self.wave_cursor();
241 self.set_wave_cursor((wave_cursor + 1) % 8)
242 }
243
244 fn reset_wave(&mut self) {
245 self.set_wave_cursor(0);
246 }
247
248 fn wave_sample(&self) -> u8 {
249 let duty = self.wave_duty() as usize;
250 let cursor = self.wave_cursor() as usize;
251
252 WAVE_DUTY_PATTERNS[duty][cursor]
253 }
254}
255
256impl<T: WaveModulation> Sample for T {
257 fn sample(&self) -> u8 {
258 self.wave_sample()
259 }
260}
261
262impl<T: Sample + EnvelopeModulation> DigitalAmplitude for T {
263 fn digital_amplitude(&self) -> u8 {
264 let sample = self.sample();
265 let volume = self.envelope_volume();
266
267 sample * volume
268 }
269}
270
271impl<T: WaveModulation + Channel> Step for T {
272 fn step(&mut self) {
273 let timer = self.frequency_timer() - 1;
274
275 self.set_frequency_timer(timer);
276
277 if timer == 0 {
278 self.reset_frequency_timer();
279 self.inc_wave_cursor();
280 }
281 }
282}