X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=plugins%2Fdfsound%2Fadsr.c;h=9e328620a0ca52201c9ec1193ce43b6d5820becc;hp=9884d624508655c633a62425b10617cc8ee221fe;hb=8a55ebcc07d4f860633db8c77bb9e16bcfa03313;hpb=a02dc3f33f8ac5ac22106e3417cac0d736628cd4 diff --git a/plugins/dfsound/adsr.c b/plugins/dfsound/adsr.c index 9884d624..9e328620 100644 --- a/plugins/dfsound/adsr.c +++ b/plugins/dfsound/adsr.c @@ -26,133 +26,322 @@ // ADSR func //////////////////////////////////////////////////////////////////////// -unsigned int RateTable[160]; +static int RateTableAdd[128]; +static int RateTableSub[128]; void InitADSR(void) // INIT ADSR { - unsigned int 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; + + // XXX: this is wrong, we need more bits.. + if (RateTableAdd[lcv] == 0) + RateTableAdd[lcv] = 1; + } } //////////////////////////////////////////////////////////////////////// INLINE void StartADSR(int ch) // MIX ADSR { - s_chan[ch].ADSRX.State=0; // and init some adsr vars - s_chan[ch].ADSRX.EnvelopeVol=0; + spu.s_chan[ch].ADSRX.State = ADSR_ATTACK; // and init some adsr vars + spu.s_chan[ch].ADSRX.EnvelopeVol = 0; } //////////////////////////////////////////////////////////////////////// -INLINE int MixADSR(int ch) // MIX ADSR -{ - static const char ratetable_offset[8] = { 0, 4, 6, 8, 9, 10, 11, 12 }; - int rto; +static int MixADSR(ADSRInfoEx *adsr, int ns_to) +{ + int EnvelopeVol = adsr->EnvelopeVol; + int ns = 0, val, rto, level; + + if (adsr->State == ADSR_RELEASE) + { + val = RateTableSub[adsr->ReleaseRate * 4]; - if(s_chan[ch].bStop) // should be stopped: - { // do release - if(s_chan[ch].ADSRX.ReleaseModeExp) - { - rto=ratetable_offset[(s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7]; - } + if (adsr->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 - { - rto=12; - } - s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x18 + rto + 32]; + { + for (; ns < ns_to; ns++) + { + EnvelopeVol += val; + if (EnvelopeVol <= 0) + break; - if(s_chan[ch].ADSRX.EnvelopeVol<0) - { - s_chan[ch].ADSRX.EnvelopeVol=0; - // FIXME: 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; - dwChannelOn&=~(1<> 21; + ChanBuf[ns] >>= 10; + } + } goto done; - } + } - switch(s_chan[ch].ADSRX.State) // not stopped yet - { - case 0: // -> attack - rto=8; - if(s_chan[ch].ADSRX.AttackModeExp&&s_chan[ch].ADSRX.EnvelopeVol>=0x60000000) + switch (adsr->State) + { + case ADSR_ATTACK: // -> attack rto = 0; - s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x18 + rto + 32]; + if (adsr->AttackModeExp && EnvelopeVol >= 0x60000000) + rto = 8; + val = RateTableAdd[adsr->AttackRate + rto]; + + for (; ns < ns_to; ns++) + { + EnvelopeVol += val; + if (EnvelopeVol < 0) + break; + + ChanBuf[ns] *= EnvelopeVol >> 21; + ChanBuf[ns] >>= 10; + } - if(s_chan[ch].ADSRX.EnvelopeVol<0) + if (EnvelopeVol < 0) // overflow { - s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF; - s_chan[ch].ADSRX.State=1; + EnvelopeVol = 0x7fffffff; + adsr->State = ADSR_DECAY; + ns++; // sample is good already + goto decay; } - break; + break; //--------------------------------------------------// - case 1: // -> decay - rto=ratetable_offset[(s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7]; - s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.DecayRate^0x1F))-0x18+ rto + 32]; + decay: + case ADSR_DECAY: // -> decay + val = RateTableSub[adsr->DecayRate * 4]; + level = adsr->SustainLevel; - 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) + for (; ns < ns_to; ) { - s_chan[ch].ADSRX.State=2; + 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) + { + adsr->State = ADSR_SUSTAIN; + goto sustain; + } } - break; + break; //--------------------------------------------------// - case 2: // -> sustain - if(s_chan[ch].ADSRX.SustainIncrease) + sustain: + case ADSR_SUSTAIN: // -> sustain + if (adsr->SustainIncrease) { - rto=8; - if(s_chan[ch].ADSRX.SustainModeExp&&s_chan[ch].ADSRX.EnvelopeVol>=0x60000000) - rto=0; - s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.SustainRate^0x7F)-0x18 + rto + 32]; + if (EnvelopeVol >= 0x7fff0000) + { + ns = ns_to; + break; + } + + rto = 0; + if (adsr->SustainModeExp && EnvelopeVol >= 0x60000000) + rto = 8; + val = RateTableAdd[adsr->SustainRate + rto]; - if(s_chan[ch].ADSRX.EnvelopeVol<0) + for (; ns < ns_to; ns++) { - s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF; + EnvelopeVol += val; + if ((unsigned int)EnvelopeVol >= 0x7fe00000) + { + EnvelopeVol = 0x7fffffff; + ns = ns_to; + break; + } + + ChanBuf[ns] *= EnvelopeVol >> 21; + ChanBuf[ns] >>= 10; } } - else + else { - if(s_chan[ch].ADSRX.SustainModeExp) + val = RateTableSub[adsr->SustainRate]; + if (adsr->SustainModeExp) + { + for (; ns < ns_to; ns++) + { + EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16); + if (EnvelopeVol < 0) + break; + + ChanBuf[ns] *= EnvelopeVol >> 21; + ChanBuf[ns] >>= 10; + } + } + else { - rto=ratetable_offset[(s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7]; + for (; ns < ns_to; ns++) + { + EnvelopeVol += val; + if (EnvelopeVol < 0) + break; + + ChanBuf[ns] *= EnvelopeVol >> 21; + ChanBuf[ns] >>= 10; + } } - else + } + break; + } + +done: + adsr->EnvelopeVol = EnvelopeVol; + return ns; +} + +static int SkipADSR(ADSRInfoEx *adsr, int ns_to) +{ + int EnvelopeVol = adsr->EnvelopeVol; + int ns = 0, val, rto, level; + int64_t v64; + + if (adsr->State == ADSR_RELEASE) + { + val = RateTableSub[adsr->ReleaseRate * 4]; + if (adsr->ReleaseModeExp) + { + for (; ns < ns_to; ns++) + { + EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16); + if (EnvelopeVol <= 0) + break; + } + } + else + { + v64 = EnvelopeVol; + v64 += (int64_t)val * ns_to; + EnvelopeVol = (int)v64; + if (v64 > 0) + ns = ns_to; + } + goto done; + } + + switch (adsr->State) + { + case ADSR_ATTACK: // -> attack + rto = 0; + if (adsr->AttackModeExp && EnvelopeVol >= 0x60000000) + rto = 8; + val = RateTableAdd[adsr->AttackRate + rto]; + + for (; ns < ns_to; ns++) + { + EnvelopeVol += val; + if (EnvelopeVol < 0) + break; + } + if (EnvelopeVol < 0) // overflow + { + EnvelopeVol = 0x7fffffff; + adsr->State = ADSR_DECAY; + ns++; + goto decay; + } + break; + + //--------------------------------------------------// + decay: + case ADSR_DECAY: // -> decay + val = RateTableSub[adsr->DecayRate * 4]; + level = adsr->SustainLevel; + + for (; ns < ns_to; ) + { + EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16); + if (EnvelopeVol < 0) + EnvelopeVol = 0; + + ns++; + + if (((EnvelopeVol >> 27) & 0xf) <= level) { - rto=12; + adsr->State = ADSR_SUSTAIN; + goto sustain; } - s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B + rto + 32]; + } + break; + + //--------------------------------------------------// + sustain: + case ADSR_SUSTAIN: // -> sustain + if (adsr->SustainIncrease) + { + ns = ns_to; + + if (EnvelopeVol >= 0x7fff0000) + break; + + rto = 0; + if (adsr->SustainModeExp && EnvelopeVol >= 0x60000000) + rto = 8; + val = RateTableAdd[adsr->SustainRate + rto]; - if(s_chan[ch].ADSRX.EnvelopeVol<0) + v64 = EnvelopeVol; + v64 += (int64_t)val * (ns_to - ns); + EnvelopeVol = (int)v64; + if (v64 >= 0x7fe00000ll) + EnvelopeVol = 0x7fffffff; + } + else + { + val = RateTableSub[adsr->SustainRate]; + if (adsr->SustainModeExp) { - s_chan[ch].ADSRX.EnvelopeVol=0; + for (; ns < ns_to; ns++) + { + EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16); + if (EnvelopeVol < 0) + break; + } + } + else + { + v64 = EnvelopeVol; + v64 += (int64_t)val * (ns_to - ns); + EnvelopeVol = (int)v64; + if (v64 > 0) + { + ns = ns_to; + break; + } } } - break; - } + break; + } done: - return s_chan[ch].ADSRX.EnvelopeVol>>21; + adsr->EnvelopeVol = EnvelopeVol; + return ns; } #endif