From: notaz Date: Fri, 29 Jul 2011 23:38:52 +0000 (+0300) Subject: spu: some major reverb refactoring X-Git-Tag: r9~26 X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=commitdiff_plain;h=1775933abd26d2e282c4e0b4093778d204a0038d;hp=07a6dd2ce2c0c8ea2de11c30c134c877e7c7b0fb spu: some major reverb refactoring some ideas lifted from SPU2-X (Pcsx2) --- diff --git a/AUTHORS b/AUTHORS index 3e943e3a..a9a361c7 100644 --- 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 diff --git a/pandora/readme.txt b/pandora/readme.txt index 2963867b..db42e9fb 100644 --- a/pandora/readme.txt +++ b/pandora/readme.txt @@ -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 diff --git a/plugins/dfsound/externals.h b/plugins/dfsound/externals.h index 2ccc811d..73134d07 100644 --- a/plugins/dfsound/externals.h +++ b/plugins/dfsound/externals.h @@ -45,7 +45,8 @@ #define MAXCHAN 24 // ~ 1 ms of data -#define NSSIZE 45 +// note: must be even due to the way reverb works now +#define NSSIZE 46 /////////////////////////////////////////////////////////// // struct defines @@ -142,8 +143,6 @@ typedef struct int VolLeft; int VolRight; - int iLastRVBLeft; - int iLastRVBRight; int iRVBLeft; int iRVBRight; @@ -179,6 +178,17 @@ typedef struct int MIX_DEST_B1; // (offset) int IN_COEF_L; // (coef.) int IN_COEF_R; // (coef.) + + int dirty; // registers changed + + // normalized offsets + int nIIR_DEST_A0, nIIR_DEST_A1, nIIR_DEST_B0, nIIR_DEST_B1, + nACC_SRC_A0, nACC_SRC_A1, nACC_SRC_B0, nACC_SRC_B1, + nIIR_SRC_A0, nIIR_SRC_A1, nIIR_SRC_B0, nIIR_SRC_B1, + nACC_SRC_C0, nACC_SRC_C1, nACC_SRC_D0, nACC_SRC_D1, + nMIX_DEST_A0, nMIX_DEST_A1, nMIX_DEST_B0, nMIX_DEST_B1; + // MIX_DEST_xx - FB_SRC_x + int nFB_SRC_A0, nFB_SRC_A1, nFB_SRC_B0, nFB_SRC_B1; } REVERBInfo; /////////////////////////////////////////////////////////// @@ -268,8 +278,5 @@ extern int iRightXAVol; extern int * sRVBPlay; extern int * sRVBEnd; extern int * sRVBStart; -extern int iReverbOff; -extern int iReverbRepeat; -extern int iReverbNum; #endif diff --git a/plugins/dfsound/registers.c b/plugins/dfsound/registers.c index 87f7558e..83b9e438 100644 --- a/plugins/dfsound/registers.c +++ b/plugins/dfsound/registers.c @@ -22,7 +22,6 @@ #include "externals.h" #include "registers.h" #include "regs.h" -#include "reverb.h" /* // adsr time values (in ms) by James Higgs ... see the end of @@ -212,6 +211,7 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val) rvb.CurrAddr=rvb.StartAddr; } } + rvb.dirty = 1; break; //-------------------------------------------------// case H_SPUirqAddr: @@ -303,19 +303,8 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val) ReverbOn(16,24,val); break; //-------------------------------------------------// - case H_Reverb+0: - - rvb.FB_SRC_A=val; - - // OK, here's the fake REVERB stuff... - // depending on effect we do more or less delay and repeats... bah - // still... better than nothing :) - - SetREVERB(val); - break; - - - case H_Reverb+2 : rvb.FB_SRC_B=(short)val; break; + case H_Reverb+0 : rvb.FB_SRC_A=val*4; break; + case H_Reverb+2 : rvb.FB_SRC_B=val*4; break; case H_Reverb+4 : rvb.IIR_ALPHA=(short)val; break; case H_Reverb+6 : rvb.ACC_COEF_A=(short)val; break; case H_Reverb+8 : rvb.ACC_COEF_B=(short)val; break; @@ -324,30 +313,33 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val) case H_Reverb+14 : rvb.IIR_COEF=(short)val; break; case H_Reverb+16 : rvb.FB_ALPHA=(short)val; break; case H_Reverb+18 : rvb.FB_X=(short)val; break; - case H_Reverb+20 : rvb.IIR_DEST_A0=(short)val; break; - case H_Reverb+22 : rvb.IIR_DEST_A1=(short)val; break; - case H_Reverb+24 : rvb.ACC_SRC_A0=(short)val; break; - case H_Reverb+26 : rvb.ACC_SRC_A1=(short)val; break; - case H_Reverb+28 : rvb.ACC_SRC_B0=(short)val; break; - case H_Reverb+30 : rvb.ACC_SRC_B1=(short)val; break; - case H_Reverb+32 : rvb.IIR_SRC_A0=(short)val; break; - case H_Reverb+34 : rvb.IIR_SRC_A1=(short)val; break; - case H_Reverb+36 : rvb.IIR_DEST_B0=(short)val; break; - case H_Reverb+38 : rvb.IIR_DEST_B1=(short)val; break; - case H_Reverb+40 : rvb.ACC_SRC_C0=(short)val; break; - case H_Reverb+42 : rvb.ACC_SRC_C1=(short)val; break; - case H_Reverb+44 : rvb.ACC_SRC_D0=(short)val; break; - case H_Reverb+46 : rvb.ACC_SRC_D1=(short)val; break; - case H_Reverb+48 : rvb.IIR_SRC_B1=(short)val; break; - case H_Reverb+50 : rvb.IIR_SRC_B0=(short)val; break; - case H_Reverb+52 : rvb.MIX_DEST_A0=(short)val; break; - case H_Reverb+54 : rvb.MIX_DEST_A1=(short)val; break; - case H_Reverb+56 : rvb.MIX_DEST_B0=(short)val; break; - case H_Reverb+58 : rvb.MIX_DEST_B1=(short)val; break; + case H_Reverb+20 : rvb.IIR_DEST_A0=val*4; break; + case H_Reverb+22 : rvb.IIR_DEST_A1=val*4; break; + case H_Reverb+24 : rvb.ACC_SRC_A0=val*4; break; + case H_Reverb+26 : rvb.ACC_SRC_A1=val*4; break; + case H_Reverb+28 : rvb.ACC_SRC_B0=val*4; break; + case H_Reverb+30 : rvb.ACC_SRC_B1=val*4; break; + case H_Reverb+32 : rvb.IIR_SRC_A0=val*4; break; + case H_Reverb+34 : rvb.IIR_SRC_A1=val*4; break; + case H_Reverb+36 : rvb.IIR_DEST_B0=val*4; break; + case H_Reverb+38 : rvb.IIR_DEST_B1=val*4; break; + case H_Reverb+40 : rvb.ACC_SRC_C0=val*4; break; + case H_Reverb+42 : rvb.ACC_SRC_C1=val*4; break; + case H_Reverb+44 : rvb.ACC_SRC_D0=val*4; break; + case H_Reverb+46 : rvb.ACC_SRC_D1=val*4; break; + case H_Reverb+48 : rvb.IIR_SRC_B1=val*4; break; + case H_Reverb+50 : rvb.IIR_SRC_B0=val*4; break; + case H_Reverb+52 : rvb.MIX_DEST_A0=val*4; break; + case H_Reverb+54 : rvb.MIX_DEST_A1=val*4; break; + case H_Reverb+56 : rvb.MIX_DEST_B0=val*4; break; + case H_Reverb+58 : rvb.MIX_DEST_B1=val*4; break; case H_Reverb+60 : rvb.IN_COEF_L=(short)val; break; case H_Reverb+62 : rvb.IN_COEF_R=(short)val; break; } + if ((r & ~0x3f) == H_Reverb) + rvb.dirty = 1; // recalculate on next update + iSpuAsyncWait=0; } diff --git a/plugins/dfsound/reverb.c b/plugins/dfsound/reverb.c index 343c979d..2d65a694 100644 --- a/plugins/dfsound/reverb.c +++ b/plugins/dfsound/reverb.c @@ -4,6 +4,10 @@ begin : Wed May 15 2002 copyright : (C) 2002 by Pete Bernert email : BlackDove@addcom.de + + Portions (C) Gražvydas "notaz" Ignotas, 2010-2011 + Portions (C) SPU2-X, gigaherz, Pcsx2 Development Team + ***************************************************************************/ /*************************************************************************** * * @@ -31,32 +35,6 @@ int * sRVBPlay = 0; int * sRVBEnd = 0; int * sRVBStart = 0; -int iReverbOff = -1; // some delay factor for reverb -int iReverbRepeat = 0; -int iReverbNum = 1; - -//////////////////////////////////////////////////////////////////////// -// SET REVERB -//////////////////////////////////////////////////////////////////////// - -void SetREVERB(unsigned short val) -{ - switch(val) - { - case 0x0000: iReverbOff=-1; break; // off - case 0x007D: iReverbOff=32; iReverbNum=2; iReverbRepeat=128; break; // ok room - - case 0x0033: iReverbOff=32; iReverbNum=2; iReverbRepeat=64; break; // studio small - case 0x00B1: iReverbOff=48; iReverbNum=2; iReverbRepeat=96; break; // ok studio medium - case 0x00E3: iReverbOff=64; iReverbNum=2; iReverbRepeat=128; break; // ok studio large ok - - case 0x01A5: iReverbOff=128; iReverbNum=4; iReverbRepeat=32; break; // ok hall - case 0x033D: iReverbOff=256; iReverbNum=4; iReverbRepeat=64; break; // space echo - case 0x0001: iReverbOff=184; iReverbNum=3; iReverbRepeat=128; break; // echo/delay - case 0x0017: iReverbOff=128; iReverbNum=2; iReverbRepeat=128; break; // half echo - default: iReverbOff=32; iReverbNum=1; iReverbRepeat=0; break; - } -} //////////////////////////////////////////////////////////////////////// // START REVERB @@ -66,15 +44,7 @@ INLINE void StartREVERB(int ch) { if(s_chan[ch].bReverb && (spuCtrl&0x80)) // reverb possible? { - if(iUseReverb==2) s_chan[ch].bRVBActive=1; - else - if(iUseReverb==1 && iReverbOff>0) // -> fake reverb used? - { - s_chan[ch].bRVBActive=1; // -> activate it - s_chan[ch].iRVBOffset=iReverbOff*45; - s_chan[ch].iRVBRepeat=iReverbRepeat*45; - s_chan[ch].iRVBNum =iReverbNum; - } + s_chan[ch].bRVBActive=!!iUseReverb; } else s_chan[ch].bRVBActive=0; // else -> no reverb } @@ -85,199 +55,198 @@ INLINE void StartREVERB(int ch) INLINE void InitREVERB(void) { - if(iUseReverb==2) - {memset(sRVBStart,0,NSSIZE*2*4);} + memset(sRVBStart,0,NSSIZE*2*4); } //////////////////////////////////////////////////////////////////////// // STORE REVERB //////////////////////////////////////////////////////////////////////// -INLINE void StoreREVERB(int ch,int ns,int sval) +INLINE void StoreREVERB(int ch,int ns,int l,int r) { - if(iUseReverb==0) return; - else - if(iUseReverb==2) // -------------------------------- // Neil's reverb - { - const int iRxl=(sval*s_chan[ch].iLeftVolume)/0x4000; - const int iRxr=(sval*s_chan[ch].iRightVolume)/0x4000; + ns<<=1; - ns<<=1; - - *(sRVBStart+ns) +=iRxl; // -> we mix all active reverb channels into an extra buffer - *(sRVBStart+ns+1)+=iRxr; - } - else // --------------------------------------------- // Pete's easy fake reverb - { - int * pN;int iRn,iRr=0; - - // we use the half channel volume (/0x8000) for the first reverb effects, quarter for next and so on - - int iRxl=(sval*s_chan[ch].iLeftVolume)/0x8000; - int iRxr=(sval*s_chan[ch].iRightVolume)/0x8000; - - for(iRn=1;iRn<=s_chan[ch].iRVBNum;iRn++,iRr+=s_chan[ch].iRVBRepeat,iRxl/=2,iRxr/=2) - { - pN=sRVBPlay+((s_chan[ch].iRVBOffset+iRr+ns)<<1); - if(pN>=sRVBEnd) pN=sRVBStart+(pN-sRVBEnd); - - (*pN)+=iRxl; - pN++; - (*pN)+=iRxr; - } - } + sRVBStart[ns] +=l; // -> we mix all active reverb channels into an extra buffer + sRVBStart[ns+1]+=r; } //////////////////////////////////////////////////////////////////////// -INLINE int g_buffer(int iOff) // get_buffer content helper: takes care about wraps +INLINE int rvb2ram_offs(int curr, int space, int iOff) { - short * p=(short *)spuMem; - iOff=(iOff*4)+rvb.CurrAddr; - while(iOff>0x3FFFF) iOff=rvb.StartAddr+(iOff-0x40000); - while(iOff= 0x40000) iOff -= space; + return iOff; } -//////////////////////////////////////////////////////////////////////// +// get_buffer content helper: takes care about wraps +#define g_buffer(var) \ + ((int)(signed short)spuMem[rvb2ram_offs(curr_addr, space, rvb.n##var)]) -INLINE void s_buffer(int iOff,int iVal) // set_buffer content helper: takes care about wraps and clipping -{ - short * p=(short *)spuMem; - iOff=(iOff*4)+rvb.CurrAddr; - while(iOff>0x3FFFF) iOff=rvb.StartAddr+(iOff-0x40000); - while(iOff32767L) iVal=32767L; - *(p+iOff)=(short)iVal; -} - -//////////////////////////////////////////////////////////////////////// +// saturate iVal and store it as var +#define s_buffer(var, iVal) \ + ssat32_to_16(iVal); \ + spuMem[rvb2ram_offs(curr_addr, space, rvb.n##var)] = iVal -INLINE void s_buffer1(int iOff,int iVal) // set_buffer (+1 sample) content helper: takes care about wraps and clipping -{ - short * p=(short *)spuMem; - iOff=(iOff*4)+rvb.CurrAddr+1; - while(iOff>0x3FFFF) iOff=rvb.StartAddr+(iOff-0x40000); - while(iOff32767L) iVal=32767L; - *(p+iOff)=(short)iVal; -} +#define s_buffer1(var, iVal) \ + ssat32_to_16(iVal); \ + spuMem[rvb2ram_offs(curr_addr, space, rvb.n##var + 1)] = iVal //////////////////////////////////////////////////////////////////////// -INLINE int MixREVERBLeft(int ns) +// portions based on spu2-x from PCSX2 +static void MixREVERB(void) { - if(iUseReverb==0) return 0; - else - if(iUseReverb==2) - { - static int iCnt=0; // this func will be called with 44.1 khz - - if(!rvb.StartAddr) // reverb is off - { - rvb.iLastRVBLeft=rvb.iLastRVBRight=rvb.iRVBLeft=rvb.iRVBRight=0; - return 0; - } - - iCnt++; - - if(iCnt&1) // we work on every second left value: downsample to 22 khz - { - if(spuCtrl&0x80) // -> reverb on? oki - { - int ACC0,ACC1,FB_A0,FB_A1,FB_B0,FB_B1; - - const int INPUT_SAMPLE_L=*(sRVBStart+(ns<<1)); - const int INPUT_SAMPLE_R=*(sRVBStart+(ns<<1)+1); - - const int IIR_INPUT_A0 = (g_buffer(rvb.IIR_SRC_A0) * rvb.IIR_COEF)/32768L + (INPUT_SAMPLE_L * rvb.IN_COEF_L)/32768L; - const int IIR_INPUT_A1 = (g_buffer(rvb.IIR_SRC_A1) * rvb.IIR_COEF)/32768L + (INPUT_SAMPLE_R * rvb.IN_COEF_R)/32768L; - const int IIR_INPUT_B0 = (g_buffer(rvb.IIR_SRC_B0) * rvb.IIR_COEF)/32768L + (INPUT_SAMPLE_L * rvb.IN_COEF_L)/32768L; - const int IIR_INPUT_B1 = (g_buffer(rvb.IIR_SRC_B1) * rvb.IIR_COEF)/32768L + (INPUT_SAMPLE_R * rvb.IN_COEF_R)/32768L; - - const int IIR_A0 = (IIR_INPUT_A0 * rvb.IIR_ALPHA)/32768L + (g_buffer(rvb.IIR_DEST_A0) * (32768L - rvb.IIR_ALPHA))/32768L; - const int IIR_A1 = (IIR_INPUT_A1 * rvb.IIR_ALPHA)/32768L + (g_buffer(rvb.IIR_DEST_A1) * (32768L - rvb.IIR_ALPHA))/32768L; - const int IIR_B0 = (IIR_INPUT_B0 * rvb.IIR_ALPHA)/32768L + (g_buffer(rvb.IIR_DEST_B0) * (32768L - rvb.IIR_ALPHA))/32768L; - const int IIR_B1 = (IIR_INPUT_B1 * rvb.IIR_ALPHA)/32768L + (g_buffer(rvb.IIR_DEST_B1) * (32768L - rvb.IIR_ALPHA))/32768L; - - s_buffer1(rvb.IIR_DEST_A0, IIR_A0); - s_buffer1(rvb.IIR_DEST_A1, IIR_A1); - s_buffer1(rvb.IIR_DEST_B0, IIR_B0); - s_buffer1(rvb.IIR_DEST_B1, IIR_B1); - - ACC0 = (g_buffer(rvb.ACC_SRC_A0) * rvb.ACC_COEF_A)/32768L + - (g_buffer(rvb.ACC_SRC_B0) * rvb.ACC_COEF_B)/32768L + - (g_buffer(rvb.ACC_SRC_C0) * rvb.ACC_COEF_C)/32768L + - (g_buffer(rvb.ACC_SRC_D0) * rvb.ACC_COEF_D)/32768L; - ACC1 = (g_buffer(rvb.ACC_SRC_A1) * rvb.ACC_COEF_A)/32768L + - (g_buffer(rvb.ACC_SRC_B1) * rvb.ACC_COEF_B)/32768L + - (g_buffer(rvb.ACC_SRC_C1) * rvb.ACC_COEF_C)/32768L + - (g_buffer(rvb.ACC_SRC_D1) * rvb.ACC_COEF_D)/32768L; - - FB_A0 = g_buffer(rvb.MIX_DEST_A0 - rvb.FB_SRC_A); - FB_A1 = g_buffer(rvb.MIX_DEST_A1 - rvb.FB_SRC_A); - FB_B0 = g_buffer(rvb.MIX_DEST_B0 - rvb.FB_SRC_B); - FB_B1 = g_buffer(rvb.MIX_DEST_B1 - rvb.FB_SRC_B); - - s_buffer(rvb.MIX_DEST_A0, ACC0 - (FB_A0 * rvb.FB_ALPHA)/32768L); - s_buffer(rvb.MIX_DEST_A1, ACC1 - (FB_A1 * rvb.FB_ALPHA)/32768L); - - 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); - 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); - - rvb.iLastRVBLeft = rvb.iRVBLeft; - rvb.iLastRVBRight = rvb.iRVBRight; - - rvb.iRVBLeft = (g_buffer(rvb.MIX_DEST_A0)+g_buffer(rvb.MIX_DEST_B0))/3; - rvb.iRVBRight = (g_buffer(rvb.MIX_DEST_A1)+g_buffer(rvb.MIX_DEST_B1))/3; - - rvb.iRVBLeft = (rvb.iRVBLeft * rvb.VolLeft) / 0x4000; - rvb.iRVBRight = (rvb.iRVBRight * rvb.VolRight) / 0x4000; - - rvb.CurrAddr++; - if(rvb.CurrAddr>0x3ffff) rvb.CurrAddr=rvb.StartAddr; - - return rvb.iLastRVBLeft+(rvb.iRVBLeft-rvb.iLastRVBLeft)/2; - } - else // -> reverb off - { - rvb.iLastRVBLeft=rvb.iLastRVBRight=rvb.iRVBLeft=rvb.iRVBRight=0; - } - - rvb.CurrAddr++; - if(rvb.CurrAddr>0x3ffff) rvb.CurrAddr=rvb.StartAddr; - } - - return rvb.iLastRVBLeft; - } - else // easy fake reverb: + int l_old = rvb.iRVBLeft; + int r_old = rvb.iRVBRight; + int curr_addr = rvb.CurrAddr; + int space = 0x40000 - rvb.StartAddr; + int l, r, ns; + + for (ns = 0; ns < NSSIZE*2; ) { - const int iRV=*sRVBPlay; // -> simply take the reverb mix buf value - *sRVBPlay++=0; // -> init it after - if(sRVBPlay>=sRVBEnd) sRVBPlay=sRVBStart; // -> and take care about wrap arounds - return iRV; // -> return reverb mix buf val + int IIR_ALPHA = rvb.IIR_ALPHA; + int ACC0, ACC1, FB_A0, FB_A1, FB_B0, FB_B1; + int mix_dest_a0, mix_dest_a1, mix_dest_b0, mix_dest_b1; + + int input_L = sRVBStart[ns] * rvb.IN_COEF_L; + int input_R = sRVBStart[ns+1] * rvb.IN_COEF_R; + + int IIR_INPUT_A0 = ((g_buffer(IIR_SRC_A0) * rvb.IIR_COEF) + input_L) >> 15; + int IIR_INPUT_A1 = ((g_buffer(IIR_SRC_A1) * rvb.IIR_COEF) + input_R) >> 15; + int IIR_INPUT_B0 = ((g_buffer(IIR_SRC_B0) * rvb.IIR_COEF) + input_L) >> 15; + int IIR_INPUT_B1 = ((g_buffer(IIR_SRC_B1) * rvb.IIR_COEF) + input_R) >> 15; + + int iir_dest_a0 = g_buffer(IIR_DEST_A0); + int iir_dest_a1 = g_buffer(IIR_DEST_A1); + int iir_dest_b0 = g_buffer(IIR_DEST_B0); + int iir_dest_b1 = g_buffer(IIR_DEST_B1); + + int IIR_A0 = iir_dest_a0 + ((IIR_INPUT_A0 - iir_dest_a0) * IIR_ALPHA >> 15); + int IIR_A1 = iir_dest_a1 + ((IIR_INPUT_A1 - iir_dest_a1) * IIR_ALPHA >> 15); + int IIR_B0 = iir_dest_b0 + ((IIR_INPUT_B0 - iir_dest_b0) * IIR_ALPHA >> 15); + int IIR_B1 = iir_dest_b1 + ((IIR_INPUT_B1 - iir_dest_b1) * IIR_ALPHA >> 15); + + s_buffer1(IIR_DEST_A0, IIR_A0); + s_buffer1(IIR_DEST_A1, IIR_A1); + s_buffer1(IIR_DEST_B0, IIR_B0); + s_buffer1(IIR_DEST_B1, IIR_B1); + + ACC0 = (g_buffer(ACC_SRC_A0) * rvb.ACC_COEF_A + + g_buffer(ACC_SRC_B0) * rvb.ACC_COEF_B + + g_buffer(ACC_SRC_C0) * rvb.ACC_COEF_C + + g_buffer(ACC_SRC_D0) * rvb.ACC_COEF_D) >> 15; + ACC1 = (g_buffer(ACC_SRC_A1) * rvb.ACC_COEF_A + + g_buffer(ACC_SRC_B1) * rvb.ACC_COEF_B + + g_buffer(ACC_SRC_C1) * rvb.ACC_COEF_C + + g_buffer(ACC_SRC_D1) * rvb.ACC_COEF_D) >> 15; + + FB_A0 = g_buffer(FB_SRC_A0); + FB_A1 = g_buffer(FB_SRC_A1); + FB_B0 = g_buffer(FB_SRC_B0); + FB_B1 = g_buffer(FB_SRC_B1); + + mix_dest_a0 = ACC0 - ((FB_A0 * rvb.FB_ALPHA) >> 15); + mix_dest_a1 = ACC1 - ((FB_A1 * rvb.FB_ALPHA) >> 15); + + mix_dest_b0 = FB_A0 + (((ACC0 - FB_A0) * rvb.FB_ALPHA - FB_B0 * rvb.FB_X) >> 15); + mix_dest_b1 = FB_A1 + (((ACC1 - FB_A1) * rvb.FB_ALPHA - FB_B1 * rvb.FB_X) >> 15); + + s_buffer(MIX_DEST_A0, mix_dest_a0); + s_buffer(MIX_DEST_A1, mix_dest_a1); + s_buffer(MIX_DEST_B0, mix_dest_b0); + s_buffer(MIX_DEST_B1, mix_dest_b1); + + l = (mix_dest_a0 + mix_dest_b0) / 3; + r = (mix_dest_a1 + mix_dest_b1) / 3; + + l = (l * rvb.VolLeft) >> 14; + r = (r * rvb.VolRight) >> 14; + + SSumLR[ns++] += (l + l_old) / 2; + SSumLR[ns++] += (r + r_old) / 2; + SSumLR[ns++] += l; + SSumLR[ns++] += r; + + l_old = l; + r_old = r; + + curr_addr++; + if (curr_addr >= 0x40000) curr_addr = rvb.StartAddr; } + + rvb.iRVBLeft = l; + rvb.iRVBRight = r; + rvb.CurrAddr = curr_addr; } -//////////////////////////////////////////////////////////////////////// +static void prepare_offsets(void) +{ + int space = 0x40000 - rvb.StartAddr; + int t; + #define prep_offs(v) \ + t = rvb.v; \ + while (t >= space) \ + t -= space; \ + rvb.n##v = t + #define prep_offs2(d, v1, v2) \ + t = rvb.v1 - rvb.v2; \ + while (t >= space) \ + t -= space; \ + rvb.n##d = t + + prep_offs(IIR_SRC_A0); + prep_offs(IIR_SRC_A1); + prep_offs(IIR_SRC_B0); + prep_offs(IIR_SRC_B1); + prep_offs(IIR_DEST_A0); + prep_offs(IIR_DEST_A1); + prep_offs(IIR_DEST_B0); + prep_offs(IIR_DEST_B1); + prep_offs(ACC_SRC_A0); + prep_offs(ACC_SRC_A1); + prep_offs(ACC_SRC_B0); + prep_offs(ACC_SRC_B1); + prep_offs(ACC_SRC_C0); + prep_offs(ACC_SRC_C1); + prep_offs(ACC_SRC_D0); + prep_offs(ACC_SRC_D1); + prep_offs(MIX_DEST_A0); + prep_offs(MIX_DEST_A1); + prep_offs(MIX_DEST_B0); + prep_offs(MIX_DEST_B1); + prep_offs2(FB_SRC_A0, MIX_DEST_A0, FB_SRC_A); + prep_offs2(FB_SRC_A1, MIX_DEST_A1, FB_SRC_A); + prep_offs2(FB_SRC_B0, MIX_DEST_B0, FB_SRC_B); + prep_offs2(FB_SRC_B1, MIX_DEST_B1, FB_SRC_B); + +#undef prep_offs +#undef prep_offs2 + rvb.dirty = 0; +} -INLINE int MixREVERBRight(void) +INLINE void REVERBDo(void) { - if(iUseReverb==0) return 0; - else - if(iUseReverb==2) // Neill's reverb: - { - int i=rvb.iLastRVBRight+(rvb.iRVBRight-rvb.iLastRVBRight)/2; - rvb.iLastRVBRight=rvb.iRVBRight; - return i; // -> just return the last right reverb val (little bit scaled by the previous right val) - } - else // easy fake reverb: - { - const int iRV=*sRVBPlay; // -> simply take the reverb mix buf value - *sRVBPlay++=0; // -> init it after - if(sRVBPlay>=sRVBEnd) sRVBPlay=sRVBStart; // -> and take care about wrap arounds - return iRV; // -> return reverb mix buf val - } + if (!rvb.StartAddr) // reverb is off + { + rvb.iRVBLeft = rvb.iRVBRight = 0; + return; + } + + if (spuCtrl & 0x80) // -> reverb on? oki + { + if (rvb.dirty) + prepare_offsets(); + + MixREVERB(); + } + else // -> reverb off + { + // supposedly runs anyway? + rvb.CurrAddr += NSSIZE/2; + while (rvb.CurrAddr >= 0x40000) + rvb.CurrAddr -= 0x40000 - rvb.StartAddr; + } } //////////////////////////////////////////////////////////////////////// @@ -460,3 +429,4 @@ buffer[MIX_DEST_B1] = (FB_ALPHA * ACC1) - FB_A1 * (FB_ALPHA^0x8000) - FB_B1 * FB ----------------------------------------------------------------------------- */ +// vim:shiftwidth=1:expandtab diff --git a/plugins/dfsound/reverb.h b/plugins/dfsound/reverb.h deleted file mode 100644 index f7e9aa27..00000000 --- a/plugins/dfsound/reverb.h +++ /dev/null @@ -1,19 +0,0 @@ -/*************************************************************************** - reverb.h - description - ------------------- - begin : Wed May 15 2002 - copyright : (C) 2002 by Pete Bernert - email : BlackDove@addcom.de - ***************************************************************************/ -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. See also the license.txt file for * - * additional informations. * - * * - ***************************************************************************/ - -void SetREVERB(unsigned short val); - diff --git a/plugins/dfsound/spu.c b/plugins/dfsound/spu.c index e6c5449d..d6cd952b 100644 --- a/plugins/dfsound/spu.c +++ b/plugins/dfsound/spu.c @@ -38,6 +38,16 @@ #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>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;