frontend: update libpicofe, fix missed callbacks
[pcsx_rearmed.git] / plugins / dfsound / reverb.c
... / ...
CommitLineData
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
35INLINE 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
46INLINE 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
60INLINE 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
77static 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
97static 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
185static 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
213static 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
270INLINE 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