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