home *** CD-ROM | disk | FTP | other *** search
/ Large Pack of OldSkool DOS MOD Trackers / goattracker_2.68.zip / src / resid-fp / envelope.h < prev    next >
C/C++ Source or Header  |  2009-01-03  |  5KB  |  175 lines

  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.  
  20. #ifndef __ENVELOPE_FP_H__
  21. #define __ENVELOPE_FP_H__
  22.  
  23. #include "siddefs-fp.h"
  24.  
  25. // ----------------------------------------------------------------------------
  26. // A 15 bit counter is used to implement the envelope rates, in effect
  27. // dividing the clock to the envelope counter by the currently selected rate
  28. // period.
  29. // In addition, another counter is used to implement the exponential envelope
  30. // decay, in effect further dividing the clock to the envelope counter.
  31. // The period of this counter is set to 1, 2, 4, 8, 16, 30 at the envelope
  32. // counter values 255, 93, 54, 26, 14, 6, respectively.
  33. // ----------------------------------------------------------------------------
  34. class EnvelopeGeneratorFP
  35. {
  36. public:
  37.   EnvelopeGeneratorFP();
  38.  
  39.   enum State { ATTACK, DECAY_SUSTAIN, RELEASE };
  40.  
  41.   RESID_INLINE void clock();
  42.   void reset();
  43.  
  44.   void writeCONTROL_REG(reg8);
  45.   void writeATTACK_DECAY(reg8);
  46.   void writeSUSTAIN_RELEASE(reg8);
  47.   reg8 readENV();
  48.  
  49.   // 8-bit envelope output.
  50.   RESID_INLINE reg8 output();
  51.  
  52. protected:
  53.   void update_rate_period(reg16 period);
  54.  
  55.   int rate_counter;
  56.   int rate_period;
  57.   reg8 exponential_counter;
  58.   reg8 exponential_counter_period;
  59.   reg8 envelope_counter;
  60.   bool hold_zero;
  61.  
  62.   reg4 attack;
  63.   reg4 decay;
  64.   reg4 sustain;
  65.   reg4 release;
  66.  
  67.   reg8 gate;
  68.  
  69.   State state;
  70.  
  71.   // Lookup table to convert from attack, decay, or release value to rate
  72.   // counter period.
  73.   static reg16 rate_counter_period[];
  74.  
  75.   // The 16 selectable sustain levels.
  76.   static reg8 sustain_level[];
  77.  
  78. friend class SIDFP;
  79. };
  80.  
  81.  
  82. // ----------------------------------------------------------------------------
  83. // SID clocking - 1 cycle.
  84. // ----------------------------------------------------------------------------
  85. RESID_INLINE
  86. void EnvelopeGeneratorFP::clock()
  87. {
  88.   if (++ rate_counter != rate_period)
  89.     return;
  90.  
  91.   rate_counter = 0;
  92.  
  93.   // The first envelope step in the attack state also resets the exponential
  94.   // counter. This has been verified by sampling ENV3.
  95.   //
  96.   if (state == ATTACK || ++exponential_counter == exponential_counter_period)
  97.   {
  98.     exponential_counter = 0;
  99.  
  100.     // Check whether the envelope counter is frozen at zero.
  101.     if (hold_zero) {
  102.       return;
  103.     }
  104.  
  105.     switch (state) {
  106.     case ATTACK:
  107.       // The envelope counter can flip from 0xff to 0x00 by changing state to
  108.       // release, then to attack. The envelope counter is then frozen at
  109.       // zero; to unlock this situation the state must be changed to release,
  110.       // then to attack. This has been verified by sampling ENV3.
  111.       //
  112.       ++envelope_counter &= 0xff;
  113.       if (envelope_counter == 0xff) {
  114.         state = DECAY_SUSTAIN;
  115.         update_rate_period(rate_counter_period[decay]);
  116.       }
  117.       break;
  118.     case DECAY_SUSTAIN:
  119.       if (envelope_counter != sustain_level[sustain]) {
  120.         --envelope_counter;
  121.       }
  122.       break;
  123.     case RELEASE:
  124.       // The envelope counter can flip from 0x00 to 0xff by changing state to
  125.       // attack, then to release. The envelope counter will then continue
  126.       // counting down in the release state.
  127.       // This has been verified by sampling ENV3.
  128.       // NB! The operation below requires two's complement integer.
  129.       //
  130.       --envelope_counter &= 0xff;
  131.       break;
  132.     }
  133.     
  134.     // Check for change of exponential counter period.
  135.     switch (envelope_counter) {
  136.     case 0xff:
  137.       exponential_counter_period = 1;
  138.       break;
  139.     case 0x5d:
  140.       exponential_counter_period = 2;
  141.       break;
  142.     case 0x36:
  143.       exponential_counter_period = 4;
  144.       break;
  145.     case 0x1a:
  146.       exponential_counter_period = 8;
  147.       break;
  148.     case 0x0e:
  149.       exponential_counter_period = 16;
  150.       break;
  151.     case 0x06:
  152.       exponential_counter_period = 30;
  153.       break;
  154.     case 0x00:
  155.       exponential_counter_period = 1;
  156.  
  157.       // When the envelope counter is changed to zero, it is frozen at zero.
  158.       // This has been verified by sampling ENV3.
  159.       hold_zero = true;
  160.       break;
  161.     }
  162.   }
  163. }
  164.  
  165. // ----------------------------------------------------------------------------
  166. // Read the envelope generator output.
  167. // ----------------------------------------------------------------------------
  168. RESID_INLINE
  169. reg8 EnvelopeGeneratorFP::output()
  170. {
  171.   return envelope_counter;
  172. }
  173.  
  174. #endif // not __ENVELOPE_FP_H__
  175.