X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=plugins%2Fdfsound%2Fadsr.c;h=e4873dfd418cdf203b0a9beabd7f4b96fbeda27c;hp=387a83b24ad08125d955abb00a953b241c1ed4f1;hb=1ab7621a76d1ef82fde77322c12d4076889bed01;hpb=08cfd5e5b3027af766dab3916747c0fc9ae47d7d diff --git a/plugins/dfsound/adsr.c b/plugins/dfsound/adsr.c index 387a83b2..e4873dfd 100644 --- a/plugins/dfsound/adsr.c +++ b/plugins/dfsound/adsr.c @@ -26,179 +26,194 @@ // ADSR func //////////////////////////////////////////////////////////////////////// -unsigned long RateTable[160]; +static int RateTableAdd[128]; +static int RateTableSub[128]; void InitADSR(void) // INIT ADSR { - unsigned long r,rs,rd;int i; - - memset(RateTable,0,sizeof(unsigned long)*160); // build the rate table according to Neill's rules (see at bottom of file) - - r=3;rs=1;rd=0; - - for(i=32;i<160;i++) // we start at pos 32 with the real values... everything before is 0 - { - if(r<0x3FFFFFFF) - { - r+=rs; - rd++;if(rd==5) {rd=1;rs*=2;} - } - if(r>0x3FFFFFFF) r=0x3FFFFFFF; - - RateTable[i]=r; - } + int lcv, denom; + + // Optimize table - Dr. Hell ADSR math + for (lcv = 0; lcv < 48; lcv++) + { + RateTableAdd[lcv] = (7 - (lcv&3)) << (11 + 16 - (lcv >> 2)); + RateTableSub[lcv] = (-8 + (lcv&3)) << (11 + 16 - (lcv >> 2)); + } + + for (; lcv < 128; lcv++) + { + denom = 1 << ((lcv>>2) - 11); + + RateTableAdd[lcv] = ((7 - (lcv&3)) << 16) / denom; + RateTableSub[lcv] = ((-8 + (lcv&3)) << 16) / denom; + } } //////////////////////////////////////////////////////////////////////// INLINE void StartADSR(int ch) // MIX ADSR { - s_chan[ch].ADSRX.lVolume=1; // and init some adsr vars - s_chan[ch].ADSRX.State=0; + s_chan[ch].ADSRX.State=0; // and init some adsr vars s_chan[ch].ADSRX.EnvelopeVol=0; } //////////////////////////////////////////////////////////////////////// -INLINE int MixADSR(int ch) // MIX ADSR -{ - if(s_chan[ch].bStop) // should be stopped: - { // do release - if(s_chan[ch].ADSRX.ReleaseModeExp) - { - switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7) - { - case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +0 + 32]; break; - case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +4 + 32]; break; - case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +6 + 32]; break; - case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +8 + 32]; break; - case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +9 + 32]; break; - case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +10+ 32]; break; - case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +11+ 32]; break; - case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 +12+ 32]; break; - } - } +static void MixADSR(int ch, int ns, int ns_to) // MIX ADSR +{ + int EnvelopeVol = s_chan[ch].ADSRX.EnvelopeVol; + int val, rto, level; + + if (s_chan[ch].bStop) // should be stopped: + { // do release + val = RateTableSub[s_chan[ch].ADSRX.ReleaseRate * 4]; + if (s_chan[ch].ADSRX.ReleaseModeExp) + { + for (; ns < ns_to; ns++) + { + EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16); + if (EnvelopeVol < 0) + break; + + ChanBuf[ns] *= EnvelopeVol >> 21; + ChanBuf[ns] >>= 10; + } + } else - { - s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x0C + 32]; - } - - if(s_chan[ch].ADSRX.EnvelopeVol<0) - { - s_chan[ch].ADSRX.EnvelopeVol=0; - // don't stop if this chan can still cause irqs - if(!(spuCtrl&0x40) || (s_chan[ch].pCurr > pSpuIrq && s_chan[ch].pLoop > pSpuIrq)) - //s_chan[ch].bOn=0; - s_chan[ch].pCurr=(unsigned char *)-1; - //s_chan[ch].bReverb=0; - //s_chan[ch].bNoise=0; - } - - s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; - return s_chan[ch].ADSRX.lVolume; - } - else // not stopped yet? - { - if(s_chan[ch].ADSRX.State==0) // -> attack - { - if(s_chan[ch].ADSRX.AttackModeExp) - { - if(s_chan[ch].ADSRX.EnvelopeVol<0x60000000) - s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32]; - else - s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x18 + 32]; - } - else - { - s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32]; - } - - if(s_chan[ch].ADSRX.EnvelopeVol<0) - { - s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF; - s_chan[ch].ADSRX.State=1; - } + { + for (; ns < ns_to; ns++) + { + EnvelopeVol += val; + if (EnvelopeVol < 0) + break; + + ChanBuf[ns] *= EnvelopeVol >> 21; + ChanBuf[ns] >>= 10; + } + } + + if (EnvelopeVol < 0) + goto stop; + + goto done; + } + + switch (s_chan[ch].ADSRX.State) + { + case 0: // -> attack + rto = 0; + if (s_chan[ch].ADSRX.AttackModeExp && EnvelopeVol >= 0x60000000) + rto = 8; + val = RateTableAdd[s_chan[ch].ADSRX.AttackRate + rto]; + + for (; ns < ns_to; ns++) + { + EnvelopeVol += val; + if (EnvelopeVol < 0) + break; + + ChanBuf[ns] *= EnvelopeVol >> 21; + ChanBuf[ns] >>= 10; + } + + if (EnvelopeVol < 0) // overflow + { + EnvelopeVol = 0x7fffffff; + s_chan[ch].ADSRX.State = 1; + ns++; // sample is good already + goto decay; + } + break; - s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; - return s_chan[ch].ADSRX.lVolume; - } //--------------------------------------------------// - if(s_chan[ch].ADSRX.State==1) // -> decay - { - switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7) - { - case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+0 + 32]; break; - case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+4 + 32]; break; - case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+6 + 32]; break; - case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+8 + 32]; break; - case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+9 + 32]; break; - case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+10+ 32]; break; - case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+11+ 32]; break; - case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+12+ 32]; break; - } + decay: + case 1: // -> decay + val = RateTableSub[s_chan[ch].ADSRX.DecayRate * 4]; + level = s_chan[ch].ADSRX.SustainLevel; + + for (; ns < ns_to; ) + { + EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16); + if (EnvelopeVol < 0) + EnvelopeVol = 0; + + ChanBuf[ns] *= EnvelopeVol >> 21; + ChanBuf[ns] >>= 10; + ns++; + + if (((EnvelopeVol >> 27) & 0xf) <= level) + { + s_chan[ch].ADSRX.State = 2; + goto sustain; + } + } + break; - if(s_chan[ch].ADSRX.EnvelopeVol<0) s_chan[ch].ADSRX.EnvelopeVol=0; - if(((s_chan[ch].ADSRX.EnvelopeVol>>27)&0xF) <= s_chan[ch].ADSRX.SustainLevel) - { - s_chan[ch].ADSRX.State=2; - } - - s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; - return s_chan[ch].ADSRX.lVolume; - } //--------------------------------------------------// - if(s_chan[ch].ADSRX.State==2) // -> sustain - { - if(s_chan[ch].ADSRX.SustainIncrease) - { - if(s_chan[ch].ADSRX.SustainModeExp) - { - if(s_chan[ch].ADSRX.EnvelopeVol<0x60000000) - s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x10 + 32]; - else - s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x18 + 32]; - } - else - { - s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x10 + 32]; - } - - if(s_chan[ch].ADSRX.EnvelopeVol<0) - { - s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF; - } - } + sustain: + case 2: // -> sustain + if (s_chan[ch].ADSRX.SustainIncrease) + { + if (EnvelopeVol >= 0x7fff0000) + break; + + rto = 0; + if (s_chan[ch].ADSRX.SustainModeExp && EnvelopeVol >= 0x60000000) + rto = 8; + val = RateTableAdd[s_chan[ch].ADSRX.SustainRate + rto]; + + for (; ns < ns_to; ns++) + { + EnvelopeVol += val; + if ((unsigned int)EnvelopeVol >= 0x7fe00000) + { + EnvelopeVol = 0x7fffffff; + break; + } + + ChanBuf[ns] *= EnvelopeVol >> 21; + ChanBuf[ns] >>= 10; + } + } else - { - if(s_chan[ch].ADSRX.SustainModeExp) - { - switch((s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7) - { - case 0: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +0 + 32];break; - case 1: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +4 + 32];break; - case 2: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +6 + 32];break; - case 3: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +8 + 32];break; - case 4: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +9 + 32];break; - case 5: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +10+ 32];break; - case 6: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +11+ 32];break; - case 7: s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B +12+ 32];break; - } - } + { + val = RateTableSub[s_chan[ch].ADSRX.SustainRate]; + if (s_chan[ch].ADSRX.SustainModeExp) + { + for (; ns < ns_to; ns++) + { + EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16); + if (EnvelopeVol < 0) + goto stop; + + ChanBuf[ns] *= EnvelopeVol >> 21; + ChanBuf[ns] >>= 10; + } + } else - { - s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x0F + 32]; - } - - if(s_chan[ch].ADSRX.EnvelopeVol<0) - { - s_chan[ch].ADSRX.EnvelopeVol=0; - } - } - s_chan[ch].ADSRX.lVolume=s_chan[ch].ADSRX.EnvelopeVol>>21; - return s_chan[ch].ADSRX.lVolume; - } - } - return 0; + { + for (; ns < ns_to; ns++) + { + EnvelopeVol += val; + if (EnvelopeVol < 0) + goto stop; + + ChanBuf[ns] *= EnvelopeVol >> 21; + ChanBuf[ns] >>= 10; + } + } + } + break; + } + +done: + s_chan[ch].ADSRX.EnvelopeVol = EnvelopeVol; + return; + +stop: + memset(&ChanBuf[ns], 0, (ns_to - ns) * sizeof(ChanBuf[0])); + s_chan[ch].ADSRX.EnvelopeVol = 0; + dwChannelOn &= ~(1<