spu: get rid of iSPUIRQWait
[pcsx_rearmed.git] / plugins / dfsound / adsr.c
CommitLineData
ef79bbde
P
1/***************************************************************************\r
2 adsr.c - description\r
3 -------------------\r
4 begin : Wed May 15 2002\r
5 copyright : (C) 2002 by Pete Bernert\r
6 email : BlackDove@addcom.de\r
7 ***************************************************************************/\r
8/***************************************************************************\r
9 * *\r
10 * This program is free software; you can redistribute it and/or modify *\r
11 * it under the terms of the GNU General Public License as published by *\r
12 * the Free Software Foundation; either version 2 of the License, or *\r
13 * (at your option) any later version. See also the license.txt file for *\r
14 * additional informations. *\r
15 * *\r
16 ***************************************************************************/\r
17\r
18#include "stdafx.h"\r
19\r
20#define _IN_ADSR\r
21\r
22// will be included from spu.c\r
23#ifdef _IN_SPU\r
24\r
25////////////////////////////////////////////////////////////////////////\r
26// ADSR func\r
27////////////////////////////////////////////////////////////////////////\r
28\r
1ab7621a 29static int RateTableAdd[128];\r
30static int RateTableSub[128];\r
ef79bbde
P
31\r
32void InitADSR(void) // INIT ADSR\r
33{\r
1ab7621a 34 int lcv, denom;\r
35\r
36 // Optimize table - Dr. Hell ADSR math\r
37 for (lcv = 0; lcv < 48; lcv++)\r
38 {\r
39 RateTableAdd[lcv] = (7 - (lcv&3)) << (11 + 16 - (lcv >> 2));\r
40 RateTableSub[lcv] = (-8 + (lcv&3)) << (11 + 16 - (lcv >> 2));\r
41 }\r
42\r
43 for (; lcv < 128; lcv++)\r
44 {\r
45 denom = 1 << ((lcv>>2) - 11);\r
46\r
47 RateTableAdd[lcv] = ((7 - (lcv&3)) << 16) / denom;\r
48 RateTableSub[lcv] = ((-8 + (lcv&3)) << 16) / denom;\r
49 }\r
ef79bbde
P
50}\r
51\r
52////////////////////////////////////////////////////////////////////////\r
53\r
54INLINE void StartADSR(int ch) // MIX ADSR\r
55{\r
6d866bb7 56 s_chan[ch].ADSRX.State=0; // and init some adsr vars\r
ef79bbde
P
57 s_chan[ch].ADSRX.EnvelopeVol=0;\r
58}\r
59\r
60////////////////////////////////////////////////////////////////////////\r
61\r
1ab7621a 62static void MixADSR(int ch, int ns, int ns_to) // MIX ADSR\r
63{\r
64 int EnvelopeVol = s_chan[ch].ADSRX.EnvelopeVol;\r
65 int val, rto, level;\r
66\r
67 if (s_chan[ch].bStop) // should be stopped:\r
68 { // do release\r
69 val = RateTableSub[s_chan[ch].ADSRX.ReleaseRate * 4];\r
70 if (s_chan[ch].ADSRX.ReleaseModeExp)\r
71 {\r
72 for (; ns < ns_to; ns++)\r
73 {\r
74 EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);\r
75 if (EnvelopeVol < 0)\r
76 break;\r
77\r
78 ChanBuf[ns] *= EnvelopeVol >> 21;\r
79 ChanBuf[ns] >>= 10;\r
80 }\r
81 }\r
ef79bbde 82 else\r
1ab7621a 83 {\r
84 for (; ns < ns_to; ns++)\r
85 {\r
86 EnvelopeVol += val;\r
87 if (EnvelopeVol < 0)\r
88 break;\r
89\r
90 ChanBuf[ns] *= EnvelopeVol >> 21;\r
91 ChanBuf[ns] >>= 10;\r
92 }\r
93 }\r
94\r
95 if (EnvelopeVol < 0)\r
96 goto stop;\r
ef79bbde 97\r
9cf0ddbc 98 goto done;\r
1ab7621a 99 }\r
ef79bbde 100\r
1ab7621a 101 switch (s_chan[ch].ADSRX.State)\r
102 {\r
9cf0ddbc 103 case 0: // -> attack\r
9cf0ddbc 104 rto = 0;\r
1ab7621a 105 if (s_chan[ch].ADSRX.AttackModeExp && EnvelopeVol >= 0x60000000)\r
106 rto = 8;\r
107 val = RateTableAdd[s_chan[ch].ADSRX.AttackRate + rto];\r
9cf0ddbc 108\r
1ab7621a 109 for (; ns < ns_to; ns++)\r
9cf0ddbc 110 {\r
1ab7621a 111 EnvelopeVol += val;\r
112 if (EnvelopeVol < 0)\r
113 break;\r
114\r
115 ChanBuf[ns] *= EnvelopeVol >> 21;\r
116 ChanBuf[ns] >>= 10;\r
9cf0ddbc 117 }\r
1ab7621a 118\r
119 if (EnvelopeVol < 0) // overflow\r
120 {\r
121 EnvelopeVol = 0x7fffffff;\r
122 s_chan[ch].ADSRX.State = 1;\r
123 ns++; // sample is good already\r
124 goto decay;\r
125 }\r
126 break;\r
ef79bbde 127\r
ef79bbde 128 //--------------------------------------------------//\r
1ab7621a 129 decay:\r
9cf0ddbc 130 case 1: // -> decay\r
1ab7621a 131 val = RateTableSub[s_chan[ch].ADSRX.DecayRate * 4];\r
132 level = s_chan[ch].ADSRX.SustainLevel;\r
ef79bbde 133\r
1ab7621a 134 for (; ns < ns_to; )\r
9cf0ddbc 135 {\r
1ab7621a 136 EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);\r
137 if (EnvelopeVol < 0)\r
138 EnvelopeVol = 0;\r
139\r
140 ChanBuf[ns] *= EnvelopeVol >> 21;\r
141 ChanBuf[ns] >>= 10;\r
142 ns++;\r
143\r
144 if (((EnvelopeVol >> 27) & 0xf) <= level)\r
145 {\r
146 s_chan[ch].ADSRX.State = 2;\r
147 goto sustain;\r
148 }\r
9cf0ddbc 149 }\r
1ab7621a 150 break;\r
ef79bbde 151\r
ef79bbde 152 //--------------------------------------------------//\r
1ab7621a 153 sustain:\r
9cf0ddbc 154 case 2: // -> sustain\r
1ab7621a 155 if (s_chan[ch].ADSRX.SustainIncrease)\r
9cf0ddbc 156 {\r
1ab7621a 157 if (EnvelopeVol >= 0x7fff0000)\r
158 break;\r
159\r
160 rto = 0;\r
161 if (s_chan[ch].ADSRX.SustainModeExp && EnvelopeVol >= 0x60000000)\r
162 rto = 8;\r
163 val = RateTableAdd[s_chan[ch].ADSRX.SustainRate + rto];\r
9cf0ddbc 164\r
1ab7621a 165 for (; ns < ns_to; ns++)\r
9cf0ddbc 166 {\r
1ab7621a 167 EnvelopeVol += val;\r
168 if ((unsigned int)EnvelopeVol >= 0x7fe00000)\r
169 {\r
170 EnvelopeVol = 0x7fffffff;\r
171 break;\r
172 }\r
173\r
174 ChanBuf[ns] *= EnvelopeVol >> 21;\r
175 ChanBuf[ns] >>= 10;\r
9cf0ddbc 176 }\r
177 }\r
1ab7621a 178 else\r
9cf0ddbc 179 {\r
1ab7621a 180 val = RateTableSub[s_chan[ch].ADSRX.SustainRate];\r
181 if (s_chan[ch].ADSRX.SustainModeExp)\r
9cf0ddbc 182 {\r
1ab7621a 183 for (; ns < ns_to; ns++)\r
184 {\r
185 EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);\r
186 if (EnvelopeVol < 0) \r
187 goto stop;\r
188\r
189 ChanBuf[ns] *= EnvelopeVol >> 21;\r
190 ChanBuf[ns] >>= 10;\r
191 }\r
9cf0ddbc 192 }\r
1ab7621a 193 else\r
9cf0ddbc 194 {\r
1ab7621a 195 for (; ns < ns_to; ns++)\r
196 {\r
197 EnvelopeVol += val;\r
198 if (EnvelopeVol < 0) \r
199 goto stop;\r
200\r
201 ChanBuf[ns] *= EnvelopeVol >> 21;\r
202 ChanBuf[ns] >>= 10;\r
203 }\r
9cf0ddbc 204 }\r
205 }\r
1ab7621a 206 break;\r
207 }\r
9cf0ddbc 208\r
209done:\r
1ab7621a 210 s_chan[ch].ADSRX.EnvelopeVol = EnvelopeVol;\r
211 return;\r
212\r
213stop:\r
214 memset(&ChanBuf[ns], 0, (ns_to - ns) * sizeof(ChanBuf[0]));\r
215 s_chan[ch].ADSRX.EnvelopeVol = 0;\r
216 dwChannelOn &= ~(1<<ch);\r
ef79bbde
P
217}\r
218\r
219#endif\r
220\r
221/*\r
222James Higgs ADSR investigations:\r
223\r
224PSX SPU Envelope Timings\r
225~~~~~~~~~~~~~~~~~~~~~~~~\r
226\r
227First, here is an extract from doomed's SPU doc, which explains the basics\r
228of the SPU "volume envelope": \r
229\r
230*** doomed doc extract start ***\r
231\r
232--------------------------------------------------------------------------\r
233Voices.\r
234--------------------------------------------------------------------------\r
235The SPU has 24 hardware voices. These voices can be used to reproduce sample\r
236data, noise or can be used as frequency modulator on the next voice.\r
237Each voice has it's own programmable ADSR envelope filter. The main volume\r
238can be programmed independently for left and right output.\r
239\r
240The ADSR envelope filter works as follows:\r
241Ar = Attack rate, which specifies the speed at which the volume increases\r
242 from zero to it's maximum value, as soon as the note on is given. The\r
243 slope can be set to lineair or exponential.\r
244Dr = Decay rate specifies the speed at which the volume decreases to the\r
245 sustain level. Decay is always decreasing exponentially.\r
246Sl = Sustain level, base level from which sustain starts.\r
247Sr = Sustain rate is the rate at which the volume of the sustained note\r
248 increases or decreases. This can be either lineair or exponential.\r
249Rr = Release rate is the rate at which the volume of the note decreases\r
250 as soon as the note off is given.\r
251\r
252 lvl |\r
253 ^ | /\Dr __\r
254 Sl _| _ / _ \__--- \\r
255 | / ---__ \ Rr\r
256 | /Ar Sr \ \\r
257 | / \\\r
258 |/___________________\________\r
259 ->time\r
260\r
261The overal volume can also be set to sweep up or down lineairly or\r
262exponentially from it's current value. This can be done seperately\r
263for left and right.\r
264\r
265Relevant SPU registers:\r
266-------------------------------------------------------------\r
267$1f801xx8 Attack/Decay/Sustain level\r
268bit |0f|0e 0d 0c 0b 0a 09 08|07 06 05 04|03 02 01 00|\r
269desc.|Am| Ar |Dr |Sl |\r
270\r
271Am 0 Attack mode Linear\r
272 1 Exponential\r
273\r
274Ar 0-7f attack rate\r
275Dr 0-f decay rate\r
276Sl 0-f sustain level\r
277-------------------------------------------------------------\r
278$1f801xxa Sustain rate, Release Rate.\r
279bit |0f|0e|0d|0c 0b 0a 09 08 07 06|05|04 03 02 01 00|\r
280desc.|Sm|Sd| 0| Sr |Rm|Rr |\r
281\r
282Sm 0 sustain rate mode linear\r
283 1 exponential\r
284Sd 0 sustain rate mode increase\r
285 1 decrease\r
286Sr 0-7f Sustain Rate\r
287Rm 0 Linear decrease\r
288 1 Exponential decrease\r
289Rr 0-1f Release Rate\r
290\r
291Note: decay mode is always Expontial decrease, and thus cannot\r
292be set.\r
293-------------------------------------------------------------\r
294$1f801xxc Current ADSR volume\r
295bit |0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00|\r
296desc.|ADSRvol |\r
297\r
298ADSRvol Returns the current envelope volume when\r
299 read.\r
300-- James' Note: return range: 0 -> 32767\r
301\r
302*** doomed doc extract end *** \r
303\r
304By using a small PSX proggie to visualise the envelope as it was played,\r
305the following results for envelope timing were obtained:\r
306\r
3071. Attack rate value (linear mode)\r
308\r
309 Attack value range: 0 -> 127\r
310\r
311 Value | 48 | 52 | 56 | 60 | 64 | 68 | 72 | | 80 |\r
312 -----------------------------------------------------------------\r
313 Frames | 11 | 21 | 42 | 84 | 169| 338| 676| |2890|\r
314\r
315 Note: frames is no. of PAL frames to reach full volume (100%\r
316 amplitude)\r
317\r
318 Hmm, noticing that the time taken to reach full volume doubles\r
319 every time we add 4 to our attack value, we know the equation is\r
320 of form:\r
321 frames = k * 2 ^ (value / 4)\r
322\r
323 (You may ponder about envelope generator hardware at this point,\r
324 or maybe not... :)\r
325\r
326 By substituting some stuff and running some checks, we get:\r
327\r
328 k = 0.00257 (close enuf)\r
329\r
330 therefore,\r
331 frames = 0.00257 * 2 ^ (value / 4)\r
332 If you just happen to be writing an emulator, then you can probably\r
333 use an equation like:\r
334\r
335 %volume_increase_per_tick = 1 / frames\r
336\r
337\r
338 ------------------------------------\r
339 Pete:\r
340 ms=((1<<(value>>2))*514)/10000\r
341 ------------------------------------\r
342\r
3432. Decay rate value (only has log mode)\r
344\r
345 Decay value range: 0 -> 15\r
346\r
347 Value | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |\r
348 ------------------------------------------------\r
349 frames | | | | | 6 | 12 | 24 | 47 |\r
350\r
351 Note: frames here is no. of PAL frames to decay to 50% volume.\r
352\r
353 formula: frames = k * 2 ^ (value)\r
354\r
355 Substituting, we get: k = 0.00146\r
356\r
357 Further info on logarithmic nature:\r
358 frames to decay to sustain level 3 = 3 * frames to decay to \r
359 sustain level 9\r
360\r
361 Also no. of frames to 25% volume = roughly 1.85 * no. of frames to\r
362 50% volume.\r
363\r
364 Frag it - just use linear approx.\r
365\r
366 ------------------------------------\r
367 Pete:\r
368 ms=((1<<value)*292)/10000\r
369 ------------------------------------\r
370\r
371\r
3723. Sustain rate value (linear mode)\r
373\r
374 Sustain rate range: 0 -> 127\r
375\r
376 Value | 48 | 52 | 56 | 60 | 64 | 68 | 72 |\r
377 -------------------------------------------\r
378 frames | 9 | 19 | 37 | 74 | 147| 293| 587|\r
379\r
380 Here, frames = no. of PAL frames for volume amplitude to go from 100%\r
381 to 0% (or vice-versa).\r
382\r
383 Same formula as for attack value, just a different value for k:\r
384\r
385 k = 0.00225\r
386\r
387 ie: frames = 0.00225 * 2 ^ (value / 4)\r
388\r
389 For emulation purposes:\r
390\r
391 %volume_increase_or_decrease_per_tick = 1 / frames\r
392\r
393 ------------------------------------\r
394 Pete:\r
395 ms=((1<<(value>>2))*450)/10000\r
396 ------------------------------------\r
397\r
398\r
3994. Release rate (linear mode)\r
400\r
401 Release rate range: 0 -> 31\r
402\r
403 Value | 13 | 14 | 15 | 16 | 17 |\r
404 ---------------------------------------------------------------\r
405 frames | 18 | 36 | 73 | 146| 292|\r
406\r
407 Here, frames = no. of PAL frames to decay from 100% vol to 0% vol\r
408 after "note-off" is triggered.\r
409\r
410 Formula: frames = k * 2 ^ (value)\r
411\r
412 And so: k = 0.00223\r
413\r
414 ------------------------------------\r
415 Pete:\r
416 ms=((1<<value)*446)/10000\r
417 ------------------------------------\r
418\r
419\r
420Other notes: \r
421\r
422Log stuff not figured out. You may get some clues from the "Decay rate"\r
423stuff above. For emu purposes it may not be important - use linear\r
424approx.\r
425\r
426To get timings in millisecs, multiply frames by 20.\r
427\r
428\r
429\r
430- James Higgs 17/6/2000\r
431james7780@yahoo.com\r
432\r
433//---------------------------------------------------------------\r
434\r
435OLD adsr mixing according to james' rules... has to be called\r
436every one millisecond\r
437\r
438\r
439 long v,v2,lT,l1,l2,l3;\r
440\r
441 if(s_chan[ch].bStop) // psx wants to stop? -> release phase\r
442 {\r
443 if(s_chan[ch].ADSR.ReleaseVal!=0) // -> release not 0: do release (if 0: stop right now)\r
444 {\r
445 if(!s_chan[ch].ADSR.ReleaseVol) // --> release just started? set up the release stuff\r
446 {\r
447 s_chan[ch].ADSR.ReleaseStartTime=s_chan[ch].ADSR.lTime;\r
448 s_chan[ch].ADSR.ReleaseVol=s_chan[ch].ADSR.lVolume;\r
449 s_chan[ch].ADSR.ReleaseTime = // --> calc how long does it take to reach the wanted sus level\r
450 (s_chan[ch].ADSR.ReleaseTime*\r
451 s_chan[ch].ADSR.ReleaseVol)/1024;\r
452 }\r
453 // -> NO release exp mode used (yet)\r
454 v=s_chan[ch].ADSR.ReleaseVol; // -> get last volume\r
455 lT=s_chan[ch].ADSR.lTime- // -> how much time is past?\r
456 s_chan[ch].ADSR.ReleaseStartTime;\r
457 l1=s_chan[ch].ADSR.ReleaseTime;\r
458 \r
459 if(lT<l1) // -> we still have to release\r
460 {\r
461 v=v-((v*lT)/l1); // --> calc new volume\r
462 }\r
463 else // -> release is over: now really stop that sample\r
464 {v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;}\r
465 }\r
466 else // -> release IS 0: release at once\r
467 {\r
468 v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;\r
469 }\r
470 }\r
471 else \r
472 {//--------------------------------------------------// not in release phase:\r
473 v=1024;\r
474 lT=s_chan[ch].ADSR.lTime;\r
475 l1=s_chan[ch].ADSR.AttackTime;\r
476 \r
477 if(lT<l1) // attack\r
478 { // no exp mode used (yet)\r
479// if(s_chan[ch].ADSR.AttackModeExp)\r
480// {\r
481// v=(v*lT)/l1;\r
482// }\r
483// else\r
484 {\r
485 v=(v*lT)/l1;\r
486 }\r
487 if(v==0) v=1;\r
488 }\r
489 else // decay\r
490 { // should be exp, but who cares? ;)\r
491 l2=s_chan[ch].ADSR.DecayTime;\r
492 v2=s_chan[ch].ADSR.SustainLevel;\r
493\r
494 lT-=l1;\r
495 if(lT<l2)\r
496 {\r
497 v-=(((v-v2)*lT)/l2);\r
498 }\r
499 else // sustain\r
500 { // no exp mode used (yet)\r
501 l3=s_chan[ch].ADSR.SustainTime;\r
502 lT-=l2;\r
503 if(s_chan[ch].ADSR.SustainModeDec>0)\r
504 {\r
505 if(l3!=0) v2+=((v-v2)*lT)/l3;\r
506 else v2=v;\r
507 }\r
508 else\r
509 {\r
510 if(l3!=0) v2-=(v2*lT)/l3;\r
511 else v2=v;\r
512 }\r
513\r
514 if(v2>v) v2=v;\r
515 if(v2<=0) {v2=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;}\r
516\r
517 v=v2;\r
518 }\r
519 }\r
520 }\r
521\r
522 //----------------------------------------------------// \r
523 // ok, done for this channel, so increase time\r
524\r
525 s_chan[ch].ADSR.lTime+=1; // 1 = 1.020408f ms; \r
526\r
527 if(v>1024) v=1024; // adjust volume\r
528 if(v<0) v=0; \r
529 s_chan[ch].ADSR.lVolume=v; // store act volume\r
530\r
531 return v; // return the volume factor\r
532*/\r
533\r
534\r
535//-----------------------------------------------------------------------------\r
536//-----------------------------------------------------------------------------\r
537//-----------------------------------------------------------------------------\r
538\r
539\r
540/*\r
541-----------------------------------------------------------------------------\r
542Neill Corlett\r
543Playstation SPU envelope timing notes\r
544-----------------------------------------------------------------------------\r
545\r
546This is preliminary. This may be wrong. But the model described herein fits\r
547all of my experimental data, and it's just simple enough to sound right.\r
548\r
549ADSR envelope level ranges from 0x00000000 to 0x7FFFFFFF internally.\r
550The value returned by channel reg 0xC is (envelope_level>>16).\r
551\r
552Each sample, an increment or decrement value will be added to or\r
553subtracted from this envelope level.\r
554\r
555Create the rate log table. The values double every 4 entries.\r
556 entry #0 = 4\r
557\r
558 4, 5, 6, 7,\r
559 8,10,12,14,\r
560 16,20,24,28, ...\r
561\r
562 entry #40 = 4096...\r
563 entry #44 = 8192...\r
564 entry #48 = 16384...\r
565 entry #52 = 32768...\r
566 entry #56 = 65536...\r
567\r
568increments and decrements are in terms of ratelogtable[n]\r
569n may exceed the table bounds (plan on n being between -32 and 127).\r
570table values are all clipped between 0x00000000 and 0x3FFFFFFF\r
571\r
572when you "voice on", the envelope is always fully reset.\r
573(yes, it may click. the real thing does this too.)\r
574\r
575envelope level begins at zero.\r
576\r
577each state happens for at least 1 cycle\r
578(transitions are not instantaneous)\r
579this may result in some oddness: if the decay rate is uberfast, it will cut\r
580the envelope from full down to half in one sample, potentially skipping over\r
581the sustain level\r
582\r
583ATTACK\r
584------\r
585- if the envelope level has overflowed past the max, clip to 0x7FFFFFFF and\r
586 proceed to DECAY.\r
587\r
588Linear attack mode:\r
589- line extends upward to 0x7FFFFFFF\r
590- increment per sample is ratelogtable[(Ar^0x7F)-0x10]\r
591\r
592Logarithmic attack mode:\r
593if envelope_level < 0x60000000:\r
594 - line extends upward to 0x60000000\r
595 - increment per sample is ratelogtable[(Ar^0x7F)-0x10]\r
596else:\r
597 - line extends upward to 0x7FFFFFFF\r
598 - increment per sample is ratelogtable[(Ar^0x7F)-0x18]\r
599\r
600DECAY\r
601-----\r
602- if ((envelope_level>>27)&0xF) <= Sl, proceed to SUSTAIN.\r
603 Do not clip to the sustain level.\r
604- current line ends at (envelope_level & 0x07FFFFFF)\r
605- decrement per sample depends on (envelope_level>>28)&0x7\r
606 0: ratelogtable[(4*(Dr^0x1F))-0x18+0]\r
607 1: ratelogtable[(4*(Dr^0x1F))-0x18+4]\r
608 2: ratelogtable[(4*(Dr^0x1F))-0x18+6]\r
609 3: ratelogtable[(4*(Dr^0x1F))-0x18+8]\r
610 4: ratelogtable[(4*(Dr^0x1F))-0x18+9]\r
611 5: ratelogtable[(4*(Dr^0x1F))-0x18+10]\r
612 6: ratelogtable[(4*(Dr^0x1F))-0x18+11]\r
613 7: ratelogtable[(4*(Dr^0x1F))-0x18+12]\r
614 (note that this is the same as the release rate formula, except that\r
615 decay rates 10-1F aren't possible... those would be slower in theory)\r
616\r
617SUSTAIN\r
618-------\r
619- no terminating condition except for voice off\r
620- Sd=0 (increase) behavior is identical to ATTACK for both log and linear.\r
621- Sd=1 (decrease) behavior:\r
622Linear sustain decrease:\r
623- line extends to 0x00000000\r
624- decrement per sample is ratelogtable[(Sr^0x7F)-0x0F]\r
625Logarithmic sustain decrease:\r
626- current line ends at (envelope_level & 0x07FFFFFF)\r
627- decrement per sample depends on (envelope_level>>28)&0x7\r
628 0: ratelogtable[(Sr^0x7F)-0x1B+0]\r
629 1: ratelogtable[(Sr^0x7F)-0x1B+4]\r
630 2: ratelogtable[(Sr^0x7F)-0x1B+6]\r
631 3: ratelogtable[(Sr^0x7F)-0x1B+8]\r
632 4: ratelogtable[(Sr^0x7F)-0x1B+9]\r
633 5: ratelogtable[(Sr^0x7F)-0x1B+10]\r
634 6: ratelogtable[(Sr^0x7F)-0x1B+11]\r
635 7: ratelogtable[(Sr^0x7F)-0x1B+12]\r
636\r
637RELEASE\r
638-------\r
639- if the envelope level has overflowed to negative, clip to 0 and QUIT.\r
640\r
641Linear release mode:\r
642- line extends to 0x00000000\r
643- decrement per sample is ratelogtable[(4*(Rr^0x1F))-0x0C]\r
644\r
645Logarithmic release mode:\r
646- line extends to (envelope_level & 0x0FFFFFFF)\r
647- decrement per sample depends on (envelope_level>>28)&0x7\r
648 0: ratelogtable[(4*(Rr^0x1F))-0x18+0]\r
649 1: ratelogtable[(4*(Rr^0x1F))-0x18+4]\r
650 2: ratelogtable[(4*(Rr^0x1F))-0x18+6]\r
651 3: ratelogtable[(4*(Rr^0x1F))-0x18+8]\r
652 4: ratelogtable[(4*(Rr^0x1F))-0x18+9]\r
653 5: ratelogtable[(4*(Rr^0x1F))-0x18+10]\r
654 6: ratelogtable[(4*(Rr^0x1F))-0x18+11]\r
655 7: ratelogtable[(4*(Rr^0x1F))-0x18+12]\r
656\r
657-----------------------------------------------------------------------------\r
658*/\r
659\r
9cf0ddbc 660// vim:shiftwidth=1:expandtab\r