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