summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/sound/spureverb.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/sound/spureverb.c')
-rw-r--r--trunk/src/emu/sound/spureverb.c336
1 files changed, 336 insertions, 0 deletions
diff --git a/trunk/src/emu/sound/spureverb.c b/trunk/src/emu/sound/spureverb.c
new file mode 100644
index 00000000000..e4d4a9f79c2
--- /dev/null
+++ b/trunk/src/emu/sound/spureverb.c
@@ -0,0 +1,336 @@
+#include "emu.h"
+#include "spureverb.h"
+
+//
+//
+//
+
+//#define use_intrinsics
+
+#ifdef use_intrinsics
+ #include <mmintrin.h>
+#endif
+
+//
+//
+//
+
+static inline int clamp(int v)
+{
+ if (v<-32768) return -32768;
+ if (v>32767) return 32767;
+ return v;
+}
+
+//
+//
+//
+
+reverb::reverb(const int hz, const int maxdelay)
+ : yp(0),
+ max_delay(maxdelay),
+ sound_hz(hz)
+{
+ for (int c=0; c<2; c++)
+ {
+ for (int f=0; f<4; f++)
+ y[c][f]=new signed short [maxdelay];
+ x[c]=new signed short [maxdelay];
+ ax[c]=new signed short [maxdelay];
+ ay[c]=new signed short [maxdelay];
+ }
+ memset(bx1,0,sizeof(bx1));
+ memset(by1,0,sizeof(by1));
+}
+
+//
+//
+//
+
+reverb::~reverb()
+{
+ for (int c=0; c<2; c++)
+ {
+ for (int f=0; f<4; f++)
+ global_free(y[c][f]);
+ global_free(x[c]);
+ global_free(ax[c]);
+ global_free(ay[c]);
+ }
+}
+
+//
+//
+//
+
+void reverb::bandpass(signed short *sp,
+ const reverb_params *rp,
+ const unsigned int sz)
+{
+ int band_pole=(int)(rp->band_pole*32767),
+ band_gain=(int)(rp->band_gain*32767);
+
+ // Bandpass
+
+ int xp=yp;
+ for (unsigned int i=0; i<(sz>>2); i++, sp+=2)
+ {
+ for (int c=0; c<2; c++)
+ {
+ int x1=(xp-1)&(max_delay-1),
+ bv;
+
+ bv=sp[c]+bx1[c][1]+((band_pole*x[c][x1])>>15);
+ bv=(bv*band_gain)>>15;
+ x[c][xp]=clamp(bv);
+ bx1[c][1]=bx1[c][0];
+ bx1[c][0]=sp[c];
+ }
+
+ xp=(xp+1)&(max_delay-1);
+ }
+}
+
+void reverb::comb_allpass1(signed short *sp,
+ signed short *dp,
+ const comb_param &comb_delay,
+ const int comb_gain,
+ const int allpass_delay,
+ const int allpass_gain,
+ const int *rvol,
+ const unsigned int sz)
+{
+ for (unsigned int i=0; i<(sz>>2); i++, sp+=2, dp+=2)
+ {
+ for (int c=0; c<2; c++)
+ {
+ // Comb
+
+ int v=0;
+
+ for (int f=0; f<4; f++)
+ {
+ int yck=(yp-comb_delay[c][f])&(max_delay-1);
+ y[c][f][yp]=clamp(x[c][yck]+((comb_gain*y[c][f][yck])>>15));
+ v+=y[c][f][yp];
+ }
+
+ v>>=2;
+
+ // Allpass
+
+ if (allpass_delay)
+ {
+ ax[c][yp]=v;
+
+ int ypa=(yp-allpass_delay)&(max_delay-1);
+ v=((allpass_gain*(ay[c][ypa]-x[c][yp]))>>15)+ax[c][ypa];
+ v=clamp(v);
+ ay[c][yp]=v;
+ }
+
+ // Output
+
+ dp[c]=clamp(((v*rvol[c])>>15)+dp[c]+sp[c]);
+ }
+ yp=(yp+1)&(max_delay-1);
+ }
+}
+
+//
+//
+//
+
+void reverb::comb_allpass4(signed short *sp,
+ signed short *dp,
+ const comb_param &comb_delay,
+ const int comb_gain,
+ const int allpass_delay,
+ const int allpass_gain,
+ const int *rvol,
+ const unsigned int sz)
+{
+#ifdef use_intrinsics
+ __m64 cg=_mm_set1_pi16(comb_gain),
+ ag=_mm_set1_pi16(allpass_gain),
+ rv[2];
+ rv[0]=_mm_set1_pi16(rvol[0]);
+ rv[1]=_mm_set1_pi16(rvol[1]);
+
+ for (unsigned int i=0; i<(sz>>4); i++, sp+=2<<2, dp+=2<<2)
+ {
+ __m64 dv[2];
+
+ for (int c=0; c<2; c++)
+ {
+ // Comb
+
+ __m64 v=_mm_setzero_si64();
+
+ for (int f=0; f<4; f++)
+ {
+ int yck=(yp-comb_delay[c][f])&(max_delay-1);
+ __m64 xv=*(__m64 *)(&x[c][yck]),
+ yv=*(__m64 *)(&y[c][f][yck]);
+ yv=_mm_mulhi_pi16(yv,cg);
+ yv=_mm_adds_pi16(yv,yv);
+ yv=_mm_adds_pi16(xv,yv);
+ *((__m64 *)&y[c][f][yp])=yv;
+ yv=_mm_srai_pi16(yv,2);
+ v=_mm_adds_pi16(v,yv);
+ }
+
+ // Allpass
+
+ if (allpass_delay)
+ {
+ *((__m64 *)&ax[c][yp])=v;
+
+ int ypa=(yp-allpass_delay)&(max_delay-1);
+ __m64 ayv=*(__m64 *)&ay[c][ypa],
+ xv=*(__m64 *)&x[c][yp],
+ axv=*(__m64 *)&ax[c][ypa];
+
+ ayv=_mm_subs_pi16(ayv,xv);
+ ayv=_mm_mulhi_pi16(ayv,ag);
+ ayv=_mm_adds_pi16(ayv,ayv);
+ v=_mm_adds_pi16(ayv,axv);
+ *((__m64 *)&ay[c][yp])=v;
+ }
+
+ // Output
+
+ dv[c]=_mm_mulhi_pi16(v,rv[c]);
+ dv[c]=_mm_adds_pi16(dv[c],dv[c]);
+ }
+
+ __m64 dv1=_mm_unpacklo_pi16(dv[0],dv[1]),
+ dv2=_mm_unpackhi_pi16(dv[0],dv[1]),
+ d1=*(__m64 *)&dp[0],
+ d2=*(__m64 *)&dp[4],
+ s1=*(__m64 *)&sp[0],
+ s2=*(__m64 *)&sp[4];
+ d1=_mm_adds_pi16(d1,s1);
+ d2=_mm_adds_pi16(d2,s2);
+ d1=_mm_adds_pi16(d1,dv1);
+ d2=_mm_adds_pi16(d2,dv2);
+ *(__m64 *)&dp[0]=d1;
+ *(__m64 *)&dp[4]=d2;
+
+ yp=(yp+4)&(max_delay-1);
+ }
+
+ _mm_empty();
+#endif
+}
+
+//
+//
+//
+
+void reverb::comb_allpass(signed short *sp,
+ signed short *dp,
+ const reverb_params *rp,
+ const int wetvol_l,
+ const int wetvol_r,
+ const unsigned int _sz)
+{
+ unsigned int sz=_sz;
+ comb_param comb_delay;
+ int comb_gain=(int)(rp->comb_gain*32767),
+ allpass_delay=(int)(((rp->allpass_delay/1000.0f)*sound_hz))&~3,
+ allpass_gain=(int)(rp->allpass_gain*32767),
+ rvol[2]={ (signed short)wetvol_l,
+ (signed short)wetvol_r };
+
+ for (int i=0; i<4; i++)
+ for (int c=0; c<2; c++)
+ comb_delay[c][i]=(int)(((rp->comb_delay[c][i]/1000.0f)*sound_hz))&~3;
+
+ #ifdef use_intrinsics
+
+ if (yp&3)
+ {
+ unsigned int n=min(sz,(unsigned int)(4-(yp&3))<<2);
+ comb_allpass1(sp,dp,
+ (const comb_param &)comb_delay,
+ comb_gain,
+ allpass_delay,
+ allpass_gain,
+ rvol,
+ n);
+ sp+=(n>>1);
+ dp+=(n>>1);
+ sz-=n;
+ }
+
+ if (sz>=16)
+ {
+ unsigned int n=sz&~15;
+ comb_allpass4(sp,dp,
+ (const comb_param &)comb_delay,
+ comb_gain,
+ allpass_delay,
+ allpass_gain,
+ rvol,
+ n);
+ sp+=n>>1;
+ dp+=n>>1;
+ sz-=n;
+ }
+
+ if (sz)
+ {
+ comb_allpass1(sp,dp,
+ (const comb_param &)comb_delay,
+ comb_gain,
+ allpass_delay,
+ allpass_gain,
+ rvol,
+ sz);
+ }
+
+ #else
+ comb_allpass1(sp,dp,
+ (const comb_param &)comb_delay,
+ comb_gain,
+ allpass_delay,
+ allpass_gain,
+ rvol,
+ sz);
+ #endif
+}
+
+//
+//
+//
+
+void reverb::process(signed short *output,
+ signed short *reverb_input,
+ const reverb_params *rp,
+ const int wetvol_l,
+ const int wetvol_r,
+ const unsigned int sz)
+{
+ signed short *sp=(signed short *)reverb_input,
+ *dp=(signed short *)output;
+
+ if (rp->band_gain>0.0f)
+ {
+ // Do reverb processing
+
+ bandpass(sp,rp,sz);
+ comb_allpass(sp,dp,rp,wetvol_l,wetvol_r,sz);
+ } else
+ {
+ // Reverb disabled - just mix the input to the output
+
+ for (unsigned int i=0; i<(sz>>2); i++)
+ {
+ output[0]=clamp(output[0]+reverb_input[0]);
+ output[1]=clamp(output[1]+reverb_input[1]);
+ output+=2;
+ reverb_input+=2;
+ }
+ }
+}