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