1 /***************************************************************************
\r
2 reverb.c - description
\r
4 begin : Wed May 15 2002
\r
5 copyright : (C) 2002 by Pete Bernert
\r
6 email : BlackDove@addcom.de
\r
8 Portions (C) GraÅžvydas "notaz" Ignotas, 2010-2011
\r
9 Portions (C) SPU2-X, gigaherz, Pcsx2 Development Team
\r
11 ***************************************************************************/
\r
12 /***************************************************************************
\r
14 * This program is free software; you can redistribute it and/or modify *
\r
15 * it under the terms of the GNU General Public License as published by *
\r
16 * the Free Software Foundation; either version 2 of the License, or *
\r
17 * (at your option) any later version. See also the license.txt file for *
\r
18 * additional informations. *
\r
20 ***************************************************************************/
\r
28 // will be included from spu.c
\r
31 ////////////////////////////////////////////////////////////////////////
\r
33 ////////////////////////////////////////////////////////////////////////
\r
35 INLINE void StartREVERB(int ch)
\r
37 if(spu.s_chan[ch].bReverb && (spu.spuCtrl&0x80)) // reverb possible?
\r
39 spu.s_chan[ch].bRVBActive=!!spu_config.iUseReverb;
\r
41 else spu.s_chan[ch].bRVBActive=0; // else -> no reverb
\r
44 ////////////////////////////////////////////////////////////////////////
\r
46 INLINE int rvb_wrap(int ofs, int space)
\r
49 int mask = (0x3ffff - ofs) >> 31;
\r
50 ofs = ofs - (space & mask);
\r
55 //assert(ofs >= 0x40000 - space);
\r
56 //assert(ofs < 0x40000);
\r
60 INLINE int rvb2ram_offs(int curr, int space, int ofs)
\r
63 return rvb_wrap(ofs, space);
\r
66 // get_buffer content helper: takes care about wraps
\r
67 #define g_buffer(var) \
\r
68 ((int)(signed short)LE16TOH(spuMem[rvb2ram_offs(curr_addr, space, var)]))
\r
70 // saturate iVal and store it as var
\r
71 #define s_buffer_w(var, iVal) \
\r
72 ssat32_to_16(iVal); \
\r
73 spuMem[rvb2ram_offs(curr_addr, space, var)] = HTOLE16(iVal)
\r
75 ////////////////////////////////////////////////////////////////////////
\r
77 static void reverb_interpolate(sample_buf *sb, int curr_addr,
\r
78 int out0[2], int out1[2])
\r
80 int spos = (curr_addr - 3) & 3;
\r
81 int dpos = curr_addr & 3;
\r
84 for (i = 0; i < 2; i++)
\r
85 sb->SB_rvb[i][dpos] = sb->SB_rvb[i][4 | dpos] = out0[i];
\r
87 // mednafen uses some 20 coefs here, we just reuse gauss [0] and [128]
\r
88 for (i = 0; i < 2; i++)
\r
91 s = &sb->SB_rvb[i][spos];
\r
92 out0[i] = (s[0] * 0x12c7 + s[1] * 0x59b3 + s[2] * 0x1307) >> 15;
\r
93 out1[i] = (s[0] * 0x019c + s[1] * 0x3def + s[2] * 0x3e4c + s[3] * 0x01a8) >> 15;
\r
97 static void MixREVERB(int *SSumLR, int *RVB, int ns_to, int curr_addr,
\r
100 unsigned short *spuMem = spu.spuMem;
\r
101 const REVERBInfo *rvb = spu.rvb;
\r
102 sample_buf *sb = &spu.sb[MAXCHAN];
\r
103 int space = 0x40000 - rvb->StartAddr;
\r
104 int mlsame_m2o = rvb->mLSAME + space - 1;
\r
105 int mrsame_m2o = rvb->mRSAME + space - 1;
\r
106 int mldiff_m2o = rvb->mLDIFF + space - 1;
\r
107 int mrdiff_m2o = rvb->mRDIFF + space - 1;
\r
108 int vCOMB1 = rvb->vCOMB1 >> 1, vCOMB2 = rvb->vCOMB2 >> 1;
\r
109 int vCOMB3 = rvb->vCOMB3 >> 1, vCOMB4 = rvb->vCOMB4 >> 1;
\r
110 int vAPF1 = rvb->vAPF1 >> 1, vAPF2 = rvb->vAPF2 >> 1;
\r
111 int vLIN = rvb->vLIN >> 1, vRIN = rvb->vRIN >> 1;
\r
112 int vWALL = rvb->vWALL >> 1;
\r
113 int vIIR = rvb->vIIR;
\r
116 #if P_HAVE_PTHREAD || defined(WANT_THREAD_CODE)
\r
117 sb = &spu.sb_thread[MAXCHAN];
\r
119 if (mlsame_m2o >= space) mlsame_m2o -= space;
\r
120 if (mrsame_m2o >= space) mrsame_m2o -= space;
\r
121 if (mldiff_m2o >= space) mldiff_m2o -= space;
\r
122 if (mrdiff_m2o >= space) mrdiff_m2o -= space;
\r
124 for (ns = 0; ns < ns_to * 2; )
\r
127 int Rin = RVB[ns+1];
\r
128 int mlsame_m2 = g_buffer(mlsame_m2o) << (15-1);
\r
129 int mrsame_m2 = g_buffer(mrsame_m2o) << (15-1);
\r
130 int mldiff_m2 = g_buffer(mldiff_m2o) << (15-1);
\r
131 int mrdiff_m2 = g_buffer(mrdiff_m2o) << (15-1);
\r
132 int Lout, Rout, out0[2], out1[2];
\r
134 ssat32_to_16(Lin); Lin *= vLIN;
\r
135 ssat32_to_16(Rin); Rin *= vRIN;
\r
137 // from nocash psx-spx
\r
138 mlsame_m2 += ((Lin + g_buffer(rvb->dLSAME) * vWALL - mlsame_m2) >> 15) * vIIR;
\r
139 mrsame_m2 += ((Rin + g_buffer(rvb->dRSAME) * vWALL - mrsame_m2) >> 15) * vIIR;
\r
140 mldiff_m2 += ((Lin + g_buffer(rvb->dLDIFF) * vWALL - mldiff_m2) >> 15) * vIIR;
\r
141 mrdiff_m2 += ((Rin + g_buffer(rvb->dRDIFF) * vWALL - mrdiff_m2) >> 15) * vIIR;
\r
142 mlsame_m2 >>= (15-1); s_buffer_w(rvb->mLSAME, mlsame_m2);
\r
143 mrsame_m2 >>= (15-1); s_buffer_w(rvb->mRSAME, mrsame_m2);
\r
144 mldiff_m2 >>= (15-1); s_buffer_w(rvb->mLDIFF, mldiff_m2);
\r
145 mrdiff_m2 >>= (15-1); s_buffer_w(rvb->mRDIFF, mrdiff_m2);
\r
147 Lout = vCOMB1 * g_buffer(rvb->mLCOMB1) + vCOMB2 * g_buffer(rvb->mLCOMB2)
\r
148 + vCOMB3 * g_buffer(rvb->mLCOMB3) + vCOMB4 * g_buffer(rvb->mLCOMB4);
\r
149 Rout = vCOMB1 * g_buffer(rvb->mRCOMB1) + vCOMB2 * g_buffer(rvb->mRCOMB2)
\r
150 + vCOMB3 * g_buffer(rvb->mRCOMB3) + vCOMB4 * g_buffer(rvb->mRCOMB4);
\r
152 preload(SSumLR + ns + 64*2/4 - 4);
\r
154 Lout -= vAPF1 * g_buffer(rvb->mLAPF1_dAPF1); Lout >>= (15-1);
\r
155 Rout -= vAPF1 * g_buffer(rvb->mRAPF1_dAPF1); Rout >>= (15-1);
\r
156 s_buffer_w(rvb->mLAPF1, Lout);
\r
157 s_buffer_w(rvb->mRAPF1, Rout);
\r
158 Lout = Lout * vAPF1 + (g_buffer(rvb->mLAPF1_dAPF1) << (15-1));
\r
159 Rout = Rout * vAPF1 + (g_buffer(rvb->mRAPF1_dAPF1) << (15-1));
\r
161 preload(RVB + ns + 64*2/4 - 4);
\r
163 Lout -= vAPF2 * g_buffer(rvb->mLAPF2_dAPF2); Lout >>= (15-1);
\r
164 Rout -= vAPF2 * g_buffer(rvb->mRAPF2_dAPF2); Rout >>= (15-1);
\r
165 s_buffer_w(rvb->mLAPF2, Lout);
\r
166 s_buffer_w(rvb->mRAPF2, Rout);
\r
167 Lout = Lout * vAPF2 + (g_buffer(rvb->mLAPF2_dAPF2) << (15-1));
\r
168 Rout = Rout * vAPF2 + (g_buffer(rvb->mRAPF2_dAPF2) << (15-1));
\r
170 out0[0] = out1[0] = (Lout >> (15-1)) * rvb->VolLeft >> 15;
\r
171 out0[1] = out1[1] = (Rout >> (15-1)) * rvb->VolRight >> 15;
\r
173 reverb_interpolate(sb, curr_addr, out0, out1);
\r
175 SSumLR[ns++] += out0[0];
\r
176 SSumLR[ns++] += out0[1];
\r
177 SSumLR[ns++] += out1[0];
\r
178 SSumLR[ns++] += out1[1];
\r
181 curr_addr = rvb_wrap(curr_addr, space);
\r
185 static void MixREVERB_off(int *SSumLR, int ns_to, int curr_addr)
\r
187 const REVERBInfo *rvb = spu.rvb;
\r
188 unsigned short *spuMem = spu.spuMem;
\r
189 int space = 0x40000 - rvb->StartAddr;
\r
190 int Lout, Rout, ns;
\r
192 for (ns = 0; ns < ns_to * 2; )
\r
194 preload(SSumLR + ns + 64*2/4 - 4);
\r
196 // todo: is this missing COMB and APF1?
\r
197 Lout = g_buffer(rvb->mLAPF2_dAPF2);
\r
198 Rout = g_buffer(rvb->mLAPF2_dAPF2);
\r
200 Lout = (Lout * rvb->VolLeft) >> 15;
\r
201 Rout = (Rout * rvb->VolRight) >> 15;
\r
203 SSumLR[ns++] += Lout;
\r
204 SSumLR[ns++] += Rout;
\r
205 SSumLR[ns++] += Lout;
\r
206 SSumLR[ns++] += Rout;
\r
209 if (curr_addr >= 0x40000) curr_addr = rvb->StartAddr;
\r
213 static void REVERBPrep(void)
\r
215 REVERBInfo *rvb = spu.rvb;
\r
218 t = regAreaGet(H_SPUReverbAddr);
\r
219 if (t == 0xFFFF || t <= 0x200)
\r
220 spu.rvb->StartAddr = spu.rvb->CurrAddr = 0;
\r
221 else if (spu.rvb->StartAddr != (t << 2))
\r
222 spu.rvb->StartAddr = spu.rvb->CurrAddr = t << 2;
\r
224 space = 0x40000 - rvb->StartAddr;
\r
226 #define prep_offs(v, r) \
\r
227 t = spu.regArea[(0x1c0 + r) >> 1] * 4; \
\r
228 while (t >= space) \
\r
231 #define prep_offs2(d, r1, r2) \
\r
232 t = spu.regArea[(0x1c0 + r1) >> 1] * 4; \
\r
233 t -= spu.regArea[(0x1c0 + r2) >> 1] * 4; \
\r
236 while (t >= space) \
\r
240 prep_offs(mLSAME, 0x14);
\r
241 prep_offs(mRSAME, 0x16);
\r
242 prep_offs(mLCOMB1, 0x18);
\r
243 prep_offs(mRCOMB1, 0x1a);
\r
244 prep_offs(mLCOMB2, 0x1c);
\r
245 prep_offs(mRCOMB2, 0x1e);
\r
246 prep_offs(dLSAME, 0x20);
\r
247 prep_offs(dRSAME, 0x22);
\r
248 prep_offs(mLDIFF, 0x24);
\r
249 prep_offs(mRDIFF, 0x26);
\r
250 prep_offs(mLCOMB3, 0x28);
\r
251 prep_offs(mRCOMB3, 0x2a);
\r
252 prep_offs(mLCOMB4, 0x2c);
\r
253 prep_offs(mRCOMB4, 0x2e);
\r
254 prep_offs(dLDIFF, 0x30);
\r
255 prep_offs(dRDIFF, 0x32);
\r
256 prep_offs(mLAPF1, 0x34);
\r
257 prep_offs(mRAPF1, 0x36);
\r
258 prep_offs(mLAPF2, 0x38);
\r
259 prep_offs(mRAPF2, 0x3a);
\r
260 prep_offs2(mLAPF1_dAPF1, 0x34, 0);
\r
261 prep_offs2(mRAPF1_dAPF1, 0x36, 0);
\r
262 prep_offs2(mLAPF2_dAPF2, 0x38, 2);
\r
263 prep_offs2(mRAPF2_dAPF2, 0x3a, 2);
\r
270 INLINE void REVERBDo(int *SSumLR, int *RVB, int ns_to, int curr_addr)
\r
272 if (spu.spuCtrl & 0x80) // -> reverb on? oki
\r
274 MixREVERB(SSumLR, RVB, ns_to, curr_addr, 0); //spu.interpolation > 1);
\r
276 else if (spu.rvb->VolLeft || spu.rvb->VolRight)
\r
278 MixREVERB_off(SSumLR, ns_to, curr_addr);
\r
282 ////////////////////////////////////////////////////////////////////////
\r
286 // vim:shiftwidth=1:expandtab
\r