libsidplayfp 2.7.1
EnvelopeGenerator.h
1/*
2 * This file is part of libsidplayfp, a SID player engine.
3 *
4 * Copyright 2011-2022 Leandro Nini <drfiemost@users.sourceforge.net>
5 * Copyright 2018 VICE Project
6 * Copyright 2007-2010 Antti Lankila
7 * Copyright 2004,2010 Dag Lem <resid@nimrod.no>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23
24#ifndef ENVELOPEGENERATOR_H
25#define ENVELOPEGENERATOR_H
26
27#include "siddefs-fp.h"
28
29namespace reSIDfp
30{
31
44{
45private:
50 enum State
51 {
52 ATTACK, DECAY_SUSTAIN, RELEASE
53 };
54
55private:
57 unsigned int lfsr;
58
60 unsigned int rate;
61
66 unsigned int exponential_counter;
67
72 unsigned int exponential_counter_period;
73 unsigned int new_exponential_counter_period;
74
75 unsigned int state_pipeline;
76
78 unsigned int envelope_pipeline;
79
80 unsigned int exponential_pipeline;
81
83 State state;
84 State next_state;
85
87 bool counter_enabled;
88
90 bool gate;
91
93 bool resetLfsr;
94
96 unsigned char envelope_counter;
97
99 unsigned char attack;
100
102 unsigned char decay;
103
105 unsigned char sustain;
106
108 unsigned char release;
109
111 unsigned char env3;
112
113private:
114 static const unsigned int adsrtable[16];
115
116private:
117 void set_exponential_counter();
118
119 void state_change();
120
121public:
125 void clock();
126
130 unsigned int output() const { return envelope_counter; }
131
136 lfsr(0x7fff),
137 rate(0),
138 exponential_counter(0),
139 exponential_counter_period(1),
140 new_exponential_counter_period(0),
141 state_pipeline(0),
142 envelope_pipeline(0),
143 exponential_pipeline(0),
144 state(RELEASE),
145 next_state(RELEASE),
146 counter_enabled(true),
147 gate(false),
148 resetLfsr(false),
149 envelope_counter(0xaa),
150 attack(0),
151 decay(0),
152 sustain(0),
153 release(0),
154 env3(0)
155 {}
156
160 void reset();
161
168 void writeCONTROL_REG(unsigned char control);
169
176 void writeATTACK_DECAY(unsigned char attack_decay);
177
184 void writeSUSTAIN_RELEASE(unsigned char sustain_release);
185
191 unsigned char readENV() const { return env3; }
192};
193
194} // namespace reSIDfp
195
196#if RESID_INLINING || defined(ENVELOPEGENERATOR_CPP)
197
198namespace reSIDfp
199{
200
201RESID_INLINE
203{
204 env3 = envelope_counter;
205
206 if (unlikely(new_exponential_counter_period > 0))
207 {
208 exponential_counter_period = new_exponential_counter_period;
209 new_exponential_counter_period = 0;
210 }
211
212 if (unlikely(state_pipeline))
213 {
214 state_change();
215 }
216
217 if (unlikely(envelope_pipeline != 0) && (--envelope_pipeline == 0))
218 {
219 if (likely(counter_enabled))
220 {
221 if (state == ATTACK)
222 {
223 if (++envelope_counter==0xff)
224 {
225 next_state = DECAY_SUSTAIN;
226 state_pipeline = 3;
227 }
228 }
229 else if ((state == DECAY_SUSTAIN) || (state == RELEASE))
230 {
231 if (--envelope_counter==0x00)
232 {
233 counter_enabled = false;
234 }
235 }
236
237 set_exponential_counter();
238 }
239 }
240 else if (unlikely(exponential_pipeline != 0) && (--exponential_pipeline == 0))
241 {
242 exponential_counter = 0;
243
244 if (((state == DECAY_SUSTAIN) && (envelope_counter != sustain))
245 || (state == RELEASE))
246 {
247 // The envelope counter can flip from 0x00 to 0xff by changing state to
248 // attack, then to release. The envelope counter will then continue
249 // counting down in the release state.
250 // This has been verified by sampling ENV3.
251
252 envelope_pipeline = 1;
253 }
254 }
255 else if (unlikely(resetLfsr))
256 {
257 lfsr = 0x7fff;
258 resetLfsr = false;
259
260 if (state == ATTACK)
261 {
262 // The first envelope step in the attack state also resets the exponential
263 // counter. This has been verified by sampling ENV3.
264 exponential_counter = 0; // NOTE this is actually delayed one cycle, not modeled
265
266 // The envelope counter can flip from 0xff to 0x00 by changing state to
267 // release, then to attack. The envelope counter is then frozen at
268 // zero; to unlock this situation the state must be changed to release,
269 // then to attack. This has been verified by sampling ENV3.
270
271 envelope_pipeline = 2;
272 }
273 else
274 {
275 if (counter_enabled && (++exponential_counter == exponential_counter_period))
276 exponential_pipeline = exponential_counter_period != 1 ? 2 : 1;
277 }
278 }
279
280 // ADSR delay bug.
281 // If the rate counter comparison value is set below the current value of the
282 // rate counter, the counter will continue counting up until it wraps around
283 // to zero at 2^15 = 0x8000, and then count rate_period - 1 before the
284 // envelope can constly be stepped.
285 // This has been verified by sampling ENV3.
286
287 // check to see if LFSR matches table value
288 if (likely(lfsr != rate))
289 {
290 // it wasn't a match, clock the LFSR once
291 // by performing XOR on last 2 bits
292 const unsigned int feedback = ((lfsr << 14) ^ (lfsr << 13)) & 0x4000;
293 lfsr = (lfsr >> 1) | feedback;
294 }
295 else
296 {
297 resetLfsr = true;
298 }
299}
300
340RESID_INLINE
341void EnvelopeGenerator::state_change()
342{
343 state_pipeline--;
344
345 switch (next_state)
346 {
347 case ATTACK:
348 if (state_pipeline == 1)
349 {
350 // The decay rate is "accidentally" enabled during first cycle of attack phase
351 rate = adsrtable[decay];
352 }
353 else if (state_pipeline == 0)
354 {
355 state = ATTACK;
356 // The attack rate is correctly enabled during second cycle of attack phase
357 rate = adsrtable[attack];
358 counter_enabled = true;
359 }
360 break;
361 case DECAY_SUSTAIN:
362 if (state_pipeline == 0)
363 {
364 state = DECAY_SUSTAIN;
365 rate = adsrtable[decay];
366 }
367 break;
368 case RELEASE:
369 if (((state == ATTACK) && (state_pipeline == 0))
370 || ((state == DECAY_SUSTAIN) && (state_pipeline == 1)))
371 {
372 state = RELEASE;
373 rate = adsrtable[release];
374 }
375 break;
376 }
377}
378
379RESID_INLINE
380void EnvelopeGenerator::set_exponential_counter()
381{
382 // Check for change of exponential counter period.
383 //
384 // For a detailed description see:
385 // http://ploguechipsounds.blogspot.it/2010/03/sid-6581r3-adsr-tables-up-close.html
386 switch (envelope_counter)
387 {
388 case 0xff:
389 case 0x00:
390 new_exponential_counter_period = 1;
391 break;
392
393 case 0x5d:
394 new_exponential_counter_period = 2;
395 break;
396
397 case 0x36:
398 new_exponential_counter_period = 4;
399 break;
400
401 case 0x1a:
402 new_exponential_counter_period = 8;
403 break;
404
405 case 0x0e:
406 new_exponential_counter_period = 16;
407 break;
408
409 case 0x06:
410 new_exponential_counter_period = 30;
411 break;
412 }
413}
414
415} // namespace reSIDfp
416
417#endif
418
419#endif
Definition EnvelopeGenerator.h:44
unsigned int output() const
Definition EnvelopeGenerator.h:130
void writeATTACK_DECAY(unsigned char attack_decay)
Definition EnvelopeGenerator.cpp:122
void reset()
Definition EnvelopeGenerator.cpp:62
void writeSUSTAIN_RELEASE(unsigned char sustain_release)
Definition EnvelopeGenerator.cpp:137
void writeCONTROL_REG(unsigned char control)
Definition EnvelopeGenerator.cpp:87
unsigned char readENV() const
Definition EnvelopeGenerator.h:191
void clock()
Definition EnvelopeGenerator.h:202
EnvelopeGenerator()
Definition EnvelopeGenerator.h:135