- {\r
- s_chan[ch].ADSRX.EnvelopeVol-=RateTable[(4*(s_chan[ch].ADSRX.ReleaseRate^0x1F))-0x0C + 32];\r
- }\r
-\r
- if(s_chan[ch].ADSRX.EnvelopeVol<0) \r
- {\r
- s_chan[ch].ADSRX.EnvelopeVol=0;\r
- // don't stop if this chan can still cause irqs\r
- if(!(spuCtrl&0x40) || (s_chan[ch].pCurr > pSpuIrq && s_chan[ch].pLoop > pSpuIrq))\r
- //s_chan[ch].bOn=0;\r
- s_chan[ch].pCurr=(unsigned char *)-1;\r
- //s_chan[ch].bReverb=0;\r
- //s_chan[ch].bNoise=0;\r
- }\r
-\r
- return s_chan[ch].ADSRX.EnvelopeVol>>21;\r
- }\r
- else // not stopped yet?\r
- {\r
- if(s_chan[ch].ADSRX.State==0) // -> attack\r
- {\r
- if(s_chan[ch].ADSRX.AttackModeExp)\r
- {\r
- if(s_chan[ch].ADSRX.EnvelopeVol<0x60000000) \r
- s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32];\r
- else\r
- s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x18 + 32];\r
- }\r
- else\r
- {\r
- s_chan[ch].ADSRX.EnvelopeVol+=RateTable[(s_chan[ch].ADSRX.AttackRate^0x7F)-0x10 + 32];\r
- }\r
-\r
- if(s_chan[ch].ADSRX.EnvelopeVol<0) \r
- {\r
- s_chan[ch].ADSRX.EnvelopeVol=0x7FFFFFFF;\r
- s_chan[ch].ADSRX.State=1;\r
- }\r
+ {\r
+ for (; ns < ns_to; ns++)\r
+ {\r
+ EnvelopeVol += val;\r
+ if (EnvelopeVol < 0)\r
+ break;\r
+\r
+ ChanBuf[ns] *= 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
+ {\r
+ case 0: // -> attack\r
+ rto = 0;\r
+ if (s_chan[ch].ADSRX.AttackModeExp && EnvelopeVol >= 0x60000000)\r
+ rto = 8;\r
+ val = RateTableAdd[s_chan[ch].ADSRX.AttackRate + rto];\r
+\r
+ for (; ns < ns_to; ns++)\r
+ {\r
+ EnvelopeVol += val;\r
+ if (EnvelopeVol < 0)\r
+ break;\r
+\r
+ ChanBuf[ns] *= EnvelopeVol >> 21;\r
+ ChanBuf[ns] >>= 10;\r
+ }\r
+\r
+ if (EnvelopeVol < 0) // overflow\r
+ {\r
+ EnvelopeVol = 0x7fffffff;\r
+ s_chan[ch].ADSRX.State = 1;\r
+ ns++; // sample is good already\r
+ goto decay;\r
+ }\r
+ break;\r