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