some random improvements
[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  spu.s_chan[ch].ADSRX.State = ADSR_ATTACK;             // and init some adsr vars\r
61  spu.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 static int SkipADSR(ADSRInfoEx *adsr, int ns_to)\r
221 {\r
222  int EnvelopeVol = adsr->EnvelopeVol;\r
223  int ns = 0, val, rto, level;\r
224  int64_t v64;\r
225 \r
226  if (adsr->State == ADSR_RELEASE)\r
227  {\r
228    val = RateTableSub[adsr->ReleaseRate * 4];\r
229    if (adsr->ReleaseModeExp)\r
230    {\r
231      for (; ns < ns_to; ns++)\r
232      {\r
233        EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);\r
234        if (EnvelopeVol <= 0)\r
235          break;\r
236      }\r
237    }\r
238    else\r
239    {\r
240      v64 = EnvelopeVol;\r
241      v64 += (int64_t)val * ns_to;\r
242      EnvelopeVol = (int)v64;\r
243      if (v64 > 0)\r
244        ns = ns_to;\r
245    }\r
246    goto done;\r
247  }\r
248 \r
249  switch (adsr->State)\r
250  {\r
251    case ADSR_ATTACK:                                   // -> attack\r
252      rto = 0;\r
253      if (adsr->AttackModeExp && EnvelopeVol >= 0x60000000)\r
254        rto = 8;\r
255      val = RateTableAdd[adsr->AttackRate + rto];\r
256 \r
257      for (; ns < ns_to; ns++)\r
258      {\r
259        EnvelopeVol += val;\r
260        if (EnvelopeVol < 0)\r
261         break;\r
262      }\r
263      if (EnvelopeVol < 0) // overflow\r
264      {\r
265        EnvelopeVol = 0x7fffffff;\r
266        adsr->State = ADSR_DECAY;\r
267        ns++;\r
268        goto decay;\r
269      }\r
270      break;\r
271 \r
272    //--------------------------------------------------//\r
273    decay:\r
274    case ADSR_DECAY:                                    // -> decay\r
275      val = RateTableSub[adsr->DecayRate * 4];\r
276      level = adsr->SustainLevel;\r
277 \r
278      for (; ns < ns_to; )\r
279      {\r
280        EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);\r
281        if (EnvelopeVol < 0)\r
282          EnvelopeVol = 0;\r
283 \r
284        ns++;\r
285 \r
286        if (((EnvelopeVol >> 27) & 0xf) <= level)\r
287        {\r
288          adsr->State = ADSR_SUSTAIN;\r
289          goto sustain;\r
290        }\r
291      }\r
292      break;\r
293 \r
294    //--------------------------------------------------//\r
295    sustain:\r
296    case ADSR_SUSTAIN:                                  // -> sustain\r
297      if (adsr->SustainIncrease)\r
298      {\r
299        ns = ns_to;\r
300 \r
301        if (EnvelopeVol >= 0x7fff0000)\r
302          break;\r
303 \r
304        rto = 0;\r
305        if (adsr->SustainModeExp && EnvelopeVol >= 0x60000000)\r
306          rto = 8;\r
307        val = RateTableAdd[adsr->SustainRate + rto];\r
308 \r
309        v64 = EnvelopeVol;\r
310        v64 += (int64_t)val * (ns_to - ns);\r
311        EnvelopeVol = (int)v64;\r
312        if (v64 >= 0x7fe00000ll)\r
313          EnvelopeVol = 0x7fffffff;\r
314      }\r
315      else\r
316      {\r
317        val = RateTableSub[adsr->SustainRate];\r
318        if (adsr->SustainModeExp)\r
319        {\r
320          for (; ns < ns_to; ns++)\r
321          {\r
322            EnvelopeVol += ((long long)val * EnvelopeVol) >> (15+16);\r
323            if (EnvelopeVol < 0)\r
324              break;\r
325          }\r
326        }\r
327        else\r
328        {\r
329          v64 = EnvelopeVol;\r
330          v64 += (int64_t)val * (ns_to - ns);\r
331          EnvelopeVol = (int)v64;\r
332          if (v64 > 0)\r
333          {\r
334            ns = ns_to;\r
335            break;\r
336          }\r
337        }\r
338      }\r
339      break;\r
340  }\r
341 \r
342 done:\r
343  adsr->EnvelopeVol = EnvelopeVol;\r
344  return ns;\r
345 }\r
346 \r
347 #endif\r
348 \r
349 /*\r
350 James Higgs ADSR investigations:\r
351 \r
352 PSX SPU Envelope Timings\r
353 ~~~~~~~~~~~~~~~~~~~~~~~~\r
354 \r
355 First, here is an extract from doomed's SPU doc, which explains the basics\r
356 of the SPU "volume envelope": \r
357 \r
358 *** doomed doc extract start ***\r
359 \r
360 --------------------------------------------------------------------------\r
361 Voices.\r
362 --------------------------------------------------------------------------\r
363 The SPU has 24 hardware voices. These voices can be used to reproduce sample\r
364 data, noise or can be used as frequency modulator on the next voice.\r
365 Each voice has it's own programmable ADSR envelope filter. The main volume\r
366 can be programmed independently for left and right output.\r
367 \r
368 The ADSR envelope filter works as follows:\r
369 Ar = Attack rate, which specifies the speed at which the volume increases\r
370      from zero to it's maximum value, as soon as the note on is given. The\r
371      slope can be set to lineair or exponential.\r
372 Dr = Decay rate specifies the speed at which the volume decreases to the\r
373      sustain level. Decay is always decreasing exponentially.\r
374 Sl = Sustain level, base level from which sustain starts.\r
375 Sr = Sustain rate is the rate at which the volume of the sustained note\r
376      increases or decreases. This can be either lineair or exponential.\r
377 Rr = Release rate is the rate at which the volume of the note decreases\r
378      as soon as the note off is given.\r
379 \r
380      lvl |\r
381        ^ |     /\Dr     __\r
382      Sl _| _  / _ \__---  \\r
383          |   /       ---__ \ Rr\r
384          |  /Ar       Sr  \ \\r
385          | /                \\\r
386          |/___________________\________\r
387                                   ->time\r
388 \r
389 The overal volume can also be set to sweep up or down lineairly or\r
390 exponentially from it's current value. This can be done seperately\r
391 for left and right.\r
392 \r
393 Relevant SPU registers:\r
394 -------------------------------------------------------------\r
395 $1f801xx8         Attack/Decay/Sustain level\r
396 bit  |0f|0e 0d 0c 0b 0a 09 08|07 06 05 04|03 02 01 00|\r
397 desc.|Am|         Ar         |Dr         |Sl         |\r
398 \r
399 Am       0        Attack mode Linear\r
400          1                    Exponential\r
401 \r
402 Ar       0-7f     attack rate\r
403 Dr       0-f      decay rate\r
404 Sl       0-f      sustain level\r
405 -------------------------------------------------------------\r
406 $1f801xxa         Sustain rate, Release Rate.\r
407 bit  |0f|0e|0d|0c 0b 0a 09 08 07 06|05|04 03 02 01 00|\r
408 desc.|Sm|Sd| 0|   Sr               |Rm|Rr            |\r
409 \r
410 Sm       0        sustain rate mode linear\r
411          1                          exponential\r
412 Sd       0        sustain rate mode increase\r
413          1                          decrease\r
414 Sr       0-7f     Sustain Rate\r
415 Rm       0        Linear decrease\r
416          1        Exponential decrease\r
417 Rr       0-1f     Release Rate\r
418 \r
419 Note: decay mode is always Expontial decrease, and thus cannot\r
420 be set.\r
421 -------------------------------------------------------------\r
422 $1f801xxc         Current ADSR volume\r
423 bit  |0f 0e 0d 0c 0b 0a 09 08 07 06 05 04 03 02 01 00|\r
424 desc.|ADSRvol                                        |\r
425 \r
426 ADSRvol           Returns the current envelope volume when\r
427                   read.\r
428 -- James' Note: return range: 0 -> 32767\r
429 \r
430 *** doomed doc extract end *** \r
431 \r
432 By using a small PSX proggie to visualise the envelope as it was played,\r
433 the following results for envelope timing were obtained:\r
434 \r
435 1. Attack rate value (linear mode)\r
436 \r
437    Attack value range: 0 -> 127\r
438 \r
439    Value  | 48 | 52 | 56 | 60 | 64 | 68 | 72 |    | 80 |\r
440    -----------------------------------------------------------------\r
441    Frames | 11 | 21 | 42 | 84 | 169| 338| 676|    |2890|\r
442 \r
443    Note: frames is no. of PAL frames to reach full volume (100%\r
444    amplitude)\r
445 \r
446    Hmm, noticing that the time taken to reach full volume doubles\r
447    every time we add 4 to our attack value, we know the equation is\r
448    of form:\r
449              frames = k * 2 ^ (value / 4)\r
450 \r
451    (You may ponder about envelope generator hardware at this point,\r
452    or maybe not... :)\r
453 \r
454    By substituting some stuff and running some checks, we get:\r
455 \r
456        k = 0.00257              (close enuf)\r
457 \r
458    therefore,\r
459              frames = 0.00257 * 2 ^ (value / 4)\r
460    If you just happen to be writing an emulator, then you can probably\r
461    use an equation like:\r
462 \r
463        %volume_increase_per_tick = 1 / frames\r
464 \r
465 \r
466    ------------------------------------\r
467    Pete:\r
468    ms=((1<<(value>>2))*514)/10000\r
469    ------------------------------------\r
470 \r
471 2. Decay rate value (only has log mode)\r
472 \r
473    Decay value range: 0 -> 15\r
474 \r
475    Value  |  8 |  9 | 10 | 11 | 12 | 13 | 14 | 15 |\r
476    ------------------------------------------------\r
477    frames |    |    |    |    |  6 | 12 | 24 | 47 |\r
478 \r
479    Note: frames here is no. of PAL frames to decay to 50% volume.\r
480 \r
481    formula: frames = k * 2 ^ (value)\r
482 \r
483    Substituting, we get: k = 0.00146\r
484 \r
485    Further info on logarithmic nature:\r
486    frames to decay to sustain level 3  =  3 * frames to decay to \r
487    sustain level 9\r
488 \r
489    Also no. of frames to 25% volume = roughly 1.85 * no. of frames to\r
490    50% volume.\r
491 \r
492    Frag it - just use linear approx.\r
493 \r
494    ------------------------------------\r
495    Pete:\r
496    ms=((1<<value)*292)/10000\r
497    ------------------------------------\r
498 \r
499 \r
500 3. Sustain rate value (linear mode)\r
501 \r
502    Sustain rate range: 0 -> 127\r
503 \r
504    Value  | 48 | 52 | 56 | 60 | 64 | 68 | 72 |\r
505    -------------------------------------------\r
506    frames |  9 | 19 | 37 | 74 | 147| 293| 587|\r
507 \r
508    Here, frames = no. of PAL frames for volume amplitude to go from 100%\r
509    to 0% (or vice-versa).\r
510 \r
511    Same formula as for attack value, just a different value for k:\r
512 \r
513    k = 0.00225\r
514 \r
515    ie: frames = 0.00225 * 2 ^ (value / 4)\r
516 \r
517    For emulation purposes:\r
518 \r
519    %volume_increase_or_decrease_per_tick = 1 / frames\r
520 \r
521    ------------------------------------\r
522    Pete:\r
523    ms=((1<<(value>>2))*450)/10000\r
524    ------------------------------------\r
525 \r
526 \r
527 4. Release rate (linear mode)\r
528 \r
529    Release rate range: 0 -> 31\r
530 \r
531    Value  | 13 | 14 | 15 | 16 | 17 |\r
532    ---------------------------------------------------------------\r
533    frames | 18 | 36 | 73 | 146| 292|\r
534 \r
535    Here, frames = no. of PAL frames to decay from 100% vol to 0% vol\r
536    after "note-off" is triggered.\r
537 \r
538    Formula: frames = k * 2 ^ (value)\r
539 \r
540    And so: k = 0.00223\r
541 \r
542    ------------------------------------\r
543    Pete:\r
544    ms=((1<<value)*446)/10000\r
545    ------------------------------------\r
546 \r
547 \r
548 Other notes:   \r
549 \r
550 Log stuff not figured out. You may get some clues from the "Decay rate"\r
551 stuff above. For emu purposes it may not be important - use linear\r
552 approx.\r
553 \r
554 To get timings in millisecs, multiply frames by 20.\r
555 \r
556 \r
557 \r
558 - James Higgs 17/6/2000\r
559 james7780@yahoo.com\r
560 \r
561 //---------------------------------------------------------------\r
562 \r
563 OLD adsr mixing according to james' rules... has to be called\r
564 every one millisecond\r
565 \r
566 \r
567  long v,v2,lT,l1,l2,l3;\r
568 \r
569  if(s_chan[ch].bStop)                                  // psx wants to stop? -> release phase\r
570   {\r
571    if(s_chan[ch].ADSR.ReleaseVal!=0)                   // -> release not 0: do release (if 0: stop right now)\r
572     {\r
573      if(!s_chan[ch].ADSR.ReleaseVol)                   // --> release just started? set up the release stuff\r
574       {\r
575        s_chan[ch].ADSR.ReleaseStartTime=s_chan[ch].ADSR.lTime;\r
576        s_chan[ch].ADSR.ReleaseVol=s_chan[ch].ADSR.lVolume;\r
577        s_chan[ch].ADSR.ReleaseTime =                   // --> calc how long does it take to reach the wanted sus level\r
578          (s_chan[ch].ADSR.ReleaseTime*\r
579           s_chan[ch].ADSR.ReleaseVol)/1024;\r
580       }\r
581                                                        // -> NO release exp mode used (yet)\r
582      v=s_chan[ch].ADSR.ReleaseVol;                     // -> get last volume\r
583      lT=s_chan[ch].ADSR.lTime-                         // -> how much time is past?\r
584         s_chan[ch].ADSR.ReleaseStartTime;\r
585      l1=s_chan[ch].ADSR.ReleaseTime;\r
586                                                        \r
587      if(lT<l1)                                         // -> we still have to release\r
588       {\r
589        v=v-((v*lT)/l1);                                // --> calc new volume\r
590       }\r
591      else                                              // -> release is over: now really stop that sample\r
592       {v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;}\r
593     }\r
594    else                                                // -> release IS 0: release at once\r
595     {\r
596      v=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;\r
597     }\r
598   }\r
599  else                                               \r
600   {//--------------------------------------------------// not in release phase:\r
601    v=1024;\r
602    lT=s_chan[ch].ADSR.lTime;\r
603    l1=s_chan[ch].ADSR.AttackTime;\r
604                                                        \r
605    if(lT<l1)                                           // attack\r
606     {                                                  // no exp mode used (yet)\r
607 //     if(s_chan[ch].ADSR.AttackModeExp)\r
608 //      {\r
609 //       v=(v*lT)/l1;\r
610 //      }\r
611 //     else\r
612       {\r
613        v=(v*lT)/l1;\r
614       }\r
615      if(v==0) v=1;\r
616     }\r
617    else                                                // decay\r
618     {                                                  // should be exp, but who cares? ;)\r
619      l2=s_chan[ch].ADSR.DecayTime;\r
620      v2=s_chan[ch].ADSR.SustainLevel;\r
621 \r
622      lT-=l1;\r
623      if(lT<l2)\r
624       {\r
625        v-=(((v-v2)*lT)/l2);\r
626       }\r
627      else                                              // sustain\r
628       {                                                // no exp mode used (yet)\r
629        l3=s_chan[ch].ADSR.SustainTime;\r
630        lT-=l2;\r
631        if(s_chan[ch].ADSR.SustainModeDec>0)\r
632         {\r
633          if(l3!=0) v2+=((v-v2)*lT)/l3;\r
634          else      v2=v;\r
635         }\r
636        else\r
637         {\r
638          if(l3!=0) v2-=(v2*lT)/l3;\r
639          else      v2=v;\r
640         }\r
641 \r
642        if(v2>v)  v2=v;\r
643        if(v2<=0) {v2=0;s_chan[ch].bOn=0;s_chan[ch].ADSR.ReleaseVol=0;s_chan[ch].bNoise=0;}\r
644 \r
645        v=v2;\r
646       }\r
647     }\r
648   }\r
649 \r
650  //----------------------------------------------------// \r
651  // ok, done for this channel, so increase time\r
652 \r
653  s_chan[ch].ADSR.lTime+=1;                             // 1 = 1.020408f ms;      \r
654 \r
655  if(v>1024)     v=1024;                                // adjust volume\r
656  if(v<0)        v=0;                                  \r
657  s_chan[ch].ADSR.lVolume=v;                            // store act volume\r
658 \r
659  return v;                                             // return the volume factor\r
660 */\r
661 \r
662 \r
663 //-----------------------------------------------------------------------------\r
664 //-----------------------------------------------------------------------------\r
665 //-----------------------------------------------------------------------------\r
666 \r
667 \r
668 /*\r
669 -----------------------------------------------------------------------------\r
670 Neill Corlett\r
671 Playstation SPU envelope timing notes\r
672 -----------------------------------------------------------------------------\r
673 \r
674 This is preliminary.  This may be wrong.  But the model described herein fits\r
675 all of my experimental data, and it's just simple enough to sound right.\r
676 \r
677 ADSR envelope level ranges from 0x00000000 to 0x7FFFFFFF internally.\r
678 The value returned by channel reg 0xC is (envelope_level>>16).\r
679 \r
680 Each sample, an increment or decrement value will be added to or\r
681 subtracted from this envelope level.\r
682 \r
683 Create the rate log table.  The values double every 4 entries.\r
684    entry #0 = 4\r
685 \r
686     4, 5, 6, 7,\r
687     8,10,12,14,\r
688    16,20,24,28, ...\r
689 \r
690    entry #40 = 4096...\r
691    entry #44 = 8192...\r
692    entry #48 = 16384...\r
693    entry #52 = 32768...\r
694    entry #56 = 65536...\r
695 \r
696 increments and decrements are in terms of ratelogtable[n]\r
697 n may exceed the table bounds (plan on n being between -32 and 127).\r
698 table values are all clipped between 0x00000000 and 0x3FFFFFFF\r
699 \r
700 when you "voice on", the envelope is always fully reset.\r
701 (yes, it may click. the real thing does this too.)\r
702 \r
703 envelope level begins at zero.\r
704 \r
705 each state happens for at least 1 cycle\r
706 (transitions are not instantaneous)\r
707 this may result in some oddness: if the decay rate is uberfast, it will cut\r
708 the envelope from full down to half in one sample, potentially skipping over\r
709 the sustain level\r
710 \r
711 ATTACK\r
712 ------\r
713 - if the envelope level has overflowed past the max, clip to 0x7FFFFFFF and\r
714   proceed to DECAY.\r
715 \r
716 Linear attack mode:\r
717 - line extends upward to 0x7FFFFFFF\r
718 - increment per sample is ratelogtable[(Ar^0x7F)-0x10]\r
719 \r
720 Logarithmic attack mode:\r
721 if envelope_level < 0x60000000:\r
722   - line extends upward to 0x60000000\r
723   - increment per sample is ratelogtable[(Ar^0x7F)-0x10]\r
724 else:\r
725   - line extends upward to 0x7FFFFFFF\r
726   - increment per sample is ratelogtable[(Ar^0x7F)-0x18]\r
727 \r
728 DECAY\r
729 -----\r
730 - if ((envelope_level>>27)&0xF) <= Sl, proceed to SUSTAIN.\r
731   Do not clip to the sustain level.\r
732 - current line ends at (envelope_level & 0x07FFFFFF)\r
733 - decrement per sample depends on (envelope_level>>28)&0x7\r
734   0: ratelogtable[(4*(Dr^0x1F))-0x18+0]\r
735   1: ratelogtable[(4*(Dr^0x1F))-0x18+4]\r
736   2: ratelogtable[(4*(Dr^0x1F))-0x18+6]\r
737   3: ratelogtable[(4*(Dr^0x1F))-0x18+8]\r
738   4: ratelogtable[(4*(Dr^0x1F))-0x18+9]\r
739   5: ratelogtable[(4*(Dr^0x1F))-0x18+10]\r
740   6: ratelogtable[(4*(Dr^0x1F))-0x18+11]\r
741   7: ratelogtable[(4*(Dr^0x1F))-0x18+12]\r
742   (note that this is the same as the release rate formula, except that\r
743    decay rates 10-1F aren't possible... those would be slower in theory)\r
744 \r
745 SUSTAIN\r
746 -------\r
747 - no terminating condition except for voice off\r
748 - Sd=0 (increase) behavior is identical to ATTACK for both log and linear.\r
749 - Sd=1 (decrease) behavior:\r
750 Linear sustain decrease:\r
751 - line extends to 0x00000000\r
752 - decrement per sample is ratelogtable[(Sr^0x7F)-0x0F]\r
753 Logarithmic sustain decrease:\r
754 - current line ends at (envelope_level & 0x07FFFFFF)\r
755 - decrement per sample depends on (envelope_level>>28)&0x7\r
756   0: ratelogtable[(Sr^0x7F)-0x1B+0]\r
757   1: ratelogtable[(Sr^0x7F)-0x1B+4]\r
758   2: ratelogtable[(Sr^0x7F)-0x1B+6]\r
759   3: ratelogtable[(Sr^0x7F)-0x1B+8]\r
760   4: ratelogtable[(Sr^0x7F)-0x1B+9]\r
761   5: ratelogtable[(Sr^0x7F)-0x1B+10]\r
762   6: ratelogtable[(Sr^0x7F)-0x1B+11]\r
763   7: ratelogtable[(Sr^0x7F)-0x1B+12]\r
764 \r
765 RELEASE\r
766 -------\r
767 - if the envelope level has overflowed to negative, clip to 0 and QUIT.\r
768 \r
769 Linear release mode:\r
770 - line extends to 0x00000000\r
771 - decrement per sample is ratelogtable[(4*(Rr^0x1F))-0x0C]\r
772 \r
773 Logarithmic release mode:\r
774 - line extends to (envelope_level & 0x0FFFFFFF)\r
775 - decrement per sample depends on (envelope_level>>28)&0x7\r
776   0: ratelogtable[(4*(Rr^0x1F))-0x18+0]\r
777   1: ratelogtable[(4*(Rr^0x1F))-0x18+4]\r
778   2: ratelogtable[(4*(Rr^0x1F))-0x18+6]\r
779   3: ratelogtable[(4*(Rr^0x1F))-0x18+8]\r
780   4: ratelogtable[(4*(Rr^0x1F))-0x18+9]\r
781   5: ratelogtable[(4*(Rr^0x1F))-0x18+10]\r
782   6: ratelogtable[(4*(Rr^0x1F))-0x18+11]\r
783   7: ratelogtable[(4*(Rr^0x1F))-0x18+12]\r
784 \r
785 -----------------------------------------------------------------------------\r
786 */\r
787 \r
788 // vim:shiftwidth=1:expandtab\r