resid/
envelope.rs

1// This file is part of resid-rs.
2// Copyright (c) 2017-2019 Sebastian Jastrzebski <sebby2k@gmail.com>. All rights reserved.
3// Portions (c) 2004 Dag Lem <resid@nimrod.no>
4// Licensed under the GPLv3. See LICENSE file in the project root for full license text.
5
6#![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))]
7
8use bit_field::BitField;
9
10const RATE_COUNTER_MASK: u16 = 0x7fff;
11const RATE_COUNTER_MSB_MASK: u16 = 0x8000;
12
13// Rate counter periods are calculated from the Envelope Rates table in
14// the Programmer's Reference Guide. The rate counter period is the number of
15// cycles between each increment of the envelope counter.
16// The rates have been verified by sampling ENV3.
17//
18// The rate counter is a 16 bit register which is incremented each cycle.
19// When the counter reaches a specific comparison value, the envelope counter
20// is incremented (attack) or decremented (decay/release) and the
21// counter is zeroed.
22//
23// NB! Sampling ENV3 shows that the calculated values are not exact.
24// It may seem like most calculated values have been rounded (.5 is rounded
25// down) and 1 has beed added to the result. A possible explanation for this
26// is that the SID designers have used the calculated values directly
27// as rate counter comparison values, not considering a one cycle delay to
28// zero the counter. This would yield an actual period of comparison value + 1.
29//
30// The time of the first envelope count can not be exactly controlled, except
31// possibly by resetting the chip. Because of this we cannot do cycle exact
32// sampling and must devise another method to calculate the rate counter
33// periods.
34//
35// The exact rate counter periods can be determined e.g. by counting the number
36// of cycles from envelope level 1 to envelope level 129, and dividing the
37// number of cycles by 128. CIA1 timer A and B in linked mode can perform
38// the cycle count. This is the method used to find the rates below.
39//
40// To avoid the ADSR delay bug, sampling of ENV3 should be done using
41// sustain = release = 0. This ensures that the attack state will not lower
42// the current rate counter period.
43//
44// The ENV3 sampling code below yields a maximum timing error of 14 cycles.
45//     lda #$01
46// l1: cmp $d41c
47//     bne l1
48//     ...
49//     lda #$ff
50// l2: cmp $d41c
51//     bne l2
52//
53// This yields a maximum error for the calculated rate period of 14/128 cycles.
54// The described method is thus sufficient for exact calculation of the rate
55// periods.
56//
57static RATE_COUNTER_PERIOD: [u16; 16] = [
58    9,     // 2ms*1.0MHz/256 = 7.81
59    32,    // 8ms*1.0MHz/256 = 31.25
60    63,    // 16ms*1.0MHz/256 = 62.50
61    95,    // 24ms*1.0MHz/256 = 93.75
62    149,   // 38ms*1.0MHz/256 = 148.44
63    220,   // 56ms*1.0MHz/256 = 218.75
64    267,   // 68ms*1.0MHz/256 = 265.63
65    313,   // 80ms*1.0MHz/256 = 312.50
66    392,   // 100ms*1.0MHz/256 = 390.63
67    977,   // 250ms*1.0MHz/256 = 976.56
68    1954,  // 500ms*1.0MHz/256 = 1953.13
69    3126,  // 800ms*1.0MHz/256 = 3125.00
70    3907,  // 1 s*1.0MHz/256 =  3906.25
71    11720, // 3 s*1.0MHz/256 = 11718.75
72    19532, // 5 s*1.0MHz/256 = 19531.25
73    31251, // 8 s*1.0MHz/256 = 31250.00
74];
75
76/// From the sustain levels it follows that both the low and high 4 bits of the
77/// envelope counter are compared to the 4-bit sustain value.
78/// This has been verified by sampling ENV3.
79static SUSTAIN_LEVEL: [u8; 16] = [
80    0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
81];
82
83#[derive(Clone, Copy, PartialEq)]
84pub enum State {
85    Attack,
86    DecaySustain,
87    Release,
88}
89
90/// A 15 bit counter is used to implement the envelope rates, in effect
91/// dividing the clock to the envelope counter by the currently selected rate
92/// period.
93/// In addition, another counter is used to implement the exponential envelope
94/// decay, in effect further dividing the clock to the envelope counter.
95/// The period of this counter is set to 1, 2, 4, 8, 16, 30 at the envelope
96/// counter values 255, 93, 54, 26, 14, 6, respectively.
97#[derive(Clone, Copy)]
98pub struct EnvelopeGenerator {
99    // Configuration
100    attack: u8,
101    decay: u8,
102    sustain: u8,
103    release: u8,
104    // Control
105    gate: bool,
106    // Runtime State
107    pub state: State,
108    pub envelope_counter: u8,
109    pub exponential_counter: u8,
110    pub exponential_counter_period: u8,
111    pub hold_zero: bool,
112    pub rate_counter: u16,
113    pub rate_counter_period: u16,
114}
115
116impl Default for EnvelopeGenerator {
117    fn default() -> Self {
118        let mut envelope = EnvelopeGenerator {
119            attack: 0,
120            decay: 0,
121            sustain: 0,
122            release: 0,
123            gate: false,
124            state: State::Release,
125            envelope_counter: 0,
126            exponential_counter: 0,
127            exponential_counter_period: 0,
128            hold_zero: false,
129            rate_counter: 0,
130            rate_counter_period: 0,
131        };
132        envelope.reset();
133        envelope
134    }
135}
136
137impl EnvelopeGenerator {
138    pub fn get_attack_decay(&self) -> u8 {
139        self.attack << 4 | self.decay
140    }
141
142    pub fn get_control(&self) -> u8 {
143        let mut value = 0u8;
144        value.set_bit(0, self.gate);
145        value
146    }
147
148    pub fn get_sustain_release(&self) -> u8 {
149        self.sustain << 4 | self.release
150    }
151
152    pub fn set_attack_decay(&mut self, value: u8) {
153        self.attack = (value >> 4) & 0x0f;
154        self.decay = value & 0x0f;
155        match self.state {
156            State::Attack => self.rate_counter_period = RATE_COUNTER_PERIOD[self.attack as usize],
157            State::DecaySustain => {
158                self.rate_counter_period = RATE_COUNTER_PERIOD[self.decay as usize]
159            }
160            _ => {}
161        }
162    }
163
164    pub fn set_control(&mut self, value: u8) {
165        let gate = value.get_bit(0);
166        if !self.gate && gate {
167            // Gate bit on: Start attack, decay, sustain.
168            self.state = State::Attack;
169            self.rate_counter_period = RATE_COUNTER_PERIOD[self.attack as usize];
170            // Switching to attack state unlocks the zero freeze.
171            self.hold_zero = false;
172        } else if self.gate && !gate {
173            // Gate bit off: Start release.
174            self.state = State::Release;
175            self.rate_counter_period = RATE_COUNTER_PERIOD[self.release as usize];
176        }
177        self.gate = gate;
178    }
179
180    pub fn set_sustain_release(&mut self, value: u8) {
181        self.sustain = (value >> 4) & 0x0f;
182        self.release = value & 0x0f;
183        if self.state == State::Release {
184            self.rate_counter_period = RATE_COUNTER_PERIOD[self.release as usize];
185        }
186    }
187
188    #[inline]
189    pub fn clock(&mut self) {
190        // Check for ADSR delay bug.
191        // If the rate counter comparison value is set below the current value of the
192        // rate counter, the counter will continue counting up until it wraps around
193        // to zero at 2^15 = 0x8000, and then count rate_period - 1 before the
194        // envelope can finally be stepped.
195        // This has been verified by sampling ENV3.
196        self.rate_counter += 1;
197        if self.rate_counter & RATE_COUNTER_MSB_MASK != 0 {
198            self.rate_counter += 1;
199            self.rate_counter &= RATE_COUNTER_MASK;
200        }
201        if self.rate_counter == self.rate_counter_period {
202            self.rate_counter = 0;
203            // The first envelope step in the attack state also resets the exponential
204            // counter. This has been verified by sampling ENV3.
205            self.exponential_counter += 1; // TODO check w/ ref impl
206            if self.state == State::Attack
207                || self.exponential_counter == self.exponential_counter_period
208            {
209                self.exponential_counter = 0;
210                // Check whether the envelope counter is frozen at zero.
211                if self.hold_zero {
212                    return;
213                }
214                match self.state {
215                    State::Attack => {
216                        // The envelope counter can flip from 0xff to 0x00 by changing state to
217                        // release, then to attack. The envelope counter is then frozen at
218                        // zero; to unlock this situation the state must be changed to release,
219                        // then to attack. This has been verified by sampling ENV3.
220                        self.envelope_counter += 1;
221                        if self.envelope_counter == 0xff {
222                            self.state = State::DecaySustain;
223                            self.rate_counter_period = RATE_COUNTER_PERIOD[self.decay as usize];
224                        }
225                    }
226                    State::DecaySustain => {
227                        if self.envelope_counter != SUSTAIN_LEVEL[self.sustain as usize] {
228                            self.envelope_counter -= 1;
229                        }
230                    }
231                    State::Release => {
232                        // The envelope counter can flip from 0x00 to 0xff by changing state to
233                        // attack, then to release. The envelope counter will then continue
234                        // counting down in the release state.
235                        // This has been verified by sampling ENV3.
236                        // NB! The operation below requires two's complement integer.
237                        self.envelope_counter -= 1;
238                    }
239                }
240                // Check for change of exponential counter period.
241                match self.envelope_counter {
242                    0xff => self.exponential_counter_period = 1,
243                    0x5d => self.exponential_counter_period = 2,
244                    0x36 => self.exponential_counter_period = 4,
245                    0x1a => self.exponential_counter_period = 8,
246                    0x0e => self.exponential_counter_period = 16,
247                    0x06 => self.exponential_counter_period = 30,
248                    0x00 => {
249                        self.exponential_counter_period = 1;
250                        // When the envelope counter is changed to zero, it is frozen at zero.
251                        // This has been verified by sampling ENV3.
252                        self.hold_zero = true;
253                    }
254                    _ => {}
255                }
256            }
257        }
258    }
259
260    #[inline]
261    pub fn clock_delta(&mut self, mut delta: u32) {
262        // NB! This requires two's complement integer.
263        let mut rate_step = self.rate_counter_period as i32 - self.rate_counter as i32;
264        if rate_step <= 0 {
265            rate_step += 0x7fff;
266        }
267        while delta != 0 {
268            if delta < rate_step as u32 {
269                self.rate_counter += delta as u16;
270                if self.rate_counter & RATE_COUNTER_MSB_MASK != 0 {
271                    self.rate_counter += 1;
272                    self.rate_counter &= RATE_COUNTER_MASK;
273                }
274                return;
275            }
276            self.rate_counter = 0;
277            delta -= rate_step as u32;
278            // The first envelope step in the attack state also resets the exponential
279            // counter. This has been verified by sampling ENV3.
280            self.exponential_counter += 1; // TODO check w/ ref impl
281            if self.state == State::Attack
282                || self.exponential_counter == self.exponential_counter_period
283            {
284                self.exponential_counter = 0;
285                // Check whether the envelope counter is frozen at zero.
286                if self.hold_zero {
287                    rate_step = self.rate_counter_period as i32;
288                    continue;
289                }
290                match self.state {
291                    State::Attack => {
292                        // The envelope counter can flip from 0xff to 0x00 by changing state to
293                        // release, then to attack. The envelope counter is then frozen at
294                        // zero; to unlock this situation the state must be changed to release,
295                        // then to attack. This has been verified by sampling ENV3.
296                        self.envelope_counter += 1;
297                        if self.envelope_counter == 0xff {
298                            self.state = State::DecaySustain;
299                            self.rate_counter_period = RATE_COUNTER_PERIOD[self.decay as usize];
300                        }
301                    }
302                    State::DecaySustain => {
303                        if self.envelope_counter != SUSTAIN_LEVEL[self.sustain as usize] {
304                            self.envelope_counter -= 1;
305                        }
306                    }
307                    State::Release => {
308                        // The envelope counter can flip from 0x00 to 0xff by changing state to
309                        // attack, then to release. The envelope counter will then continue
310                        // counting down in the release state.
311                        // This has been verified by sampling ENV3.
312                        // NB! The operation below requires two's complement integer.
313                        self.envelope_counter -= 1;
314                    }
315                }
316                // Check for change of exponential counter period.
317                match self.envelope_counter {
318                    0xff => self.exponential_counter_period = 1,
319                    0x5d => self.exponential_counter_period = 2,
320                    0x36 => self.exponential_counter_period = 4,
321                    0x1a => self.exponential_counter_period = 8,
322                    0x0e => self.exponential_counter_period = 16,
323                    0x06 => self.exponential_counter_period = 30,
324                    0x00 => {
325                        self.exponential_counter_period = 1;
326                        // When the envelope counter is changed to zero, it is frozen at zero.
327                        // This has been verified by sampling ENV3.
328                        self.hold_zero = true;
329                    }
330                    _ => {}
331                }
332            }
333            rate_step = self.rate_counter_period as i32;
334        }
335    }
336
337    #[inline]
338    pub fn output(&self) -> u8 {
339        self.envelope_counter
340    }
341
342    pub fn read_env(&self) -> u8 {
343        self.output()
344    }
345
346    pub fn reset(&mut self) {
347        self.attack = 0;
348        self.decay = 0;
349        self.sustain = 0;
350        self.release = 0;
351        self.gate = false;
352        self.state = State::Release;
353        self.envelope_counter = 0;
354        self.exponential_counter = 0;
355        self.exponential_counter_period = 1;
356        self.hold_zero = true;
357        self.rate_counter = 0;
358        self.rate_counter_period = RATE_COUNTER_PERIOD[self.release as usize];
359    }
360}