Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. void PS_SPU::RunEnvelope(SPU_Voice *voice)
  2. {
  3.    SPU_ADSR *ADSR = &voice->ADSR;
  4.    int increment;
  5.    int divinco;
  6.    int16 uoflow_reset;
  7.  
  8.    if(ADSR->Phase == ADSR_ATTACK && ADSR->EnvLevel == 0x7FFF)
  9.       ADSR->Phase++;
  10.  
  11.    //static INLINE void CalcVCDelta(const uint8 zs, uint8 speed, bool log_mode, bool decrement, bool inv_increment, int16 Current, int &increment, int &divinco)
  12.    switch(ADSR->Phase)
  13.    {
  14.       default: assert(0);
  15.                break;
  16.  
  17.       case ADSR_ATTACK:
  18.                CalcVCDelta(0x7F, ADSR->AttackRate, ADSR->AttackExp, false, false, (int16)ADSR->EnvLevel, increment, divinco);
  19.                uoflow_reset = 0x7FFF;
  20.                break;
  21.  
  22.       case ADSR_DECAY:
  23.                CalcVCDelta(0x1F << 2, ADSR->DecayRate, true, true, true, (int16)ADSR->EnvLevel, increment, divinco);
  24.                uoflow_reset = 0;
  25.                break;
  26.  
  27.       case ADSR_SUSTAIN:
  28.                CalcVCDelta(0x7F, ADSR->SustainRate, ADSR->SustainExp, ADSR->SustainDec, ADSR->SustainDec, (int16)ADSR->EnvLevel, increment, divinco);
  29.                uoflow_reset = ADSR->SustainDec ? 0 : 0x7FFF;
  30.                break;
  31.  
  32.       case ADSR_RELEASE:
  33.                CalcVCDelta(0x1F << 2, ADSR->ReleaseRate, ADSR->ReleaseExp, true, true, (int16)ADSR->EnvLevel, increment, divinco);
  34.                uoflow_reset = 0;
  35.                break;
  36.    }
  37.  
  38.    ADSR->Divider += divinco;
  39.    if(ADSR->Divider & 0x8000)
  40.    {
  41.       const uint16 prev_level = ADSR->EnvLevel;
  42.  
  43.       ADSR->Divider = 0;
  44.       ADSR->EnvLevel += increment;
  45.  
  46.       if(ADSR->Phase == ADSR_ATTACK)
  47.       {
  48.          // If previous the upper bit was 0, but now it's 1, handle overflow.
  49.          if(((prev_level ^ ADSR->EnvLevel) & ADSR->EnvLevel) & 0x8000)
  50.             ADSR->EnvLevel = uoflow_reset;
  51.       }
  52.       else
  53.       {
  54.          if(ADSR->EnvLevel & 0x8000)
  55.             ADSR->EnvLevel = uoflow_reset;
  56.       }
  57.       if(ADSR->Phase == ADSR_DECAY && (uint16)ADSR->EnvLevel < ADSR->SustainLevel)
  58.          ADSR->Phase++;
  59.    }
  60. }
  61.  
  62. static INLINE void CalcVCDelta(const uint8 zs, uint8 speed, bool log_mode, bool dec_mode, bool inv_increment, int16 Current, int &increment, int &divinco)
  63. {
  64.    increment = (7 - (speed & 0x3));
  65.  
  66.    if(inv_increment)
  67.       increment = ~increment;
  68.  
  69.    divinco = 32768;
  70.  
  71.    if(speed < 0x2C)
  72.       increment = (unsigned)increment << ((0x2F - speed) >> 2);
  73.  
  74.    if(speed >= 0x30)
  75.       divinco >>= (speed - 0x2C) >> 2;
  76.  
  77.    if(log_mode)
  78.    {
  79.       if(dec_mode)  // Log decrement mode
  80.          increment = (Current * increment) >> 15;
  81.       else          // Log increment mode
  82.       {
  83.          if((Current & 0x7FFF) >= 0x6000)
  84.          {
  85.             if(speed < 0x28)
  86.                increment >>= 2;
  87.             else if(speed >= 0x2C)
  88.                divinco >>= 2;
  89.             else    // 0x28 ... 0x2B
  90.             {
  91.                increment >>= 1;
  92.                divinco >>= 1;
  93.             }
  94.          }
  95.       }
  96.    } // end if(log_mode)
  97.  
  98.    if(divinco == 0 && speed < zs) //0x7F)
  99.       divinco = 1;
  100. }