padme_core/apu/
modulation.rs

1//
2// All wave duty patterns
3//
4const WAVE_DUTY_PATTERNS: [[u8; 8]; 4] = [
5    // 12.5% (_-------_-------_-------)
6    [0, 0, 0, 0, 0, 0, 0, 1],
7    // 25% (__------__------__------)
8    [1, 0, 0, 0, 0, 0, 0, 1],
9    // 50% (____----____----____----)
10    [1, 0, 0, 0, 0, 1, 1, 1],
11    // 75% (______--______--______--)
12    [0, 1, 1, 1, 1, 1, 1, 0]
13];
14
15pub trait DigitalAmplitude {
16    fn digital_amplitude(&self) -> u8;
17}
18
19// pub trait Clock {
20//     fn step(&mut self);
21// }
22
23pub 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            // from [0x0; 0xF] to [-1; 1]
59            (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            // Adjust time when we reached the period
104            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        // overflow check
199        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}