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