1 /***************************************************************************
2 reverb.c - description
3 -------------------
4 begin : Wed May 15 2002
5 copyright : (C) 2002 by Pete Bernert
6 email : BlackDove@addcom.de
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. See also the license.txt file for *
15 * additional informations. *
16 * *
17 ***************************************************************************/
18
19 //*************************************************************************//
20 // History of changes:
21 //
22 // 2003/03/17 - xodnizel
23 // - Implemented Neill's 44.1Khz-22050Hz downsampling data
24 // I also need to check if the ~4 sample delay doesn't screw any sounds
25 // up by making things too out of phase. It could be fixed easily(elsewhere).
26 //
27 // 2003/01/19 - Pete
28 // - added Neill's reverb (see at the end of file)
29 //
30 // 2002/12/26 - Pete
31 // - adjusted reverb handling
32 //
33 // 2002/08/14 - Pete
34 // - added extra reverb
35 //
36 // 2002/05/15 - Pete
37 // - generic cleanup for the Peops release
38 //
39 //*************************************************************************//
40
41 #define _IN_REVERB
42
43 // will be included from spu.c
44 #ifdef _IN_SPU
45
46 ////////////////////////////////////////////////////////////////////////
47 // globals
48 ////////////////////////////////////////////////////////////////////////
49
50 // REVERB info and timing vars...
51
52 ////////////////////////////////////////////////////////////////////////
53
g_buffer(int iOff)54 static inline s64 g_buffer(int iOff) // get_buffer content helper: takes care about wraps
55 {
56 s16 * p=(s16 *)spuMem;
57 iOff=(iOff*4)+rvb.CurrAddr;
58 while(iOff>0x3FFFF) iOff=rvb.StartAddr+(iOff-0x40000);
59 while(iOff<rvb.StartAddr) iOff=0x3ffff-(rvb.StartAddr-iOff);
60 return (int)(s16)BFLIP16(*(p+iOff));
61 }
62
63 ////////////////////////////////////////////////////////////////////////
64
s_buffer(int iOff,int iVal)65 static inline void s_buffer(int iOff,int iVal) // set_buffer content helper: takes care about wraps and clipping
66 {
67 s16 * p=(s16 *)spuMem;
68 iOff=(iOff*4)+rvb.CurrAddr;
69 while(iOff>0x3FFFF) iOff=rvb.StartAddr+(iOff-0x40000);
70 while(iOff<rvb.StartAddr) iOff=0x3ffff-(rvb.StartAddr-iOff);
71 if(iVal<-32768L) iVal=-32768L;
72 if(iVal>32767L) iVal=32767L;
73 *(p+iOff)=(s16)BFLIP16((s16)iVal);
74 }
75
76 ////////////////////////////////////////////////////////////////////////
77
s_buffer1(int iOff,int iVal)78 static inline void s_buffer1(int iOff,int iVal) // set_buffer (+1 sample) content helper: takes care about wraps and clipping
79 {
80 s16 * p=(s16 *)spuMem;
81 iOff=(iOff*4)+rvb.CurrAddr+1;
82 while(iOff>0x3FFFF) iOff=rvb.StartAddr+(iOff-0x40000);
83 while(iOff<rvb.StartAddr) iOff=0x3ffff-(rvb.StartAddr-iOff);
84 if(iVal<-32768L) iVal=-32768L;
85 if(iVal>32767L) iVal=32767L;
86 *(p+iOff)=(s16)BFLIP16((s16)iVal);
87 }
88
MixREVERBLeftRight(s32 * oleft,s32 * oright,s32 inleft,s32 inright)89 static inline void MixREVERBLeftRight(s32 *oleft, s32 *oright, s32 inleft, s32 inright)
90 {
91 static s32 downbuf[2][8];
92 static s32 upbuf[2][8];
93 static int dbpos=0,ubpos=0;
94 static s32 downcoeffs[8]={ /* Symmetry is sexy. */
95 1283,5344,10895,15243,
96 15243,10895,5344,1283
97 };
98 int x;
99
100 if(!rvb.StartAddr) // reverb is off
101 {
102 rvb.iRVBLeft=rvb.iRVBRight=0;
103 return;
104 }
105
106 //if(inleft<-32767 || inleft>32767) printf("%d\n",inleft);
107 //if(inright<-32767 || inright>32767) printf("%d\n",inright);
108 downbuf[0][dbpos]=inleft;
109 downbuf[1][dbpos]=inright;
110 dbpos=(dbpos+1)&7;
111
112 if(dbpos&1) // we work on every second left value: downsample to 22 khz
113 {
114 if(spuCtrl&0x80) // -> reverb on? oki
115 {
116 int ACC0,ACC1,FB_A0,FB_A1,FB_B0,FB_B1;
117 s32 INPUT_SAMPLE_L=0;
118 s32 INPUT_SAMPLE_R=0;
119
120 for(x=0;x<8;x++)
121 {
122 INPUT_SAMPLE_L+=(downbuf[0][(dbpos+x)&7]*downcoeffs[x])>>8; /* Lose insignificant
123 digits to prevent
124 overflow(check this) */
125 INPUT_SAMPLE_R+=(downbuf[1][(dbpos+x)&7]*downcoeffs[x])>>8;
126 }
127
128 INPUT_SAMPLE_L>>=(16-8);
129 INPUT_SAMPLE_R>>=(16-8);
130 {
131 const s64 IIR_INPUT_A0 = ((g_buffer(rvb.IIR_SRC_A0) * rvb.IIR_COEF)>>15) + ((INPUT_SAMPLE_L * rvb.IN_COEF_L)>>15);
132 const s64 IIR_INPUT_A1 = ((g_buffer(rvb.IIR_SRC_A1) * rvb.IIR_COEF)>>15) + ((INPUT_SAMPLE_R * rvb.IN_COEF_R)>>15);
133 const s64 IIR_INPUT_B0 = ((g_buffer(rvb.IIR_SRC_B0) * rvb.IIR_COEF)>>15) + ((INPUT_SAMPLE_L * rvb.IN_COEF_L)>>15);
134 const s64 IIR_INPUT_B1 = ((g_buffer(rvb.IIR_SRC_B1) * rvb.IIR_COEF)>>15) + ((INPUT_SAMPLE_R * rvb.IN_COEF_R)>>15);
135 const s64 IIR_A0 = ((IIR_INPUT_A0 * rvb.IIR_ALPHA)>>15) + ((g_buffer(rvb.IIR_DEST_A0) * (32768L - rvb.IIR_ALPHA))>>15);
136 const s64 IIR_A1 = ((IIR_INPUT_A1 * rvb.IIR_ALPHA)>>15) + ((g_buffer(rvb.IIR_DEST_A1) * (32768L - rvb.IIR_ALPHA))>>15);
137 const s64 IIR_B0 = ((IIR_INPUT_B0 * rvb.IIR_ALPHA)>>15) + ((g_buffer(rvb.IIR_DEST_B0) * (32768L - rvb.IIR_ALPHA))>>15);
138 const s64 IIR_B1 = ((IIR_INPUT_B1 * rvb.IIR_ALPHA)>>15) + ((g_buffer(rvb.IIR_DEST_B1) * (32768L - rvb.IIR_ALPHA))>>15);
139
140 s_buffer1(rvb.IIR_DEST_A0, IIR_A0);
141 s_buffer1(rvb.IIR_DEST_A1, IIR_A1);
142 s_buffer1(rvb.IIR_DEST_B0, IIR_B0);
143 s_buffer1(rvb.IIR_DEST_B1, IIR_B1);
144
145 ACC0 = ((g_buffer(rvb.ACC_SRC_A0) * rvb.ACC_COEF_A)>>15) +
146 ((g_buffer(rvb.ACC_SRC_B0) * rvb.ACC_COEF_B)>>15) +
147 ((g_buffer(rvb.ACC_SRC_C0) * rvb.ACC_COEF_C)>>15) +
148 ((g_buffer(rvb.ACC_SRC_D0) * rvb.ACC_COEF_D)>>15);
149 ACC1 = ((g_buffer(rvb.ACC_SRC_A1) * rvb.ACC_COEF_A)>>15) +
150 ((g_buffer(rvb.ACC_SRC_B1) * rvb.ACC_COEF_B)>>15) +
151 ((g_buffer(rvb.ACC_SRC_C1) * rvb.ACC_COEF_C)>>15) +
152 ((g_buffer(rvb.ACC_SRC_D1) * rvb.ACC_COEF_D)>>15);
153
154 FB_A0 = g_buffer(rvb.MIX_DEST_A0 - rvb.FB_SRC_A);
155 FB_A1 = g_buffer(rvb.MIX_DEST_A1 - rvb.FB_SRC_A);
156 FB_B0 = g_buffer(rvb.MIX_DEST_B0 - rvb.FB_SRC_B);
157 FB_B1 = g_buffer(rvb.MIX_DEST_B1 - rvb.FB_SRC_B);
158
159 s_buffer(rvb.MIX_DEST_A0, ACC0 - ((FB_A0 * rvb.FB_ALPHA)>>15));
160 s_buffer(rvb.MIX_DEST_A1, ACC1 - ((FB_A1 * rvb.FB_ALPHA)>>15));
161
162 s_buffer(rvb.MIX_DEST_B0, ((rvb.FB_ALPHA * ACC0)>>15) - ((FB_A0 * (int)(rvb.FB_ALPHA^0xFFFF8000))>>15) - ((FB_B0 * rvb.FB_X)>>15));
163 s_buffer(rvb.MIX_DEST_B1, ((rvb.FB_ALPHA * ACC1)>>15) - ((FB_A1 * (int)(rvb.FB_ALPHA^0xFFFF8000))>>15) - ((FB_B1 * rvb.FB_X)>>15));
164
165 rvb.iRVBLeft = (g_buffer(rvb.MIX_DEST_A0)+g_buffer(rvb.MIX_DEST_B0))/3;
166 rvb.iRVBRight = (g_buffer(rvb.MIX_DEST_A1)+g_buffer(rvb.MIX_DEST_B1))/3;
167
168 rvb.iRVBLeft = ((s64)rvb.iRVBLeft * rvb.VolLeft) >> 14;
169 rvb.iRVBRight = ((s64)rvb.iRVBRight * rvb.VolRight) >> 14;
170
171 upbuf[0][ubpos]=rvb.iRVBLeft;
172 upbuf[1][ubpos]=rvb.iRVBRight;
173 ubpos=(ubpos+1)&7;
174 } // Bracket hack(et).
175 }
176 else // -> reverb off
177 {
178 rvb.iRVBLeft=rvb.iRVBRight=0;
179 return;
180 }
181 rvb.CurrAddr++;
182 if(rvb.CurrAddr>0x3ffff) rvb.CurrAddr=rvb.StartAddr;
183 }
184 else
185 {
186 upbuf[0][ubpos]=0;
187 upbuf[1][ubpos]=0;
188 ubpos=(ubpos+1)&7;
189 }
190 {
191 s32 retl=0,retr=0;
192 for(x=0;x<8;x++)
193 {
194 retl+=(upbuf[0][(ubpos+x)&7]*downcoeffs[x])>>8;
195 retr+=(upbuf[1][(ubpos+x)&7]*downcoeffs[x])>>8;
196 }
197 retl>>=(16-8-1); /* -1 To adjust for the null padding. */
198 retr>>=(16-8-1);
199
200 *oleft+=retl;
201 *oright+=retr;
202 }
203 }
204
205 ////////////////////////////////////////////////////////////////////////
206
207 #endif
208
209 /*
210 -----------------------------------------------------------------------------
211 PSX reverb hardware notes
212 by Neill Corlett
213 -----------------------------------------------------------------------------
214
215 Yadda yadda disclaimer yadda probably not perfect yadda well it's okay anyway
216 yadda yadda.
217
218 -----------------------------------------------------------------------------
219
220 Basics
221 ------
222
223 - The reverb buffer is 22khz 16-bit mono PCM.
224 - It starts at the reverb address given by 1DA2, extends to
225 the end of sound RAM, and wraps back to the 1DA2 address.
226
227 Setting the address at 1DA2 resets the current reverb work address.
228
229 This work address ALWAYS increments every 1/22050 sec., regardless of
230 whether reverb is enabled (bit 7 of 1DAA set).
231
232 And the contents of the reverb buffer ALWAYS play, scaled by the
233 "reverberation depth left/right" volumes (1D84/1D86).
234 (which, by the way, appear to be scaled so 3FFF=approx. 1.0, 4000=-1.0)
235
236 -----------------------------------------------------------------------------
237
238 Register names
239 --------------
240
241 These are probably not their real names.
242 These are probably not even correct names.
243 We will use them anyway, because we can.
244
245 1DC0: FB_SRC_A (offset)
246 1DC2: FB_SRC_B (offset)
247 1DC4: IIR_ALPHA (coef.)
248 1DC6: ACC_COEF_A (coef.)
249 1DC8: ACC_COEF_B (coef.)
250 1DCA: ACC_COEF_C (coef.)
251 1DCC: ACC_COEF_D (coef.)
252 1DCE: IIR_COEF (coef.)
253 1DD0: FB_ALPHA (coef.)
254 1DD2: FB_X (coef.)
255 1DD4: IIR_DEST_A0 (offset)
256 1DD6: IIR_DEST_A1 (offset)
257 1DD8: ACC_SRC_A0 (offset)
258 1DDA: ACC_SRC_A1 (offset)
259 1DDC: ACC_SRC_B0 (offset)
260 1DDE: ACC_SRC_B1 (offset)
261 1DE0: IIR_SRC_A0 (offset)
262 1DE2: IIR_SRC_A1 (offset)
263 1DE4: IIR_DEST_B0 (offset)
264 1DE6: IIR_DEST_B1 (offset)
265 1DE8: ACC_SRC_C0 (offset)
266 1DEA: ACC_SRC_C1 (offset)
267 1DEC: ACC_SRC_D0 (offset)
268 1DEE: ACC_SRC_D1 (offset)
269 1DF0: IIR_SRC_B1 (offset)
270 1DF2: IIR_SRC_B0 (offset)
271 1DF4: MIX_DEST_A0 (offset)
272 1DF6: MIX_DEST_A1 (offset)
273 1DF8: MIX_DEST_B0 (offset)
274 1DFA: MIX_DEST_B1 (offset)
275 1DFC: IN_COEF_L (coef.)
276 1DFE: IN_COEF_R (coef.)
277
278 The coefficients are signed fractional values.
279 -32768 would be -1.0
280 32768 would be 1.0 (if it were possible... the highest is of course 32767)
281
282 The offsets are (byte/8) offsets into the reverb buffer.
283 i.e. you multiply them by 8, you get byte offsets.
284 You can also think of them as (samples/4) offsets.
285 They appear to be signed. They can be negative.
286 None of the documented presets make them negative, though.
287
288 Yes, 1DF0 and 1DF2 appear to be backwards. Not a typo.
289
290 -----------------------------------------------------------------------------
291
292 What it does
293 ------------
294
295 We take all reverb sources:
296 - regular channels that have the reverb bit on
297 - cd and external sources, if their reverb bits are on
298 and mix them into one stereo 44100hz signal.
299
300 Lowpass/downsample that to 22050hz. The PSX uses a proper bandlimiting
301 algorithm here, but I haven't figured out the hysterically exact specifics.
302 I use an 8-tap filter with these coefficients, which are nice but probably
303 not the real ones:
304
305 0.037828187894
306 0.157538631280
307 0.321159685278
308 0.449322115345
309 0.449322115345
310 0.321159685278
311 0.157538631280
312 0.037828187894
313
314 So we have two input samples (INPUT_SAMPLE_L, INPUT_SAMPLE_R) every 22050hz.
315
316 * IN MY EMULATION, I divide these by 2 to make it clip less.
317 (and of course the L/R output coefficients are adjusted to compensate)
318 The real thing appears to not do this.
319
320 At every 22050hz tick:
321 - If the reverb bit is enabled (bit 7 of 1DAA), execute the reverb
322 steady-state algorithm described below
323 - AFTERWARDS, retrieve the "wet out" L and R samples from the reverb buffer
324 (This part may not be exactly right and I guessed at the coefs. TODO: check later.)
325 L is: 0.333 * (buffer[MIX_DEST_A0] + buffer[MIX_DEST_B0])
326 R is: 0.333 * (buffer[MIX_DEST_A1] + buffer[MIX_DEST_B1])
327 - Advance the current buffer position by 1 sample
328
329 The wet out L and R are then upsampled to 44100hz and played at the
330 "reverberation depth left/right" (1D84/1D86) volume, independent of the main
331 volume.
332
333 -----------------------------------------------------------------------------
334
335 Reverb steady-state
336 -------------------
337
338 The reverb steady-state algorithm is fairly clever, and of course by
339 "clever" I mean "batshit insane".
340
341 buffer[x] is relative to the current buffer position, not the beginning of
342 the buffer. Note that all buffer offsets must wrap around so they're
343 contained within the reverb work area.
344
345 Clipping is performed at the end... maybe also sooner, but definitely at
346 the end.
347
348 IIR_INPUT_A0 = buffer[IIR_SRC_A0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L;
349 IIR_INPUT_A1 = buffer[IIR_SRC_A1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R;
350 IIR_INPUT_B0 = buffer[IIR_SRC_B0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L;
351 IIR_INPUT_B1 = buffer[IIR_SRC_B1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R;
352
353 IIR_A0 = IIR_INPUT_A0 * IIR_ALPHA + buffer[IIR_DEST_A0] * (1.0 - IIR_ALPHA);
354 IIR_A1 = IIR_INPUT_A1 * IIR_ALPHA + buffer[IIR_DEST_A1] * (1.0 - IIR_ALPHA);
355 IIR_B0 = IIR_INPUT_B0 * IIR_ALPHA + buffer[IIR_DEST_B0] * (1.0 - IIR_ALPHA);
356 IIR_B1 = IIR_INPUT_B1 * IIR_ALPHA + buffer[IIR_DEST_B1] * (1.0 - IIR_ALPHA);
357
358 buffer[IIR_DEST_A0 + 1sample] = IIR_A0;
359 buffer[IIR_DEST_A1 + 1sample] = IIR_A1;
360 buffer[IIR_DEST_B0 + 1sample] = IIR_B0;
361 buffer[IIR_DEST_B1 + 1sample] = IIR_B1;
362
363 ACC0 = buffer[ACC_SRC_A0] * ACC_COEF_A +
364 buffer[ACC_SRC_B0] * ACC_COEF_B +
365 buffer[ACC_SRC_C0] * ACC_COEF_C +
366 buffer[ACC_SRC_D0] * ACC_COEF_D;
367 ACC1 = buffer[ACC_SRC_A1] * ACC_COEF_A +
368 buffer[ACC_SRC_B1] * ACC_COEF_B +
369 buffer[ACC_SRC_C1] * ACC_COEF_C +
370 buffer[ACC_SRC_D1] * ACC_COEF_D;
371
372 FB_A0 = buffer[MIX_DEST_A0 - FB_SRC_A];
373 FB_A1 = buffer[MIX_DEST_A1 - FB_SRC_A];
374 FB_B0 = buffer[MIX_DEST_B0 - FB_SRC_B];
375 FB_B1 = buffer[MIX_DEST_B1 - FB_SRC_B];
376
377 buffer[MIX_DEST_A0] = ACC0 - FB_A0 * FB_ALPHA;
378 buffer[MIX_DEST_A1] = ACC1 - FB_A1 * FB_ALPHA;
379 buffer[MIX_DEST_B0] = (FB_ALPHA * ACC0) - FB_A0 * (FB_ALPHA^0x8000) - FB_B0 * FB_X;
380 buffer[MIX_DEST_B1] = (FB_ALPHA * ACC1) - FB_A1 * (FB_ALPHA^0x8000) - FB_B1 * FB_X;
381
382 -----------------------------------------------------------------------------
383 */
384
385