Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. struct ADSRTableEntry
  2. {
  3.   s32 ticks;
  4.   s32 step;
  5. };
  6. enum : u32
  7. {
  8.   NUM_ADSR_TABLE_ENTRIES = 128,
  9.   NUM_ADSR_DIRECTIONS = 2 // increasing, decreasing
  10. };
  11. using ADSRTableEntries = std::array<std::array<ADSRTableEntry, NUM_ADSR_TABLE_ENTRIES>, NUM_ADSR_DIRECTIONS>;
  12.  
  13. static constexpr ADSRTableEntries ComputeADSRTableEntries()
  14. {
  15.   ADSRTableEntries entries = {};
  16.   for (u32 decreasing = 0; decreasing < 2; decreasing++)
  17.   {
  18.     for (u32 rate = 0; rate < NUM_ADSR_TABLE_ENTRIES; rate++)
  19.     {
  20.       if (rate < 48)
  21.       {
  22.         entries[decreasing][rate].ticks = 1;
  23.         if (decreasing != 0)
  24.           entries[decreasing][rate].step =
  25.             static_cast<s32>(static_cast<u32>(-8 + static_cast<s32>(rate & 3)) << (11 - (rate >> 2)));
  26.         else
  27.           entries[decreasing][rate].step = (7 - static_cast<s32>(rate & 3)) << (11 - (rate >> 2));
  28.       }
  29.       else
  30.       {
  31.         entries[decreasing][rate].ticks = 1 << (static_cast<s32>(rate >> 2) - 11);
  32.         if (decreasing != 0)
  33.           entries[decreasing][rate].step = (-8 + static_cast<s32>(rate & 3));
  34.         else
  35.           entries[decreasing][rate].step = (7 - static_cast<s32>(rate & 3));
  36.       }
  37.     }
  38.   }
  39.  
  40.   return entries;
  41. }
  42.  
  43. static constexpr ADSRTableEntries s_adsr_table = ComputeADSRTableEntries();
  44.  
  45. void SPU::VolumeEnvelope::Reset(u8 rate_, bool decreasing_, bool exponential_)
  46. {
  47.   rate = rate_;
  48.   decreasing = decreasing_;
  49.   exponential = exponential_;
  50.  
  51.   const ADSRTableEntry& table_entry = s_adsr_table[BoolToUInt8(decreasing)][rate];
  52.   counter = table_entry.ticks;
  53. }
  54.  
  55. s16 SPU::VolumeEnvelope::Tick(s16 current_level)
  56. {
  57.   counter--;
  58.   if (counter > 0)
  59.     return current_level;
  60.  
  61.   const ADSRTableEntry& table_entry = s_adsr_table[BoolToUInt8(decreasing)][rate];
  62.   s32 this_step = table_entry.step;
  63.   counter = table_entry.ticks;
  64.  
  65.   if (exponential)
  66.   {
  67.     if (decreasing)
  68.     {
  69.       this_step = (this_step * current_level) >> 15;
  70.     }
  71.     else
  72.     {
  73.       if (current_level >= 0x6000)
  74.       {
  75.         if (rate < 40)
  76.         {
  77.           this_step >>= 2;
  78.         }
  79.         else if (rate >= 44)
  80.         {
  81.           counter >>= 2;
  82.         }
  83.         else
  84.         {
  85.           this_step >>= 1;
  86.           counter >>= 1;
  87.         }
  88.       }
  89.     }
  90.   }
  91.  
  92.   return static_cast<s16>(
  93.     std::clamp<s32>(static_cast<s32>(current_level) + this_step, ENVELOPE_MIN_VOLUME, ENVELOPE_MAX_VOLUME));
  94. }
  95.  
  96. void SPU::Voice::UpdateADSREnvelope()
  97. {
  98.   switch (adsr_phase)
  99.   {
  100.     case ADSRPhase::Off:
  101.       adsr_target = 0;
  102.       adsr_envelope.Reset(0, false, false);
  103.       return;
  104.  
  105.     case ADSRPhase::Attack:
  106.       adsr_target = 32767; // 0 -> max
  107.       adsr_envelope.Reset(regs.adsr.attack_rate, false, regs.adsr.attack_exponential);
  108.       break;
  109.  
  110.     case ADSRPhase::Decay:
  111.       adsr_target = static_cast<s16>(std::min<s32>((u32(regs.adsr.sustain_level.GetValue()) + 1) * 0x800,
  112.                                                    ENVELOPE_MAX_VOLUME)); // max -> sustain level
  113.       adsr_envelope.Reset(regs.adsr.decay_rate_shr2 << 2, true, true);
  114.       break;
  115.  
  116.     case ADSRPhase::Sustain:
  117.       adsr_target = 0;
  118.       adsr_envelope.Reset(regs.adsr.sustain_rate, regs.adsr.sustain_direction_decrease, regs.adsr.sustain_exponential);
  119.       break;
  120.  
  121.     case ADSRPhase::Release:
  122.       adsr_target = 0;
  123.       adsr_envelope.Reset(regs.adsr.release_rate_shr2 << 2, true, regs.adsr.release_exponential);
  124.       break;
  125.  
  126.     default:
  127.       break;
  128.   }
  129. }
  130.  
  131. void SPU::Voice::TickADSR()
  132. {
  133.   regs.adsr_volume = adsr_envelope.Tick(regs.adsr_volume);
  134.  
  135.   if (adsr_phase != ADSRPhase::Sustain)
  136.   {
  137.     const bool reached_target =
  138.       adsr_envelope.decreasing ? (regs.adsr_volume <= adsr_target) : (regs.adsr_volume >= adsr_target);
  139.     if (reached_target)
  140.     {
  141.       adsr_phase = GetNextADSRPhase(adsr_phase);
  142.       UpdateADSREnvelope();
  143.     }
  144.   }
  145. }