libsidplayfp  0.3.5
EnvelopeGenerator.h
1 /*
2  * This file is part of reSID, a MOS6581 SID emulator engine.
3  * Copyright (C) 2004 Dag Lem <resid@nimrod.no>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * @author Ken Händel
20  *
21  */
22 
23 #ifndef ENVELOPEGENERATOR_H
24 #define ENVELOPEGENERATOR_H
25 
26 #include "siddefs-fp.h"
27 
28 namespace reSIDfp
29 {
30 
43 
44 private:
49  enum State {
50  ATTACK, DECAY_SUSTAIN, RELEASE
51  };
52 
58  int rate_counter;
59 
63  int rate_period;
64 
69  int exponential_counter;
70 
75  int exponential_counter_period;
76 
78  unsigned char envelope_counter;
79 
81  int attack;
82 
84  int decay;
85 
87  int sustain;
88 
90  int release;
91 
93  State state;
94 
98  bool hold_zero;
99 
100  bool envelope_pipeline;
101 
103  bool gate;
104 
141  static const int ENVELOPE_PERIOD[16];
142 
175  short dac[256];
176 
177  void set_exponential_counter();
178 
179 public:
187  void setChipModel(const ChipModel chipModel);
188 
192  void clock();
193 
194  short output() const;
195 
200  rate_counter(0),
201  rate_period(0),
202  exponential_counter(0),
203  exponential_counter_period(1),
204  envelope_counter(0),
205  attack(0),
206  decay(0),
207  sustain(0),
208  release(0),
209  state(RELEASE),
210  hold_zero(true),
211  envelope_pipeline(false),
212  gate(false) {}
213 
217  void reset();
218 
219  // ----------------------------------------------------------------------------
220  // Register functions.
221  // ----------------------------------------------------------------------------
222 
227  void writeCONTROL_REG(const unsigned char control);
228 
233  void writeATTACK_DECAY(const unsigned char attack_decay);
234 
239  void writeSUSTAIN_RELEASE(const unsigned char sustain_release);
240 
246  unsigned char readENV() { return envelope_counter; }
247 };
248 
249 } // namespace reSIDfp
250 
251 #if RESID_INLINING || defined(ENVELOPEGENERATOR_CPP)
252 
253 namespace reSIDfp
254 {
255 
256 RESID_INLINE
258  if (envelope_pipeline) {
259  -- envelope_counter;
260  envelope_pipeline = false;
261  // Check for change of exponential counter period.
262  set_exponential_counter();
263  }
264 
265  // Check for ADSR delay bug.
266  // If the rate counter comparison value is set below the current value of the
267  // rate counter, the counter will continue counting up until it wraps around
268  // to zero at 2^15 = 0x8000, and then count rate_period - 1 before the
269  // envelope can constly be stepped.
270  // This has been verified by sampling ENV3.
271  //
272  if ((++ rate_counter & 0x8000) != 0) {
273  rate_counter = (rate_counter + 1) & 0x7fff;
274  }
275 
276  if (rate_counter != rate_period) {
277  return;
278  }
279 
280  rate_counter = 0;
281 
282  // The first envelope step in the attack state also resets the exponential
283  // counter. This has been verified by sampling ENV3.
284  //
285  if (state == ATTACK || ++exponential_counter == exponential_counter_period) {
286  // likely (~50%)
287  exponential_counter = 0;
288 
289  // Check whether the envelope counter is frozen at zero.
290  if (hold_zero) {
291  return;
292  }
293 
294  switch (state) {
295  case ATTACK:
296  // The envelope counter can flip from 0xff to 0x00 by changing state to
297  // release, then to attack. The envelope counter is then frozen at
298  // zero; to unlock this situation the state must be changed to release,
299  // then to attack. This has been verified by sampling ENV3.
300  //
301  ++ envelope_counter;
302  if (envelope_counter == (unsigned char) 0xff) {
303  state = DECAY_SUSTAIN;
304  rate_period = ENVELOPE_PERIOD[decay];
305  }
306  break;
307  case DECAY_SUSTAIN:
308  if (envelope_counter == (unsigned char) (sustain << 4 | sustain)) {
309  return;
310  }
311  if (exponential_counter_period != 1) {
312  // unlikely (15%)
313  // The decrement is delayed one cycle.
314  envelope_pipeline = true;
315  return;
316  }
317  -- envelope_counter;
318  break;
319  case RELEASE:
320  // The envelope counter can flip from 0x00 to 0xff by changing state to
321  // attack, then to release. The envelope counter will then continue
322  // counting down in the release state.
323  // This has been verified by sampling ENV3.
324  // NB! The operation below requires two's complement integer.
325  //
326  if (exponential_counter_period != 1) {
327  // likely (~50%)
328  // The decrement is delayed one cycle.
329  envelope_pipeline = true;
330  return;
331  }
332  -- envelope_counter;
333  break;
334  }
335 
336  // Check for change of exponential counter period.
337  set_exponential_counter();
338  }
339 }
340 
341 RESID_INLINE
342 short EnvelopeGenerator::output() const {
343  // DAC imperfections are emulated by using envelope_counter as an index
344  // into a DAC lookup table. readENV() uses envelope_counter directly.
345  return dac[envelope_counter & 0xff];
346 }
347 
348 } // namespace reSIDfp
349 
350 #endif
351 
352 #endif