aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/dfsound/adsr.c219
-rw-r--r--plugins/dfsound/spu.c28
2 files changed, 156 insertions, 91 deletions
diff --git a/plugins/dfsound/adsr.c b/plugins/dfsound/adsr.c
index 9884d62..e4873df 100644
--- a/plugins/dfsound/adsr.c
+++ b/plugins/dfsound/adsr.c
@@ -26,27 +26,27 @@
// 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;
+ }
}
////////////////////////////////////////////////////////////////////////
@@ -59,100 +59,161 @@ INLINE void StartADSR(int ch) // MIX ADSR
////////////////////////////////////////////////////////////////////////
-INLINE int MixADSR(int ch) // MIX ADSR
-{
- static const char ratetable_offset[8] = { 0, 4, 6, 8, 9, 10, 11, 12 };
- int rto;
+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;
- 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];
- }
+ 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<<ch);
- //s_chan[ch].bReverb=0;
- //s_chan[ch].bNoise=0;
- }
+ ChanBuf[ns] *= EnvelopeVol >> 21;
+ ChanBuf[ns] >>= 10;
+ }
+ }
+
+ if (EnvelopeVol < 0)
+ goto stop;
goto done;
- }
+ }
- switch(s_chan[ch].ADSRX.State) // not stopped yet
- {
+ switch (s_chan[ch].ADSRX.State)
+ {
case 0: // -> attack
- rto=8;
- if(s_chan[ch].ADSRX.AttackModeExp&&s_chan[ch].ADSRX.EnvelopeVol>=0x60000000)
rto = 0;
- s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x18 + rto + 32];
+ if (s_chan[ch].ADSRX.AttackModeExp && EnvelopeVol >= 0x60000000)
+ rto = 8;
+ val = RateTableAdd[s_chan[ch].ADSRX.AttackRate + rto];
- if(s_chan[ch].ADSRX.EnvelopeVol<0)
+ for (; ns < ns_to; ns++)
{
- s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF;
- s_chan[ch].ADSRX.State=1;
+ EnvelopeVol += val;
+ if (EnvelopeVol < 0)
+ break;
+
+ ChanBuf[ns] *= EnvelopeVol >> 21;
+ ChanBuf[ns] >>= 10;
}
- break;
+
+ if (EnvelopeVol < 0) // overflow
+ {
+ EnvelopeVol = 0x7fffffff;
+ s_chan[ch].ADSRX.State = 1;
+ ns++; // sample is good already
+ goto decay;
+ }
+ break;
//--------------------------------------------------//
+ decay:
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];
+ val = RateTableSub[s_chan[ch].ADSRX.DecayRate * 4];
+ level = s_chan[ch].ADSRX.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)
+ {
+ s_chan[ch].ADSRX.State = 2;
+ goto sustain;
+ }
}
- break;
+ break;
//--------------------------------------------------//
+ sustain:
case 2: // -> sustain
- if(s_chan[ch].ADSRX.SustainIncrease)
+ if (s_chan[ch].ADSRX.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)
+ break;
+
+ rto = 0;
+ if (s_chan[ch].ADSRX.SustainModeExp && EnvelopeVol >= 0x60000000)
+ rto = 8;
+ val = RateTableAdd[s_chan[ch].ADSRX.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;
+ break;
+ }
+
+ ChanBuf[ns] *= EnvelopeVol >> 21;
+ ChanBuf[ns] >>= 10;
}
}
- else
+ else
{
- if(s_chan[ch].ADSRX.SustainModeExp)
- {
- rto=ratetable_offset[(s_chan[ch].ADSRX.EnvelopeVol>>28)&0x7];
- }
- else
+ val = RateTableSub[s_chan[ch].ADSRX.SustainRate];
+ if (s_chan[ch].ADSRX.SustainModeExp)
{
- rto=12;
+ for (; ns < ns_to; ns++)
+ {
+ EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);
+ if (EnvelopeVol < 0)
+ goto stop;
+
+ ChanBuf[ns] *= EnvelopeVol >> 21;
+ ChanBuf[ns] >>= 10;
+ }
}
- s_chan[ch].ADSRX.EnvelopeVol-=RateTable[((s_chan[ch].ADSRX.SustainRate^0x7F))-0x1B + rto + 32];
-
- if(s_chan[ch].ADSRX.EnvelopeVol<0)
+ else
{
- s_chan[ch].ADSRX.EnvelopeVol=0;
+ for (; ns < ns_to; ns++)
+ {
+ EnvelopeVol += val;
+ if (EnvelopeVol < 0)
+ goto stop;
+
+ ChanBuf[ns] *= EnvelopeVol >> 21;
+ ChanBuf[ns] >>= 10;
+ }
}
}
- break;
- }
+ break;
+ }
done:
- return s_chan[ch].ADSRX.EnvelopeVol>>21;
+ 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<<ch);
}
#endif
diff --git a/plugins/dfsound/spu.c b/plugins/dfsound/spu.c
index 228267d..79e534c 100644
--- a/plugins/dfsound/spu.c
+++ b/plugins/dfsound/spu.c
@@ -108,6 +108,7 @@ static const int f[8][2] = { { 0, 0 },
{ 115, -52 },
{ 98, -55 },
{ 122, -60 } };
+int ChanBuf[NSSIZE];
int SSumLR[NSSIZE*2];
int iFMod[NSSIZE];
int iCycle = 0;
@@ -597,8 +598,6 @@ static void *MAINThread(void *arg)
for(ns=ns_from;ns<ns_to;ns++) // loop until 1 ms of data is reached
{
- int sval;
-
if(!(dwChannelOn&(1<<ch))) break; // something turned ch off (adsr or flags)
if(s_chan[ch].bFMod==1 && iFMod[ns]) // fmod freq channel
@@ -628,12 +627,23 @@ static void *MAINThread(void *arg)
if(s_chan[ch].bNoise)
fa=iGetNoiseVal(ch); // get noise val
else fa=iGetInterpolationVal(ch); // get sample val
+ ChanBuf[ns]=fa;
+
+ ////////////////////////////////////////////////
+ // ok, go on until 1 ms data of this channel is collected
+
+ s_chan[ch].spos += s_chan[ch].sinc;
+ENDX: ;
+ }
- sval = (MixADSR(ch) * fa) / 1024; // mix adsr
+ MixADSR(ch, ns_from, ns_to);
+
+ if(s_chan[ch].bFMod==2) // fmod freq channel
+ memcpy(iFMod, ChanBuf, sizeof(iFMod));
+ else for(ns=ns_from;ns<ns_to;ns++)
+ {
+ int sval = ChanBuf[ns];
- if(s_chan[ch].bFMod==2) // fmod freq channel
- iFMod[ns]=sval; // -> store 1T sample data, use that to do fmod on next channel
- else // no fmod freq channel
{
//////////////////////////////////////////////
// ok, left/right sound volume (psx volume goes from 0 ... 0x3fff)
@@ -646,13 +656,7 @@ static void *MAINThread(void *arg)
if(s_chan[ch].bRVBActive) StoreREVERB(ch,ns,sval);
}
-
- ////////////////////////////////////////////////
- // ok, go on until 1 ms data of this channel is collected
-
- s_chan[ch].spos += s_chan[ch].sinc;
}
-ENDX: ;
}
}