c736c1ccb628e3ab212ef837f2137f3721ed4a75
[pcsx_rearmed.git] / plugins / dfsound / reverb.c
1 /***************************************************************************\r
2                           reverb.c  -  description\r
3                              -------------------\r
4     begin                : Wed May 15 2002\r
5     copyright            : (C) 2002 by Pete Bernert\r
6     email                : BlackDove@addcom.de\r
7 \r
8  Portions (C) GraÅžvydas "notaz" Ignotas, 2010-2011\r
9  Portions (C) SPU2-X, gigaherz, Pcsx2 Development Team\r
10 \r
11  ***************************************************************************/\r
12 /***************************************************************************\r
13  *                                                                         *\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
19  *                                                                         *\r
20  ***************************************************************************/\r
21 \r
22 #include "stdafx.h"\r
23 #include "spu.h"\r
24 #include <assert.h>\r
25 \r
26 #define _IN_REVERB\r
27 \r
28 // will be included from spu.c\r
29 #ifdef _IN_SPU\r
30 \r
31 ////////////////////////////////////////////////////////////////////////\r
32 // START REVERB\r
33 ////////////////////////////////////////////////////////////////////////\r
34 \r
35 INLINE void StartREVERB(int ch)\r
36 {\r
37  if(spu.s_chan[ch].bReverb && (spu.spuCtrl&0x80))      // reverb possible?\r
38   {\r
39    spu.s_chan[ch].bRVBActive=!!spu_config.iUseReverb;\r
40   }\r
41  else spu.s_chan[ch].bRVBActive=0;                     // else -> no reverb\r
42 }\r
43 \r
44 ////////////////////////////////////////////////////////////////////////\r
45 \r
46 INLINE int rvb_wrap(int ofs, int space)\r
47 {\r
48 #if 0\r
49  int mask = (0x3ffff - ofs) >> 31;\r
50  ofs = ofs - (space & mask);\r
51 #else\r
52  if (ofs >= 0x40000)\r
53   ofs -= space;\r
54 #endif\r
55  //assert(ofs >= 0x40000 - space);\r
56  //assert(ofs < 0x40000);\r
57  return ofs;\r
58 }\r
59 \r
60 INLINE int rvb2ram_offs(int curr, int space, int ofs)\r
61 {\r
62  ofs += curr;\r
63  return rvb_wrap(ofs, space);\r
64 }\r
65 \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
69 \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
74 \r
75 ////////////////////////////////////////////////////////////////////////\r
76 \r
77 static void reverb_interpolate(sample_buf *sb, int curr_addr,\r
78   int out0[2], int out1[2])\r
79 {\r
80  int spos = (curr_addr - 3) & 3;\r
81  int dpos = curr_addr & 3;\r
82  int i;\r
83 \r
84  for (i = 0; i < 2; i++)\r
85   sb->SB_rvb[i][dpos] = sb->SB_rvb[i][4 | dpos] = out0[i];\r
86 \r
87  // mednafen uses some 20 coefs here, we just reuse gauss [0] and [128]\r
88  for (i = 0; i < 2; i++)\r
89  {\r
90   const int *s;\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
94  }\r
95 }\r
96 \r
97 static void MixREVERB(int *SSumLR, int *RVB, int ns_to, int curr_addr,\r
98   int do_filter)\r
99 {\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
114  int ns;\r
115 \r
116 #if P_HAVE_PTHREAD || defined(WANT_THREAD_CODE)\r
117  sb = &spu.sb_thread[MAXCHAN];\r
118 #endif\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
123 \r
124  for (ns = 0; ns < ns_to * 2; )\r
125   {\r
126    int Lin = RVB[ns];\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
133 \r
134    ssat32_to_16(Lin); Lin *= vLIN;\r
135    ssat32_to_16(Rin); Rin *= vRIN;\r
136 \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
146 \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
151 \r
152    preload(SSumLR + ns + 64*2/4 - 4);\r
153 \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
160 \r
161    preload(RVB + ns + 64*2/4 - 4);\r
162 \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
169 \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
172    if (do_filter)\r
173     reverb_interpolate(sb, curr_addr, out0, out1);\r
174 \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
179 \r
180    curr_addr++;\r
181    curr_addr = rvb_wrap(curr_addr, space);\r
182   }\r
183 }\r
184 \r
185 static void MixREVERB_off(int *SSumLR, int ns_to, int curr_addr)\r
186 {\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
191 \r
192  for (ns = 0; ns < ns_to * 2; )\r
193   {\r
194    preload(SSumLR + ns + 64*2/4 - 4);\r
195 \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
199 \r
200    Lout = (Lout * rvb->VolLeft)  >> 15;\r
201    Rout = (Rout * rvb->VolRight) >> 15;\r
202 \r
203    SSumLR[ns++] += Lout;\r
204    SSumLR[ns++] += Rout;\r
205    SSumLR[ns++] += Lout;\r
206    SSumLR[ns++] += Rout;\r
207 \r
208    curr_addr++;\r
209    if (curr_addr >= 0x40000) curr_addr = rvb->StartAddr;\r
210   }\r
211 }\r
212 \r
213 static void REVERBPrep(void)\r
214 {\r
215  REVERBInfo *rvb = spu.rvb;\r
216  int space, t;\r
217 \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
223 \r
224  space = 0x40000 - rvb->StartAddr;\r
225 \r
226  #define prep_offs(v, r) \\r
227    t = spu.regArea[(0x1c0 + r) >> 1] * 4; \\r
228    while (t >= space) \\r
229      t -= space; \\r
230    rvb->v = t\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
234    while (t < 0) \\r
235      t += space; \\r
236    while (t >= space) \\r
237      t -= space; \\r
238    rvb->d = t\r
239 \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
264 \r
265 #undef prep_offs\r
266 #undef prep_offs2\r
267  rvb->dirty = 0;\r
268 }\r
269 \r
270 INLINE void REVERBDo(int *SSumLR, int *RVB, int ns_to, int curr_addr)\r
271 {\r
272  if (spu.spuCtrl & 0x80)                               // -> reverb on? oki\r
273  {\r
274   MixREVERB(SSumLR, RVB, ns_to, curr_addr, 0); //spu.interpolation > 1);\r
275  }\r
276  else if (spu.rvb->VolLeft || spu.rvb->VolRight)\r
277  {\r
278   MixREVERB_off(SSumLR, ns_to, curr_addr);\r
279  }\r
280 }\r
281 \r
282 ////////////////////////////////////////////////////////////////////////\r
283 \r
284 #endif\r
285 \r
286 // vim:shiftwidth=1:expandtab\r