spu: some major reverb refactoring
authornotaz <notasas@gmail.com>
Fri, 29 Jul 2011 23:38:52 +0000 (02:38 +0300)
committernotaz <notasas@gmail.com>
Sat, 30 Jul 2011 20:32:27 +0000 (23:32 +0300)
some ideas lifted from SPU2-X (Pcsx2)

AUTHORS
pandora/readme.txt
plugins/dfsound/externals.h
plugins/dfsound/registers.c
plugins/dfsound/reverb.c
plugins/dfsound/reverb.h [deleted file]
plugins/dfsound/spu.c

diff --git a/AUTHORS b/AUTHORS
index 3e943e3..a9a361c 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -36,11 +36,16 @@ GLES plugin (psx4m project):
        Proger
        Pickle
 
-builtin GPU/SPU plugins:
-       Pete Bernert and the P.E.Op.S. team
+builtin GPU plugin:
+       (C) Pete Bernert and the P.E.Op.S. team
+
+builtin SPU plugin:
+       (C) Pete Bernert and the P.E.Op.S. team
+       (C) SPU2-X, gigaherz, Pcsx2 Development Team
+       shalma
 
 MIPS->ARM recompiler:
-       (C) 2009-2010 Ari64
+       (C) 2009-2011 Ari64
 
 integration, optimization and frontend:
        (C) 2010-2011 notaz
index 2963867..db42e9f 100644 (file)
@@ -202,11 +202,16 @@ GLES plugin (psx4m project):
        Proger
        Pickle
 
-builtin GPU/SPU plugins:
-       Pete Bernert and the P.E.Op.S. team
+builtin GPU/SPU plugin:
+       (C) Pete Bernert and the P.E.Op.S. team
+
+builtin SPU plugin:
+       (C) Pete Bernert and the P.E.Op.S. team
+       (C) SPU2-X, gigaherz, Pcsx2 Development Team
+       shalma
 
 MIPS->ARM recompiler:
-       (C) 2009-2010 Ari64
+       (C) 2009-2011 Ari64
 
 integration, optimization and frontend:
        (C) 2010-2011 notaz
index 2ccc811..73134d0 100644 (file)
@@ -45,7 +45,8 @@
 #define MAXCHAN     24\r
 \r
 // ~ 1 ms of data\r
-#define NSSIZE 45\r
+// note: must be even due to the way reverb works now\r
+#define NSSIZE 46\r
 \r
 ///////////////////////////////////////////////////////////\r
 // struct defines\r
@@ -142,8 +143,6 @@ typedef struct
 \r
  int VolLeft;\r
  int VolRight;\r
- int iLastRVBLeft;\r
- int iLastRVBRight;\r
  int iRVBLeft;\r
  int iRVBRight;\r
 \r
@@ -179,6 +178,17 @@ typedef struct
  int MIX_DEST_B1;    // (offset)\r
  int IN_COEF_L;      // (coef.)\r
  int IN_COEF_R;      // (coef.)\r
+\r
+ int dirty;          // registers changed\r
+\r
+ // normalized offsets\r
+ int nIIR_DEST_A0, nIIR_DEST_A1, nIIR_DEST_B0, nIIR_DEST_B1,\r
+       nACC_SRC_A0, nACC_SRC_A1, nACC_SRC_B0, nACC_SRC_B1, \r
+       nIIR_SRC_A0, nIIR_SRC_A1, nIIR_SRC_B0, nIIR_SRC_B1,\r
+       nACC_SRC_C0, nACC_SRC_C1, nACC_SRC_D0, nACC_SRC_D1,\r
+       nMIX_DEST_A0, nMIX_DEST_A1, nMIX_DEST_B0, nMIX_DEST_B1;\r
+ // MIX_DEST_xx - FB_SRC_x\r
+ int nFB_SRC_A0, nFB_SRC_A1, nFB_SRC_B0, nFB_SRC_B1;\r
 } REVERBInfo;\r
 \r
 ///////////////////////////////////////////////////////////\r
@@ -268,8 +278,5 @@ extern int           iRightXAVol;
 extern int *          sRVBPlay;\r
 extern int *          sRVBEnd;\r
 extern int *          sRVBStart;\r
-extern int            iReverbOff;\r
-extern int            iReverbRepeat;\r
-extern int            iReverbNum;    \r
 \r
 #endif\r
index 87f7558..83b9e43 100644 (file)
@@ -22,7 +22,6 @@
 #include "externals.h"\r
 #include "registers.h"\r
 #include "regs.h"\r
