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