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}