-#include "reverb.h"\r
 \r
 /*\r
 // adsr time values (in ms) by James Higgs ... see the end of\r
@@ -212,6 +211,7 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val)
           rvb.CurrAddr=rvb.StartAddr;\r
          }\r
        }\r
+      rvb.dirty = 1;\r
       break;\r
     //-------------------------------------------------//\r
     case H_SPUirqAddr:\r
@@ -303,19 +303,8 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val)
       ReverbOn(16,24,val);\r
       break;\r
     //-------------------------------------------------//\r
-    case H_Reverb+0:\r
-\r
-      rvb.FB_SRC_A=val;\r
-\r
-      // OK, here's the fake REVERB stuff...\r
-      // depending on effect we do more or less delay and repeats... bah\r
-      // still... better than nothing :)\r
-\r
-      SetREVERB(val);\r
-      break;\r
-\r
-\r
-    case H_Reverb+2   : rvb.FB_SRC_B=(short)val;       break;\r
+    case H_Reverb+0   : rvb.FB_SRC_A=val*4;            break;\r
+    case H_Reverb+2   : rvb.FB_SRC_B=val*4;            break;\r
     case H_Reverb+4   : rvb.IIR_ALPHA=(short)val;      break;\r
     case H_Reverb+6   : rvb.ACC_COEF_A=(short)val;     break;\r
     case H_Reverb+8   : rvb.ACC_COEF_B=(short)val;     break;\r
@@ -324,30 +313,33 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val)
     case H_Reverb+14  : rvb.IIR_COEF=(short)val;       break;\r
     case H_Reverb+16  : rvb.FB_ALPHA=(short)val;       break;\r
     case H_Reverb+18  : rvb.FB_X=(short)val;           break;\r
-    case H_Reverb+20  : rvb.IIR_DEST_A0=(short)val;    break;\r
-    case H_Reverb+22  : rvb.IIR_DEST_A1=(short)val;    break;\r
-    case H_Reverb+24  : rvb.ACC_SRC_A0=(short)val;     break;\r
-    case H_Reverb+26  : rvb.ACC_SRC_A1=(short)val;     break;\r
-    case H_Reverb+28  : rvb.ACC_SRC_B0=(short)val;     break;\r
-    case H_Reverb+30  : rvb.ACC_SRC_B1=(short)val;     break;\r
-    case H_Reverb+32  : rvb.IIR_SRC_A0=(short)val;     break;\r
-    case H_Reverb+34  : rvb.IIR_SRC_A1=(short)val;     break;\r
-    case H_Reverb+36  : rvb.IIR_DEST_B0=(short)val;    break;\r
-    case H_Reverb+38  : rvb.IIR_DEST_B1=(short)val;    break;\r
-    case H_Reverb+40  : rvb.ACC_SRC_C0=(short)val;     break;\r
-    case H_Reverb+42  : rvb.ACC_SRC_C1=(short)val;     break;\r
-    case H_Reverb+44  : rvb.ACC_SRC_D0=(short)val;     break;\r
-    case H_Reverb+46  : rvb.ACC_SRC_D1=(short)val;     break;\r
-    case H_Reverb+48  : rvb.IIR_SRC_B1=(short)val;     break;\r
-    case H_Reverb+50  : rvb.IIR_SRC_B0=(short)val;     break;\r
-    case H_Reverb+52  : rvb.MIX_DEST_A0=(short)val;    break;\r
-    case H_Reverb+54  : rvb.MIX_DEST_A1=(short)val;    break;\r
-    case H_Reverb+56  : rvb.MIX_DEST_B0=(short)val;    break;\r
-    case H_Reverb+58  : rvb.MIX_DEST_B1=(short)val;    break;\r
+    case H_Reverb+20  : rvb.IIR_DEST_A0=val*4;         break;\r
+    case H_Reverb+22  : rvb.IIR_DEST_A1=val*4;         break;\r
+    case H_Reverb+24  : rvb.ACC_SRC_A0=val*4;          break;\r
+    case H_Reverb+26  : rvb.ACC_SRC_A1=val*4;          break;\r
+    case H_Reverb+28  : rvb.ACC_SRC_B0=val*4;          break;\r
+    case H_Reverb+30  : rvb.ACC_SRC_B1=val*4;          break;\r
+    case H_Reverb+32  : rvb.IIR_SRC_A0=val*4;          break;\r
+    case H_Reverb+34  : rvb.IIR_SRC_A1=val*4;          break;\r
+    case H_Reverb+36  : rvb.IIR_DEST_B0=val*4;         break;\r
+    case H_Reverb+38  : rvb.IIR_DEST_B1=val*4;         break;\r
+    case H_Reverb+40  : rvb.ACC_SRC_C0=val*4;          break;\r
+    case H_Reverb+42  : rvb.ACC_SRC_C1=val*4;          break;\r
+    case H_Reverb+44  : rvb.ACC_SRC_D0=val*4;          break;\r
+    case H_Reverb+46  : rvb.ACC_SRC_D1=val*4;          break;\r
+    case H_Reverb+48  : rvb.IIR_SRC_B1=val*4;          break;\r
+    case H_Reverb+50  : rvb.IIR_SRC_B0=val*4;          break;\r
+    case H_Reverb+52  : rvb.MIX_DEST_A0=val*4;         break;\r
+    case H_Reverb+54  : rvb.MIX_DEST_A1=val*4;         break;\r
+    case H_Reverb+56  : rvb.MIX_DEST_B0=val*4;         break;\r
+    case H_Reverb+58  : rvb.MIX_DEST_B1=val*4;         break;\r
     case H_Reverb+60  : rvb.IN_COEF_L=(short)val;      break;\r
     case H_Reverb+62  : rvb.IN_COEF_R=(short)val;      break;\r
    }\r
 \r
+ if ((r & ~0x3f) == H_Reverb)\r
+  rvb.dirty = 1; // recalculate on next update\r
+\r
  iSpuAsyncWait=0;\r
 }\r
 \r
index 343c979..2d65a69 100644 (file)
@@ -4,6 +4,10 @@
     begin                : Wed May 15 2002\r
     copyright            : (C) 2002 by Pete Bernert\r
     email                : BlackDove@addcom.de\r
+\r
+ Portions (C) GraÅžvydas "notaz" Ignotas, 2010-2011\r
+ Portions (C) SPU2-X, gigaherz, Pcsx2 Development Team\r
+\r
  ***************************************************************************/\r
 /***************************************************************************\r
  *                                                                         *\r
 int *          sRVBPlay      = 0;\r
 int *          sRVBEnd       = 0;\r
 int *          sRVBStart     = 0;\r
-int            iReverbOff    = -1;                          // some delay factor for reverb\r
-int            iReverbRepeat = 0;\r
-int            iReverbNum    = 1;    \r
-\r
-////////////////////////////////////////////////////////////////////////\r
-// SET REVERB\r
-////////////////////////////////////////////////////////////////////////\r
-\r
-void SetREVERB(unsigned short val)\r
-{\r
- switch(val)\r
-  {\r
-   case 0x0000: iReverbOff=-1;  break;                                         // off\r
-   case 0x007D: iReverbOff=32;  iReverbNum=2; iReverbRepeat=128;  break;       // ok room\r
-\r
-   case 0x0033: iReverbOff=32;  iReverbNum=2; iReverbRepeat=64;   break;       // studio small\r
-   case 0x00B1: iReverbOff=48;  iReverbNum=2; iReverbRepeat=96;   break;       // ok studio medium\r
-   case 0x00E3: iReverbOff=64;  iReverbNum=2; iReverbRepeat=128;  break;       // ok studio large ok\r
-\r
-   case 0x01A5: iReverbOff=128; iReverbNum=4; iReverbRepeat=32;   break;       // ok hall\r
-   case 0x033D: iReverbOff=256; iReverbNum=4; iReverbRepeat=64;   break;       // space echo\r
-   case 0x0001: iReverbOff=184; iReverbNum=3; iReverbRepeat=128;  break;       // echo/delay\r
-   case 0x0017: iReverbOff=128; iReverbNum=2; iReverbRepeat=128;  break;       // half echo\r
-   default:     iReverbOff=32;  iReverbNum=1; iReverbRepeat=0;    break;\r
-  }\r
-}\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
 // START REVERB\r
@@ -66,15 +44,7 @@ INLINE void StartREVERB(int ch)
 {\r
  if(s_chan[ch].bReverb && (spuCtrl&0x80))              // reverb possible?\r
   {\r
-   if(iUseReverb==2) s_chan[ch].bRVBActive=1;\r
-   else\r
-   if(iUseReverb==1 && iReverbOff>0)                   // -> fake reverb used?\r
-    {\r
-     s_chan[ch].bRVBActive=1;                            // -> activate it\r
-     s_chan[ch].iRVBOffset=iReverbOff*45;\r
-     s_chan[ch].iRVBRepeat=iReverbRepeat*45;\r
-     s_chan[ch].iRVBNum   =iReverbNum;\r
-    }\r
+   s_chan[ch].bRVBActive=!!iUseReverb;\r
   }\r
  else s_chan[ch].bRVBActive=0;                         // else -> no reverb\r
 }\r
@@ -85,199 +55,198 @@ INLINE void StartREVERB(int ch)
 \r
 INLINE void InitREVERB(void)\r
 {\r
- if(iUseReverb==2)\r
-  {memset(sRVBStart,0,NSSIZE*2*4);}\r
+ memset(sRVBStart,0,NSSIZE*2*4);\r
 }\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
 // STORE REVERB\r
 ////////////////////////////////////////////////////////////////////////\r
 \r
-INLINE void StoreREVERB(int ch,int ns,int sval)\r
+INLINE void StoreREVERB(int ch,int ns,int l,int r)\r
 {\r
- if(iUseReverb==0) return;\r
- else\r
- if(iUseReverb==2) // -------------------------------- // Neil's reverb\r
-  {\r
-   const int iRxl=(sval*s_chan[ch].iLeftVolume)/0x4000;\r
-   const int iRxr=(sval*s_chan[ch].iRightVolume)/0x4000;\r
+ ns<<=1;\r
 \r
-   ns<<=1;\r
-\r
-   *(sRVBStart+ns)  +=iRxl;                            // -> we mix all active reverb channels into an extra buffer\r
-   *(sRVBStart+ns+1)+=iRxr;\r
-  }\r
- else // --------------------------------------------- // Pete's easy fake reverb\r
-  {\r
-   int * pN;int iRn,iRr=0;\r
-\r
-   // we use the half channel volume (/0x8000) for the first reverb effects, quarter for next and so on\r
-\r
-   int iRxl=(sval*s_chan[ch].iLeftVolume)/0x8000;\r
-   int iRxr=(sval*s_chan[ch].iRightVolume)/0x8000;\r
\r
-   for(iRn=1;iRn<=s_chan[ch].iRVBNum;iRn++,iRr+=s_chan[ch].iRVBRepeat,iRxl/=2,iRxr/=2)\r
-    {\r
-     pN=sRVBPlay+((s_chan[ch].iRVBOffset+iRr+ns)<<1);\r
-     if(pN>=sRVBEnd) pN=sRVBStart+(pN-sRVBEnd);\r
-\r
-     (*pN)+=iRxl;\r
-     pN++;\r
-     (*pN)+=iRxr;\r
-    }\r
-  }\r
+ sRVBStart[ns]  +=l;                                   // -> we mix all active reverb channels into an extra buffer\r
+ sRVBStart[ns+1]+=r;\r
 }\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
 \r
-INLINE int g_buffer(int iOff)                          // get_buffer content helper: takes care about wraps\r
+INLINE int rvb2ram_offs(int curr, int space, int iOff)\r
 {\r
- short * p=(short *)spuMem;\r
- iOff=(iOff*4)+rvb.CurrAddr;\r
- while(iOff>0x3FFFF)       iOff=rvb.StartAddr+(iOff-0x40000);\r
- while(iOff<rvb.StartAddr) iOff=0x3ffff-(rvb.StartAddr-iOff);\r
- return (int)*(p+iOff);\r
+ iOff += curr;\r
+ if (iOff >= 0x40000) iOff -= space;\r
+ return iOff;\r
 }\r
 \r
-////////////////////////////////////////////////////////////////////////\r
+// get_buffer content helper: takes care about wraps\r
+#define g_buffer(var) \\r
+ ((int)(signed short)spuMem[rvb2ram_offs(curr_addr, space, rvb.n##var)])\r
 \r
-INLINE void s_buffer(int iOff,int iVal)                // set_buffer content helper: takes care about wraps and clipping\r
-{\r
- short * p=(short *)spuMem;\r
- iOff=(iOff*4)+rvb.CurrAddr;\r
- while(iOff>0x3FFFF) iOff=rvb.StartAddr+(iOff-0x40000);\r
- while(iOff<rvb.StartAddr) iOff=0x3ffff-(rvb.StartAddr-iOff);\r
- if(iVal<-32768L) iVal=-32768L;if(iVal>32767L) iVal=32767L;\r
- *(p+iOff)=(short)iVal;\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////\r
+// saturate iVal and store it as var\r
+#define s_buffer(var, iVal) \\r
+ ssat32_to_16(iVal); \\r
+ spuMem[rvb2ram_offs(curr_addr, space, rvb.n##var)] = iVal\r
 \r
-INLINE void s_buffer1(int iOff,int iVal)                // set_buffer (+1 sample) content helper: takes care about wraps and clipping\r
-{\r
- short * p=(short *)spuMem;\r
- iOff=(iOff*4)+rvb.CurrAddr+1;\r
- while(iOff>0x3FFFF) iOff=rvb.StartAddr+(iOff-0x40000);\r
- while(iOff<rvb.StartAddr) iOff=0x3ffff-(rvb.StartAddr-iOff);\r
- if(iVal<-32768L) iVal=-32768L;if(iVal>32767L) iVal=32767L;\r
- *(p+iOff)=(short)iVal;\r
-}\r
+#define s_buffer1(var, iVal) \\r
+ ssat32_to_16(iVal); \\r
+ spuMem[rvb2ram_offs(curr_addr, space, rvb.n##var + 1)] = iVal\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
 \r
-INLINE int MixREVERBLeft(int ns)\r
+// portions based on spu2-x from PCSX2\r
+static void MixREVERB(void)\r
 {\r
- if(iUseReverb==0) return 0;\r
- else\r
- if(iUseReverb==2)\r
-  {\r
-   static int iCnt=0;                                  // this func will be called with 44.1 khz\r
-\r
-   if(!rvb.StartAddr)                                  // reverb is off\r
-    {\r
-     rvb.iLastRVBLeft=rvb.iLastRVBRight=rvb.iRVBLeft=rvb.iRVBRight=0;\r
-     return 0;\r
-    }\r
-\r
-   iCnt++;                                    \r
-\r
-   if(iCnt&1)                                          // we work on every second left value: downsample to 22 khz\r
-    {\r
-     if(spuCtrl&0x80)                                  // -> reverb on? oki\r
-      {\r
-       int ACC0,ACC1,FB_A0,FB_A1,FB_B0,FB_B1;\r
-\r
-       const int INPUT_SAMPLE_L=*(sRVBStart+(ns<<1));                         \r
-       const int INPUT_SAMPLE_R=*(sRVBStart+(ns<<1)+1);                     \r
-\r
-       const int IIR_INPUT_A0 = (g_buffer(rvb.IIR_SRC_A0) * rvb.IIR_COEF)/32768L + (INPUT_SAMPLE_L * rvb.IN_COEF_L)/32768L;\r
-       const int IIR_INPUT_A1 = (g_buffer(rvb.IIR_SRC_A1) * rvb.IIR_COEF)/32768L + (INPUT_SAMPLE_R * rvb.IN_COEF_R)/32768L;\r
-       const int IIR_INPUT_B0 = (g_buffer(rvb.IIR_SRC_B0) * rvb.IIR_COEF)/32768L + (INPUT_SAMPLE_L * rvb.IN_COEF_L)/32768L;\r
-       const int IIR_INPUT_B1 = (g_buffer(rvb.IIR_SRC_B1) * rvb.IIR_COEF)/32768L + (INPUT_SAMPLE_R * rvb.IN_COEF_R)/32768L;\r
-\r
-       const int IIR_A0 = (IIR_INPUT_A0 * rvb.IIR_ALPHA)/32768L + (g_buffer(rvb.IIR_DEST_A0) * (32768L - rvb.IIR_ALPHA))/32768L;\r
-       const int IIR_A1 = (IIR_INPUT_A1 * rvb.IIR_ALPHA)/32768L + (g_buffer(rvb.IIR_DEST_A1) * (32768L - rvb.IIR_ALPHA))/32768L;\r
-       const int IIR_B0 = (IIR_INPUT_B0 * rvb.IIR_ALPHA)/32768L + (g_buffer(rvb.IIR_DEST_B0) * (32768L - rvb.IIR_ALPHA))/32768L;\r
-       const int IIR_B1 = (IIR_INPUT_B1 * rvb.IIR_ALPHA)/32768L + (g_buffer(rvb.IIR_DEST_B1) * (32768L - rvb.IIR_ALPHA))/32768L;\r
-\r
-       s_buffer1(rvb.IIR_DEST_A0, IIR_A0);\r
-       s_buffer1(rvb.IIR_DEST_A1, IIR_A1);\r
-       s_buffer1(rvb.IIR_DEST_B0, IIR_B0);\r
-       s_buffer1(rvb.IIR_DEST_B1, IIR_B1);\r
\r
-       ACC0 = (g_buffer(rvb.ACC_SRC_A0) * rvb.ACC_COEF_A)/32768L +\r
-              (g_buffer(rvb.ACC_SRC_B0) * rvb.ACC_COEF_B)/32768L +\r
-              (g_buffer(rvb.ACC_SRC_C0) * rvb.ACC_COEF_C)/32768L +\r
-              (g_buffer(rvb.ACC_SRC_D0) * rvb.ACC_COEF_D)/32768L;\r
-       ACC1 = (g_buffer(rvb.ACC_SRC_A1) * rvb.ACC_COEF_A)/32768L +\r
-              (g_buffer(rvb.ACC_SRC_B1) * rvb.ACC_COEF_B)/32768L +\r
-              (g_buffer(rvb.ACC_SRC_C1) * rvb.ACC_COEF_C)/32768L +\r
-              (g_buffer(rvb.ACC_SRC_D1) * rvb.ACC_COEF_D)/32768L;\r
-\r
-       FB_A0 = g_buffer(rvb.MIX_DEST_A0 - rvb.FB_SRC_A);\r
-       FB_A1 = g_buffer(rvb.MIX_DEST_A1 - rvb.FB_SRC_A);\r
-       FB_B0 = g_buffer(rvb.MIX_DEST_B0 - rvb.FB_SRC_B);\r
-       FB_B1 = g_buffer(rvb.MIX_DEST_B1 - rvb.FB_SRC_B);\r
-\r
-       s_buffer(rvb.MIX_DEST_A0, ACC0 - (FB_A0 * rvb.FB_ALPHA)/32768L);\r
-       s_buffer(rvb.MIX_DEST_A1, ACC1 - (FB_A1 * rvb.FB_ALPHA)/32768L);\r
-       \r
-       s_buffer(rvb.MIX_DEST_B0, (rvb.FB_ALPHA * ACC0)/32768L - (FB_A0 * (int)(rvb.FB_ALPHA^0xFFFF8000))/32768L - (FB_B0 * rvb.FB_X)/32768L);\r
-       s_buffer(rvb.MIX_DEST_B1, (rvb.FB_ALPHA * ACC1)/32768L - (FB_A1 * (int)(rvb.FB_ALPHA^0xFFFF8000))/32768L - (FB_B1 * rvb.FB_X)/32768L);\r
\r
-       rvb.iLastRVBLeft  = rvb.iRVBLeft;\r
-       rvb.iLastRVBRight = rvb.iRVBRight;\r
-\r
-       rvb.iRVBLeft  = (g_buffer(rvb.MIX_DEST_A0)+g_buffer(rvb.MIX_DEST_B0))/3;\r
-       rvb.iRVBRight = (g_buffer(rvb.MIX_DEST_A1)+g_buffer(rvb.MIX_DEST_B1))/3;\r
-\r
-       rvb.iRVBLeft  = (rvb.iRVBLeft  * rvb.VolLeft)  / 0x4000;\r
-       rvb.iRVBRight = (rvb.iRVBRight * rvb.VolRight) / 0x4000;\r
-\r
-       rvb.CurrAddr++;\r
-       if(rvb.CurrAddr>0x3ffff) rvb.CurrAddr=rvb.StartAddr;\r
-\r
-       return rvb.iLastRVBLeft+(rvb.iRVBLeft-rvb.iLastRVBLeft)/2;\r
-      }\r
-     else                                              // -> reverb off\r
-      {\r
-       rvb.iLastRVBLeft=rvb.iLastRVBRight=rvb.iRVBLeft=rvb.iRVBRight=0;\r
-      }\r
-\r
-     rvb.CurrAddr++;\r
-     if(rvb.CurrAddr>0x3ffff) rvb.CurrAddr=rvb.StartAddr;\r
-    }\r
-\r
-   return rvb.iLastRVBLeft;\r
-  }\r
- else                                                  // easy fake reverb:\r
+ int l_old = rvb.iRVBLeft;\r
+ int r_old = rvb.iRVBRight;\r
+ int curr_addr = rvb.CurrAddr;\r
+ int space = 0x40000 - rvb.StartAddr;\r
+ int l, r, ns;\r
+\r
+ for (ns = 0; ns < NSSIZE*2; )\r
   {\r
-   const int iRV=*sRVBPlay;                            // -> simply take the reverb mix buf value\r
-   *sRVBPlay++=0;                                      // -> init it after\r
-   if(sRVBPlay>=sRVBEnd) sRVBPlay=sRVBStart;           // -> and take care about wrap arounds\r
-   return iRV;                                         // -> return reverb mix buf val\r
+   int IIR_ALPHA = rvb.IIR_ALPHA;\r
+   int ACC0, ACC1, FB_A0, FB_A1, FB_B0, FB_B1;\r
+   int mix_dest_a0, mix_dest_a1, mix_dest_b0, mix_dest_b1;\r
+\r
+   int input_L = sRVBStart[ns]   * rvb.IN_COEF_L;\r
+   int input_R = sRVBStart[ns+1] * rvb.IN_COEF_R;\r
+\r
+   int IIR_INPUT_A0 = ((g_buffer(IIR_SRC_A0) * rvb.IIR_COEF) + input_L) >> 15;\r
+   int IIR_INPUT_A1 = ((g_buffer(IIR_SRC_A1) * rvb.IIR_COEF) + input_R) >> 15;\r
+   int IIR_INPUT_B0 = ((g_buffer(IIR_SRC_B0) * rvb.IIR_COEF) + input_L) >> 15;\r
+   int IIR_INPUT_B1 = ((g_buffer(IIR_SRC_B1) * rvb.IIR_COEF) + input_R) >> 15;\r
+\r
+   int iir_dest_a0 = g_buffer(IIR_DEST_A0);\r
+   int iir_dest_a1 = g_buffer(IIR_DEST_A1);\r
+   int iir_dest_b0 = g_buffer(IIR_DEST_B0);\r
+   int iir_dest_b1 = g_buffer(IIR_DEST_B1);\r
+\r
+   int IIR_A0 = iir_dest_a0 + ((IIR_INPUT_A0 - iir_dest_a0) * IIR_ALPHA >> 15);\r
+   int IIR_A1 = iir_dest_a1 + ((IIR_INPUT_A1 - iir_dest_a1) * IIR_ALPHA >> 15);\r
+   int IIR_B0 = iir_dest_b0 + ((IIR_INPUT_B0 - iir_dest_b0) * IIR_ALPHA >> 15);\r
+   int IIR_B1 = iir_dest_b1 + ((IIR_INPUT_B1 - iir_dest_b1) * IIR_ALPHA >> 15);\r
+\r
+   s_buffer1(IIR_DEST_A0, IIR_A0);\r
+   s_buffer1(IIR_DEST_A1, IIR_A1);\r
+   s_buffer1(IIR_DEST_B0, IIR_B0);\r
+   s_buffer1(IIR_DEST_B1, IIR_B1);\r
+\r
+   ACC0 = (g_buffer(ACC_SRC_A0) * rvb.ACC_COEF_A +\r
+           g_buffer(ACC_SRC_B0) * rvb.ACC_COEF_B +\r
+           g_buffer(ACC_SRC_C0) * rvb.ACC_COEF_C +\r
+           g_buffer(ACC_SRC_D0) * rvb.ACC_COEF_D) >> 15;\r
+   ACC1 = (g_buffer(ACC_SRC_A1) * rvb.ACC_COEF_A +\r
+           g_buffer(ACC_SRC_B1) * rvb.ACC_COEF_B +\r
+           g_buffer(ACC_SRC_C1) * rvb.ACC_COEF_C +\r
+           g_buffer(ACC_SRC_D1) * rvb.ACC_COEF_D) >> 15;\r
+\r
+   FB_A0 = g_buffer(FB_SRC_A0);\r
+   FB_A1 = g_buffer(FB_SRC_A1);\r
+   FB_B0 = g_buffer(FB_SRC_B0);\r
+   FB_B1 = g_buffer(FB_SRC_B1);\r
+\r
+   mix_dest_a0 = ACC0 - ((FB_A0 * rvb.FB_ALPHA) >> 15);\r
+   mix_dest_a1 = ACC1 - ((FB_A1 * rvb.FB_ALPHA) >> 15);\r
+\r
+   mix_dest_b0 = FB_A0 + (((ACC0 - FB_A0) * rvb.FB_ALPHA - FB_B0 * rvb.FB_X) >> 15);\r
+   mix_dest_b1 = FB_A1 + (((ACC1 - FB_A1) * rvb.FB_ALPHA - FB_B1 * rvb.FB_X) >> 15);\r
+\r
+   s_buffer(MIX_DEST_A0, mix_dest_a0);\r
+   s_buffer(MIX_DEST_A1, mix_dest_a1);\r
+   s_buffer(MIX_DEST_B0, mix_dest_b0);\r
+   s_buffer(MIX_DEST_B1, mix_dest_b1);\r
+\r
+   l = (mix_dest_a0 + mix_dest_b0) / 3;\r
+   r = (mix_dest_a1 + mix_dest_b1) / 3;\r
+\r
+   l = (l * rvb.VolLeft)  >> 14;\r
+   r = (r * rvb.VolRight) >> 14;\r
+\r
+   SSumLR[ns++] += (l + l_old) / 2;\r
+   SSumLR[ns++] += (r + r_old) / 2;\r
+   SSumLR[ns++] += l;\r
+   SSumLR[ns++] += r;\r
+\r
+   l_old = l;\r
+   r_old = r;\r
+\r
+   curr_addr++;\r
+   if (curr_addr >= 0x40000) curr_addr = rvb.StartAddr;\r
   }\r
+\r
+ rvb.iRVBLeft = l;\r
+ rvb.iRVBRight = r;\r
+ rvb.CurrAddr = curr_addr;\r
 }\r
 \r
-////////////////////////////////////////////////////////////////////////\r
+static void prepare_offsets(void)\r
+{\r
+ int space = 0x40000 - rvb.StartAddr;\r
+ int t;\r
+ #define prep_offs(v) \\r
+   t = rvb.v; \\r
+   while (t >= space) \\r
+     t -= space; \\r
+   rvb.n##v = t\r
+ #define prep_offs2(d, v1, v2) \\r
+   t = rvb.v1 - rvb.v2; \\r
+   while (t >= space) \\r
+     t -= space; \\r
+   rvb.n##d = t\r
+\r
+ prep_offs(IIR_SRC_A0);\r
+ prep_offs(IIR_SRC_A1);\r
+ prep_offs(IIR_SRC_B0);\r
+ prep_offs(IIR_SRC_B1);\r
+ prep_offs(IIR_DEST_A0);\r
+ prep_offs(IIR_DEST_A1);\r
+ prep_offs(IIR_DEST_B0);\r
+ prep_offs(IIR_DEST_B1);\r
+ prep_offs(ACC_SRC_A0);\r
+ prep_offs(ACC_SRC_A1);\r
+ prep_offs(ACC_SRC_B0);\r
+ prep_offs(ACC_SRC_B1);\r
+ prep_offs(ACC_SRC_C0);\r
+ prep_offs(ACC_SRC_C1);\r
+ prep_offs(ACC_SRC_D0);\r
+ prep_offs(ACC_SRC_D1);\r
+ prep_offs(MIX_DEST_A0);\r
+ prep_offs(MIX_DEST_A1);\r
+ prep_offs(MIX_DEST_B0);\r
+ prep_offs(MIX_DEST_B1);\r
+ prep_offs2(FB_SRC_A0, MIX_DEST_A0, FB_SRC_A);\r
+ prep_offs2(FB_SRC_A1, MIX_DEST_A1, FB_SRC_A);\r
+ prep_offs2(FB_SRC_B0, MIX_DEST_B0, FB_SRC_B);\r
+ prep_offs2(FB_SRC_B1, MIX_DEST_B1, FB_SRC_B);\r
+\r
+#undef prep_offs\r
+#undef prep_offs2\r
+ rvb.dirty = 0;\r
+}\r
 \r
-INLINE int MixREVERBRight(void)\r
+INLINE void REVERBDo(void)\r
 {\r
- if(iUseReverb==0) return 0;\r
- else\r
- if(iUseReverb==2)                                     // Neill's reverb:\r
-  {\r
-   int i=rvb.iLastRVBRight+(rvb.iRVBRight-rvb.iLastRVBRight)/2;\r
-   rvb.iLastRVBRight=rvb.iRVBRight;\r
-   return i;                                           // -> just return the last right reverb val (little bit scaled by the previous right val)\r
-  }\r
- else                                                  // easy fake reverb:\r
-  {\r
-   const int iRV=*sRVBPlay;                            // -> simply take the reverb mix buf value\r
-   *sRVBPlay++=0;                                      // -> init it after\r
-   if(sRVBPlay>=sRVBEnd) sRVBPlay=sRVBStart;           // -> and take care about wrap arounds\r
-   return iRV;                                         // -> return reverb mix buf val\r
-  }\r
+ if (!rvb.StartAddr)                                   // reverb is off\r
+ {\r
+  rvb.iRVBLeft = rvb.iRVBRight = 0;\r
+  return;\r
+ }\r
+\r
+ if (spuCtrl & 0x80)                                   // -> reverb on? oki\r
+ {\r
+  if (rvb.dirty)\r
+   prepare_offsets();\r
+\r
+  MixREVERB();\r
+ }\r
+ else                                                  // -> reverb off\r
+ {\r
+  // supposedly runs anyway?\r
+  rvb.CurrAddr += NSSIZE/2;\r
+  while (rvb.CurrAddr >= 0x40000)\r
+   rvb.CurrAddr -= 0x40000 - rvb.StartAddr;\r
+ }\r
 }\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
@@ -460,3 +429,4 @@ buffer[MIX_DEST_B1] = (FB_ALPHA * ACC1) - FB_A1 * (FB_ALPHA^0x8000) - FB_B1 * FB
 -----------------------------------------------------------------------------\r
 */\r
 \r
