\r
INLINE void StartADSR(int ch) // MIX ADSR\r
{\r
- s_chan[ch].ADSRX.State=0; // and init some adsr vars\r
- s_chan[ch].ADSRX.EnvelopeVol=0;\r
+ spu.s_chan[ch].ADSRX.State = ADSR_ATTACK; // and init some adsr vars\r
+ spu.s_chan[ch].ADSRX.EnvelopeVol = 0;\r
}\r
\r
////////////////////////////////////////////////////////////////////////\r
\r
-static void MixADSR(int ch, int ns, int ns_to) // MIX ADSR\r
+static int MixADSR(ADSRInfoEx *adsr, int ns_to)\r
{\r
- int EnvelopeVol = s_chan[ch].ADSRX.EnvelopeVol;\r
- int val, rto, level;\r
+ unsigned int EnvelopeVol = adsr->EnvelopeVol;\r
+ int ns = 0, val, rto, level;\r
\r
- if (s_chan[ch].bStop) // should be stopped:\r
- { // do release\r
- val = RateTableSub[s_chan[ch].ADSRX.ReleaseRate * 4];\r
+ if (adsr->State == ADSR_RELEASE)\r
+ {\r
+ val = RateTableSub[adsr->ReleaseRate * 4];\r
\r
- if (s_chan[ch].ADSRX.ReleaseModeExp)\r
+ if (adsr->ReleaseModeExp)\r
{\r
for (; ns < ns_to; ns++)\r
{\r
EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);\r
- if (EnvelopeVol <= 0)\r
+ if ((signed int)EnvelopeVol <= 0)\r
break;\r
\r
- ChanBuf[ns] *= EnvelopeVol >> 21;\r
+ ChanBuf[ns] *= (signed int)EnvelopeVol >> 21;\r
ChanBuf[ns] >>= 10;\r
}\r
}\r
for (; ns < ns_to; ns++)\r
{\r
EnvelopeVol += val;\r
- if (EnvelopeVol <= 0)\r
+ if ((signed int)EnvelopeVol <= 0)\r
break;\r
\r
- ChanBuf[ns] *= EnvelopeVol >> 21;\r
+ ChanBuf[ns] *= (signed int)EnvelopeVol >> 21;\r
ChanBuf[ns] >>= 10;\r
}\r
}\r
\r
- if (EnvelopeVol <= 0)\r
- goto stop;\r
-\r
goto done;\r
}\r
\r
- switch (s_chan[ch].ADSRX.State)\r
+ switch (adsr->State)\r
{\r
- case 0: // -> attack\r
+ case ADSR_ATTACK: // -> attack\r
rto = 0;\r
- if (s_chan[ch].ADSRX.AttackModeExp && EnvelopeVol >= 0x60000000)\r
+ if (adsr->AttackModeExp && EnvelopeVol >= 0x60000000)\r
rto = 8;\r
- val = RateTableAdd[s_chan[ch].ADSRX.AttackRate + rto];\r
+ val = RateTableAdd[adsr->AttackRate + rto];\r
\r
for (; ns < ns_to; ns++)\r
{\r
EnvelopeVol += val;\r
- if (EnvelopeVol < 0)\r
+ if ((signed int)EnvelopeVol < 0) // overflow\r
break;\r
\r
- ChanBuf[ns] *= EnvelopeVol >> 21;\r
+ ChanBuf[ns] *= (signed int)EnvelopeVol >> 21;\r
ChanBuf[ns] >>= 10;\r
}\r
\r
- if (EnvelopeVol < 0) // overflow\r
+ if ((signed int)EnvelopeVol < 0) // overflow\r
{\r
EnvelopeVol = 0x7fffffff;\r
- s_chan[ch].ADSRX.State = 1;\r
+ adsr->State = ADSR_DECAY;\r
ns++; // sample is good already\r
goto decay;\r
}\r
\r
//--------------------------------------------------//\r
decay:\r
- case 1: // -> decay\r
- val = RateTableSub[s_chan[ch].ADSRX.DecayRate * 4];\r
- level = s_chan[ch].ADSRX.SustainLevel;\r
+ case ADSR_DECAY: // -> decay\r
+ val = RateTableSub[adsr->DecayRate * 4];\r
+ level = adsr->SustainLevel;\r
\r
for (; ns < ns_to; )\r
{\r
EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);\r
- if (EnvelopeVol < 0)\r
+ if ((signed int)EnvelopeVol < 0)\r
EnvelopeVol = 0;\r
\r
ChanBuf[ns] *= EnvelopeVol >> 21;\r
\r
if (((EnvelopeVol >> 27) & 0xf) <= level)\r
{\r
- s_chan[ch].ADSRX.State = 2;\r
+ adsr->State = ADSR_SUSTAIN;\r
goto sustain;\r
}\r
}\r
\r
//--------------------------------------------------//\r
sustain:\r
- case 2: // -> sustain\r
- if (s_chan[ch].ADSRX.SustainIncrease)\r
+ case ADSR_SUSTAIN: // -> sustain\r
+ if (adsr->SustainIncrease)\r
{\r
if (EnvelopeVol >= 0x7fff0000)\r
+ {\r
+ ns = ns_to;\r
break;\r
+ }\r
\r
rto = 0;\r
- if (s_chan[ch].ADSRX.SustainModeExp && EnvelopeVol >= 0x60000000)\r
+ if (adsr->SustainModeExp && EnvelopeVol >= 0x60000000)\r
rto = 8;\r
- val = RateTableAdd[s_chan[ch].ADSRX.SustainRate + rto];\r
+ val = RateTableAdd[adsr->SustainRate + rto];\r
\r
for (; ns < ns_to; ns++)\r
{\r
EnvelopeVol += val;\r
- if ((unsigned int)EnvelopeVol >= 0x7fe00000)\r
+ if (EnvelopeVol >= 0x7fe00000)\r
{\r
EnvelopeVol = 0x7fffffff;\r
+ ns = ns_to;\r
break;\r
}\r
\r
- ChanBuf[ns] *= EnvelopeVol >> 21;\r
+ ChanBuf[ns] *= (signed int)EnvelopeVol >> 21;\r
ChanBuf[ns] >>= 10;\r
}\r
}\r
else\r
{\r
- val = RateTableSub[s_chan[ch].ADSRX.SustainRate];\r
- if (s_chan[ch].ADSRX.SustainModeExp)\r
+ val = RateTableSub[adsr->SustainRate];\r
+ if (adsr->SustainModeExp)\r
{\r
for (; ns < ns_to; ns++)\r
{\r
EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);\r
- if (EnvelopeVol < 0) \r
- goto stop;\r
+ if ((signed int)EnvelopeVol < 0)\r
+ break;\r
\r
- ChanBuf[ns] *= EnvelopeVol >> 21;\r
+ ChanBuf[ns] *= (signed int)EnvelopeVol >> 21;\r
ChanBuf[ns] >>= 10;\r
}\r
}\r
for (; ns < ns_to; ns++)\r
{\r
EnvelopeVol += val;\r
- if (EnvelopeVol < 0) \r
- goto stop;\r
+ if ((signed int)EnvelopeVol < 0)\r
+ break;\r
\r
- ChanBuf[ns] *= EnvelopeVol >> 21;\r
+ ChanBuf[ns] *= (signed int)EnvelopeVol >> 21;\r
ChanBuf[ns] >>= 10;\r
}\r
}\r
}\r
\r
done:\r
- s_chan[ch].ADSRX.EnvelopeVol = EnvelopeVol;\r
- return;\r
+ adsr->EnvelopeVol = EnvelopeVol;\r
+ return ns;\r
+}\r
+\r
+static int SkipADSR(ADSRInfoEx *adsr, int ns_to)\r
+{\r
+ unsigned int EnvelopeVol = adsr->EnvelopeVol;\r
+ int ns = 0, val, rto, level;\r
+ int64_t v64;\r
+\r
+ if (adsr->State == ADSR_RELEASE)\r
+ {\r
+ val = RateTableSub[adsr->ReleaseRate * 4];\r
+ if (adsr->ReleaseModeExp)\r
+ {\r
+ for (; ns < ns_to; ns++)\r
+ {\r
+ EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);\r
+ if ((signed int)EnvelopeVol <= 0)\r
+ break;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ v64 = EnvelopeVol;\r
+ v64 += (int64_t)val * ns_to;\r
+ EnvelopeVol = (int)v64;\r
+ if (v64 > 0)\r
+ ns = ns_to;\r
+ }\r
+ goto done;\r
+ }\r
+\r
+ switch (adsr->State)\r
+ {\r
+ case ADSR_ATTACK: // -> attack\r
+ rto = 0;\r
+ if (adsr->AttackModeExp && EnvelopeVol >= 0x60000000)\r
+ rto = 8;\r
+ val = RateTableAdd[adsr->AttackRate + rto];\r
+\r
+ for (; ns < ns_to; ns++)\r
+ {\r
+ EnvelopeVol += val;\r
+ if ((signed int)EnvelopeVol < 0)\r
+ break;\r
+ }\r
+ if ((signed int)EnvelopeVol < 0) // overflow\r
+ {\r
+ EnvelopeVol = 0x7fffffff;\r
+ adsr->State = ADSR_DECAY;\r
+ ns++;\r
+ goto decay;\r
+ }\r
+ break;\r
+\r
+ //--------------------------------------------------//\r
+ decay:\r
+ case ADSR_DECAY: // -> decay\r
+ val = RateTableSub[adsr->DecayRate * 4];\r
+ level = adsr->SustainLevel;\r
+\r
+ for (; ns < ns_to; )\r
+ {\r
+ EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);\r
+ if ((signed int)EnvelopeVol < 0)\r
+ EnvelopeVol = 0;\r
+\r
+ ns++;\r
+\r
+ if (((EnvelopeVol >> 27) & 0xf) <= level)\r
+ {\r
+ adsr->State = ADSR_SUSTAIN;\r
+ goto sustain;\r
+ }\r
+ }\r
+ break;\r
+\r
+ //--------------------------------------------------//\r
+ sustain:\r
+ case ADSR_SUSTAIN: // -> sustain\r
+ if (adsr->SustainIncrease)\r
+ {\r
+ ns = ns_to;\r
+\r
+ if (EnvelopeVol >= 0x7fff0000)\r
+ break;\r
+\r
+ rto = 0;\r
+ if (adsr->SustainModeExp && EnvelopeVol >= 0x60000000)\r
+ rto = 8;\r
+ val = RateTableAdd[adsr->SustainRate + rto];\r
\r
-stop:\r
- memset(&ChanBuf[ns], 0, (ns_to - ns) * sizeof(ChanBuf[0]));\r
- s_chan[ch].ADSRX.EnvelopeVol = 0;\r
- spu.dwChannelOn &= ~(1<<ch);\r
+ v64 = EnvelopeVol;\r
+ v64 += (int64_t)val * (ns_to - ns);\r
+ EnvelopeVol = (int)v64;\r
+ if (v64 >= 0x7fe00000ll)\r
+ EnvelopeVol = 0x7fffffff;\r
+ }\r
+ else\r
+ {\r
+ val = RateTableSub[adsr->SustainRate];\r
+ if (adsr->SustainModeExp)\r
+ {\r
+ for (; ns < ns_to; ns++)\r
+ {\r
+ EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);\r
+ if ((signed int)EnvelopeVol < 0)\r
+ break;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ v64 = EnvelopeVol;\r
+ v64 += (int64_t)val * (ns_to - ns);\r
+ EnvelopeVol = (int)v64;\r
+ if (v64 > 0)\r
+ ns = ns_to;\r
+ }\r
+ }\r
+ break;\r
+ }\r
+\r
+done:\r
+ adsr->EnvelopeVol = EnvelopeVol;\r
+ return ns;\r
}\r
\r
#endif\r