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