+// vim:shiftwidth=1:expandtab\r
diff --git a/plugins/dfsound/reverb.h b/plugins/dfsound/reverb.h
deleted file mode 100644 (file)
index f7e9aa2..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/***************************************************************************\r
-                          reverb.h  -  description\r
-                             -------------------\r
-    begin                : Wed May 15 2002\r
-    copyright            : (C) 2002 by Pete Bernert\r
-    email                : BlackDove@addcom.de\r
- ***************************************************************************/\r
-/***************************************************************************\r
- *                                                                         *\r
- *   This program is free software; you can redistribute it and/or modify  *\r
- *   it under the terms of the GNU General Public License as published by  *\r
- *   the Free Software Foundation; either version 2 of the License, or     *\r
- *   (at your option) any later version. See also the license.txt file for *\r
- *   additional informations.                                              *\r
- *                                                                         *\r
- ***************************************************************************/\r
-\r
-void SetREVERB(unsigned short val);\r
-\r
index e6c5449..d6cd952 100644 (file)
 #define N_(x) (x)
 #endif
 
+#ifdef __arm__
+ #define ssat32_to_16(v) \
+  asm("ssat %0,#16,%1" : "=r" (v) : "r" (v))
+#else
+ #define ssat32_to_16(v) do { \
+  if (v < -32768) v = -32768; \
+  else if (v > 32767) v = 32767; \
+ } while (0)
+#endif
+
 /*
 #if defined (USEMACOSX)
 static char * libraryName     = N_("Mac OS X Sound");
@@ -730,21 +740,28 @@ static void *MAINThread(void *arg)
 
        if(s_chan[ch].bFMod==2)                         // fmod freq channel
         memcpy(iFMod, ChanBuf, sizeof(iFMod));
-       else for(ns=ns_from;ns<ns_to;ns++)
+       else
         {
-         int sval = ChanBuf[ns];
+         int lv=s_chan[ch].iLeftVolume;
+         int rv=s_chan[ch].iRightVolume;
 
+         for(ns=ns_from;ns<ns_to;ns++)
           {
+           int sval = ChanBuf[ns];
+           int l, r;
+
            //////////////////////////////////////////////
            // ok, left/right sound volume (psx volume goes from 0 ... 0x3fff)
 
-           SSumLR[ns*2]  +=(sval*s_chan[ch].iLeftVolume)/0x4000L;
-           SSumLR[ns*2+1]+=(sval*s_chan[ch].iRightVolume)/0x4000L;
+           l=(sval*lv)>>14;
+           r=(sval*rv)>>14;
+           SSumLR[ns*2]  +=l;
+           SSumLR[ns*2+1]+=r;
 
            //////////////////////////////////////////////
            // now let us store sound data for reverb    
 
-           if(s_chan[ch].bRVBActive) StoreREVERB(ch,ns,sval);
+           if(s_chan[ch].bRVBActive) StoreREVERB(ch,ns,l,r);
           }
         }
       }
@@ -811,19 +828,24 @@ static void *MAINThread(void *arg)
   ///////////////////////////////////////////////////////
   // mix all channels (including reverb) into one buffer
 
+  if(iUseReverb)
+   REVERBDo();
+
+  if((spuCtrl&0x4000)==0) // muted? (rare, don't optimize for this)
+   {
+    memset(pS, 0, NSSIZE * 2 * sizeof(pS[0]));
+    pS += NSSIZE*2;
+   }
+  else
   for (ns = 0; ns < NSSIZE*2; )
    {
-    SSumLR[ns] += MixREVERBLeft(ns/2);
-
     d = SSumLR[ns] / voldiv; SSumLR[ns] = 0;
-    if (d < -32767) d = -32767; if (d > 32767) d = 32767;
+    ssat32_to_16(d);
     *pS++ = d;
     ns++;
 
-    SSumLR[ns] += MixREVERBRight();
-
     d = SSumLR[ns] / voldiv; SSumLR[ns] = 0;
-    if(d < -32767) d = -32767; if(d > 32767) d = 32767;
+    ssat32_to_16(d);
     *pS++ = d;
     ns++;
    }
@@ -1037,7 +1059,6 @@ long CALLBACK SPUinit(void)
  InitADSR();
 
  iVolume = 3;
- iReverbOff = -1;
  spuIrq = 0;
  spuAddr = 0xffffffff;
  bEndThread = 0;