libsidplayfp  1.0.3
EnvelopeGenerator.h
1 /*
2  * This file is part of libsidplayfp, a SID player engine.
3  *
4  * Copyright 2011-2013 Leandro Nini <drfiemost@users.sourceforge.net>
5  * Copyright 2007-2010 Antti Lankila
6  * Copyright 2004 Dag Lem <resid@nimrod.no>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  */
22 
23 #ifndef ENVELOPEGENERATOR_H
24 #define ENVELOPEGENERATOR_H
25 
26 #include "siddefs-fp.h"
27 
28 namespace reSIDfp
29 {
30 
45 {
46 private:
51  enum State
52  {
53  ATTACK, DECAY_SUSTAIN, RELEASE
54  };
55 
59  int lfsr;
60 
64  int rate;
65 
70  int exponential_counter;
71 
76  int exponential_counter_period;
77 
79  int attack;
80 
82  int decay;
83 
85  int sustain;
86 
88  int release;
89 
91  State state;
92 
96  bool hold_zero;
97 
98  bool envelope_pipeline;
99 
101  bool gate;
102 
104  unsigned char envelope_counter;
105 
111  short dac[256];
112 
113  void set_exponential_counter();
114 
126  static const int adsrtable[16];
127 
128 public:
136  void setChipModel(ChipModel chipModel);
137 
141  void clock();
142 
148  short output() const { return dac[envelope_counter]; }
149 
154  lfsr(0),
155  rate(0),
156  exponential_counter(0),
157  exponential_counter_period(1),
158  attack(0),
159  decay(0),
160  sustain(0),
161  release(0),
162  state(RELEASE),
163  hold_zero(true),
164  envelope_pipeline(false),
165  gate(false),
166  envelope_counter(0) {}
167 
171  void reset();
172 
173  // ----------------------------------------------------------------------------
174  // Register functions.
175  // ----------------------------------------------------------------------------
176 
181  void writeCONTROL_REG(unsigned char control);
182 
187  void writeATTACK_DECAY(unsigned char attack_decay);
188 
193  void writeSUSTAIN_RELEASE(unsigned char sustain_release);
194 
200  unsigned char readENV() const { return envelope_counter; }
201 };
202 
203 } // namespace reSIDfp
204 
205 #if RESID_INLINING || defined(ENVELOPEGENERATOR_CPP)
206 
207 namespace reSIDfp
208 {
209 
210 RESID_INLINE
212 {
213  if (envelope_pipeline)
214  {
215  -- envelope_counter;
216  envelope_pipeline = false;
217  // Check for change of exponential counter period.
218  set_exponential_counter();
219  }
220 
221  // Check for ADSR delay bug.
222  // If the rate counter comparison value is set below the current value of the
223  // rate counter, the counter will continue counting up until it wraps around
224  // to zero at 2^15 = 0x8000, and then count rate_period - 1 before the
225  // envelope can constly be stepped.
226  // This has been verified by sampling ENV3.
227  //
228  // Envelope is now implemented like in the real machine with a shift register
229  // so the ADSR delay bug should be correcly modeled
230 
231  // check to see if LFSR matches table value
232  if (lfsr != rate)
233  {
234  // it wasn't a match, clock the LFSR once
235  // by performing XOR on last 2 bits
236  const int feedback = ((lfsr >> 14) ^ (lfsr >> 13)) & 0x01;
237  lfsr = ((lfsr << 1) & 0x7fff) | feedback;
238  return;
239  }
240 
241  // reset LFSR
242  lfsr = 0x7fff;
243 
244  // The first envelope step in the attack state also resets the exponential
245  // counter. This has been verified by sampling ENV3.
246  //
247  if (state == ATTACK || ++exponential_counter == exponential_counter_period)
248  {
249  // likely (~50%)
250  exponential_counter = 0;
251 
252  // Check whether the envelope counter is frozen at zero.
253  if (hold_zero)
254  {
255  return;
256  }
257 
258  switch (state)
259  {
260  case ATTACK:
261  // The envelope counter can flip from 0xff to 0x00 by changing state to
262  // release, then to attack. The envelope counter is then frozen at
263  // zero; to unlock this situation the state must be changed to release,
264  // then to attack. This has been verified by sampling ENV3.
265  //
266  ++ envelope_counter;
267 
268  if (envelope_counter == (unsigned char) 0xff)
269  {
270  state = DECAY_SUSTAIN;
271  rate = adsrtable[decay];
272  }
273 
274  break;
275 
276  case DECAY_SUSTAIN:
277 
278  // From the sustain levels it follows that both the low and high 4 bits
279  // of the envelope counter are compared to the 4-bit sustain value.
280  // This has been verified by sampling ENV3.
281  //
282  // For a detailed description see:
283  // http://ploguechipsounds.blogspot.it/2010/11/new-research-on-sid-adsr.html
284  if (envelope_counter == (unsigned char)(sustain << 4 | sustain))
285  {
286  return;
287  }
288 
289  if (exponential_counter_period != 1)
290  {
291  // unlikely (15%)
292  // The decrement is delayed one cycle.
293  envelope_pipeline = true;
294  return;
295  }
296 
297  -- envelope_counter;
298  break;
299 
300  case RELEASE:
301 
302  // The envelope counter can flip from 0x00 to 0xff by changing state to
303  // attack, then to release. The envelope counter will then continue
304  // counting down in the release state.
305  // This has been verified by sampling ENV3.
306  // NB! The operation below requires two's complement integer.
307  //
308  if (exponential_counter_period != 1)
309  {
310  // likely (~50%)
311  // The decrement is delayed one cycle.
312  envelope_pipeline = true;
313  return;
314  }
315 
316  -- envelope_counter;
317  break;
318  }
319 
320  // Check for change of exponential counter period.
321  set_exponential_counter();
322  }
323 }
324 
325 } // namespace reSIDfp
326 
327 #endif
328 
329 #endif