add OMAP layer, also preliminary menu, hud and input support
[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 /***************************************************************************\r
9  *                                                                         *\r
10  *   This program is free software; you can redistribute it and/or modify  *\r
11  *   it under the terms of the GNU General Public License as published by  *\r
12  *   the Free Software Foundation; either version 2 of the License, or     *\r
13  *   (at your option) any later version. See also the license.txt file for *\r
14  *   additional informations.                                              *\r
15  *                                                                         *\r
16  ***************************************************************************/\r
17 \r
18 #include "stdafx.h"\r
19 \r
20 #define _IN_REVERB\r
21 \r
22 // will be included from spu.c\r
23 #ifdef _IN_SPU\r
24 \r
25 ////////////////////////////////////////////////////////////////////////\r
26 // globals\r
27 ////////////////////////////////////////////////////////////////////////\r
28 \r
29 // REVERB info and timing vars...\r
30 \r
31 int *          sRVBPlay      = 0;\r
32 int *          sRVBEnd       = 0;\r
33 int *          sRVBStart     = 0;\r
34 int            iReverbOff    = -1;                          // some delay factor for reverb\r
35 int            iReverbRepeat = 0;\r
36 int            iReverbNum    = 1;    \r
37 \r
38 ////////////////////////////////////////////////////////////////////////\r
39 // SET REVERB\r
40 ////////////////////////////////////////////////////////////////////////\r
41 \r
42 void SetREVERB(unsigned short val)\r
43 {\r
44  switch(val)\r
45   {\r
46    case 0x0000: iReverbOff=-1;  break;                                         // off\r
47    case 0x007D: iReverbOff=32;  iReverbNum=2; iReverbRepeat=128;  break;       // ok room\r
48 \r
49    case 0x0033: iReverbOff=32;  iReverbNum=2; iReverbRepeat=64;   break;       // studio small\r
50    case 0x00B1: iReverbOff=48;  iReverbNum=2; iReverbRepeat=96;   break;       // ok studio medium\r
51    case 0x00E3: iReverbOff=64;  iReverbNum=2; iReverbRepeat=128;  break;       // ok studio large ok\r
52 \r
53    case 0x01A5: iReverbOff=128; iReverbNum=4; iReverbRepeat=32;   break;       // ok hall\r
54    case 0x033D: iReverbOff=256; iReverbNum=4; iReverbRepeat=64;   break;       // space echo\r
55    case 0x0001: iReverbOff=184; iReverbNum=3; iReverbRepeat=128;  break;       // echo/delay\r
56    case 0x0017: iReverbOff=128; iReverbNum=2; iReverbRepeat=128;  break;       // half echo\r
57    default:     iReverbOff=32;  iReverbNum=1; iReverbRepeat=0;    break;\r
58   }\r
59 }\r
60 \r
61 ////////////////////////////////////////////////////////////////////////\r
62 // START REVERB\r
63 ////////////////////////////////////////////////////////////////////////\r
64 \r
65 INLINE void StartREVERB(int ch)\r
66 {\r
67  if(s_chan[ch].bReverb && (spuCtrl&0x80))              // reverb possible?\r
68   {\r
69    if(iUseReverb==2) s_chan[ch].bRVBActive=1;\r
70    else\r
71    if(iUseReverb==1 && iReverbOff>0)                   // -> fake reverb used?\r
72     {\r
73      s_chan[ch].bRVBActive=1;                            // -> activate it\r
74      s_chan[ch].iRVBOffset=iReverbOff*45;\r
75      s_chan[ch].iRVBRepeat=iReverbRepeat*45;\r
76      s_chan[ch].iRVBNum   =iReverbNum;\r
77     }\r
78   }\r
79  else s_chan[ch].bRVBActive=0;                         // else -> no reverb\r
80 }\r
81 \r
82 ////////////////////////////////////////////////////////////////////////\r
83 // HELPER FOR NEILL'S REVERB: re-inits our reverb mixing buf\r
84 ////////////////////////////////////////////////////////////////////////\r
85 \r
86 INLINE void InitREVERB(void)\r
87 {\r
88  if(iUseReverb==2)\r
89   {memset(sRVBStart,0,NSSIZE*2*4);}\r
90 }\r
91 \r
92 ////////////////////////////////////////////////////////////////////////\r
93 // STORE REVERB\r
94 ////////////////////////////////////////////////////////////////////////\r
95 \r
96 INLINE void StoreREVERB(int ch,int ns)\r
97 {\r
98  if(iUseReverb==0) return;\r
99  else\r
100  if(iUseReverb==2) // -------------------------------- // Neil's reverb\r
101   {\r
102    const int iRxl=(s_chan[ch].sval*s_chan[ch].iLeftVolume)/0x4000;\r
103    const int iRxr=(s_chan[ch].sval*s_chan[ch].iRightVolume)/0x4000;\r
104 \r
105    ns<<=1;\r
106 \r
107    *(sRVBStart+ns)  +=iRxl;                            // -> we mix all active reverb channels into an extra buffer\r
108    *(sRVBStart+ns+1)+=iRxr;\r
109   }\r
110  else // --------------------------------------------- // Pete's easy fake reverb\r
111   {\r
112    int * pN;int iRn,iRr=0;\r
113 \r
114    // we use the half channel volume (/0x8000) for the first reverb effects, quarter for next and so on\r
115 \r
116    int iRxl=(s_chan[ch].sval*s_chan[ch].iLeftVolume)/0x8000;\r
117    int iRxr=(s_chan[ch].sval*s_chan[ch].iRightVolume)/0x8000;\r
118  \r
119    for(iRn=1;iRn<=s_chan[ch].iRVBNum;iRn++,iRr+=s_chan[ch].iRVBRepeat,iRxl/=2,iRxr/=2)\r
120     {\r
121      pN=sRVBPlay+((s_chan[ch].iRVBOffset+iRr+ns)<<1);\r
122      if(pN>=sRVBEnd) pN=sRVBStart+(pN-sRVBEnd);\r
123 \r
124      (*pN)+=iRxl;\r
125      pN++;\r
126      (*pN)+=iRxr;\r
127     }\r
128   }\r
129 }\r
130 \r
131 ////////////////////////////////////////////////////////////////////////\r
132 \r
133 INLINE int g_buffer(int iOff)                          // get_buffer content helper: takes care about wraps\r
134 {\r
135  short * p=(short *)spuMem;\r
136  iOff=(iOff*4)+rvb.CurrAddr;\r
137  while(iOff>0x3FFFF)       iOff=rvb.StartAddr+(iOff-0x40000);\r
138  while(iOff<rvb.StartAddr) iOff=0x3ffff-(rvb.StartAddr-iOff);\r
139  return (int)*(p+iOff);\r
140 }\r
141 \r
142 ////////////////////////////////////////////////////////////////////////\r
143 \r
144 INLINE void s_buffer(int iOff,int iVal)                // set_buffer content helper: takes care about wraps and clipping\r
145 {\r
146  short * p=(short *)spuMem;\r
147  iOff=(iOff*4)+rvb.CurrAddr;\r
148  while(iOff>0x3FFFF) iOff=rvb.StartAddr+(iOff-0x40000);\r
149  while(iOff<rvb.StartAddr) iOff=0x3ffff-(rvb.StartAddr-iOff);\r
150  if(iVal<-32768L) iVal=-32768L;if(iVal>32767L) iVal=32767L;\r
151  *(p+iOff)=(short)iVal;\r
152 }\r
153 \r
154 ////////////////////////////////////////////////////////////////////////\r
155 \r
156 INLINE void s_buffer1(int iOff,int iVal)                // set_buffer (+1 sample) content helper: takes care about wraps and clipping\r
157 {\r
158  short * p=(short *)spuMem;\r
159  iOff=(iOff*4)+rvb.CurrAddr+1;\r
160  while(iOff>0x3FFFF) iOff=rvb.StartAddr+(iOff-0x40000);\r
161  while(iOff<rvb.StartAddr) iOff=0x3ffff-(rvb.StartAddr-iOff);\r
162  if(iVal<-32768L) iVal=-32768L;if(iVal>32767L) iVal=32767L;\r
163  *(p+iOff)=(short)iVal;\r
164 }\r
165 \r
166 ////////////////////////////////////////////////////////////////////////\r
167 \r
168 INLINE int MixREVERBLeft(int ns)\r
169 {\r
170  if(iUseReverb==0) return 0;\r
171  else\r
172  if(iUseReverb==2)\r
173   {\r
174    static int iCnt=0;                                  // this func will be called with 44.1 khz\r
175 \r
176    if(!rvb.StartAddr)                                  // reverb is off\r
177     {\r
178      rvb.iLastRVBLeft=rvb.iLastRVBRight=rvb.iRVBLeft=rvb.iRVBRight=0;\r
179      return 0;\r
180     }\r
181 \r
182    iCnt++;                                    \r
183 \r
184    if(iCnt&1)                                          // we work on every second left value: downsample to 22 khz\r
185     {\r
186      if(spuCtrl&0x80)                                  // -> reverb on? oki\r
187       {\r
188        int ACC0,ACC1,FB_A0,FB_A1,FB_B0,FB_B1;\r
189 \r
190        const int INPUT_SAMPLE_L=*(sRVBStart+(ns<<1));                         \r
191        const int INPUT_SAMPLE_R=*(sRVBStart+(ns<<1)+1);                     \r
192 \r
193        const int IIR_INPUT_A0 = (g_buffer(rvb.IIR_SRC_A0) * rvb.IIR_COEF)/32768L + (INPUT_SAMPLE_L * rvb.IN_COEF_L)/32768L;\r
194        const int IIR_INPUT_A1 = (g_buffer(rvb.IIR_SRC_A1) * rvb.IIR_COEF)/32768L + (INPUT_SAMPLE_R * rvb.IN_COEF_R)/32768L;\r
195        const int IIR_INPUT_B0 = (g_buffer(rvb.IIR_SRC_B0) * rvb.IIR_COEF)/32768L + (INPUT_SAMPLE_L * rvb.IN_COEF_L)/32768L;\r
196        const int IIR_INPUT_B1 = (g_buffer(rvb.IIR_SRC_B1) * rvb.IIR_COEF)/32768L + (INPUT_SAMPLE_R * rvb.IN_COEF_R)/32768L;\r
197 \r
198        const int IIR_A0 = (IIR_INPUT_A0 * rvb.IIR_ALPHA)/32768L + (g_buffer(rvb.IIR_DEST_A0) * (32768L - rvb.IIR_ALPHA))/32768L;\r
199        const int IIR_A1 = (IIR_INPUT_A1 * rvb.IIR_ALPHA)/32768L + (g_buffer(rvb.IIR_DEST_A1) * (32768L - rvb.IIR_ALPHA))/32768L;\r
200        const int IIR_B0 = (IIR_INPUT_B0 * rvb.IIR_ALPHA)/32768L + (g_buffer(rvb.IIR_DEST_B0) * (32768L - rvb.IIR_ALPHA))/32768L;\r
201        const int IIR_B1 = (IIR_INPUT_B1 * rvb.IIR_ALPHA)/32768L + (g_buffer(rvb.IIR_DEST_B1) * (32768L - rvb.IIR_ALPHA))/32768L;\r
202 \r
203        s_buffer1(rvb.IIR_DEST_A0, IIR_A0);\r
204        s_buffer1(rvb.IIR_DEST_A1, IIR_A1);\r
205        s_buffer1(rvb.IIR_DEST_B0, IIR_B0);\r
206        s_buffer1(rvb.IIR_DEST_B1, IIR_B1);\r
207  \r
208        ACC0 = (g_buffer(rvb.ACC_SRC_A0) * rvb.ACC_COEF_A)/32768L +\r
209               (g_buffer(rvb.ACC_SRC_B0) * rvb.ACC_COEF_B)/32768L +\r
210               (g_buffer(rvb.ACC_SRC_C0) * rvb.ACC_COEF_C)/32768L +\r
211               (g_buffer(rvb.ACC_SRC_D0) * rvb.ACC_COEF_D)/32768L;\r
212        ACC1 = (g_buffer(rvb.ACC_SRC_A1) * rvb.ACC_COEF_A)/32768L +\r
213               (g_buffer(rvb.ACC_SRC_B1) * rvb.ACC_COEF_B)/32768L +\r
214               (g_buffer(rvb.ACC_SRC_C1) * rvb.ACC_COEF_C)/32768L +\r
215               (g_buffer(rvb.ACC_SRC_D1) * rvb.ACC_COEF_D)/32768L;\r
216 \r
217        FB_A0 = g_buffer(rvb.MIX_DEST_A0 - rvb.FB_SRC_A);\r
218        FB_A1 = g_buffer(rvb.MIX_DEST_A1 - rvb.FB_SRC_A);\r
219        FB_B0 = g_buffer(rvb.MIX_DEST_B0 - rvb.FB_SRC_B);\r
220        FB_B1 = g_buffer(rvb.MIX_DEST_B1 - rvb.FB_SRC_B);\r
221 \r
222        s_buffer(rvb.MIX_DEST_A0, ACC0 - (FB_A0 * rvb.FB_ALPHA)/32768L);\r
223        s_buffer(rvb.MIX_DEST_A1, ACC1 - (FB_A1 * rvb.FB_ALPHA)/32768L);\r
224        \r
225        s_buffer(rvb.MIX_DEST_B0, (rvb.FB_ALPHA * ACC0)/32768L - (FB_A0 * (int)(rvb.FB_ALPHA^0xFFFF8000))/32768L - (FB_B0 * rvb.FB_X)/32768L);\r
226        s_buffer(rvb.MIX_DEST_B1, (rvb.FB_ALPHA * ACC1)/32768L - (FB_A1 * (int)(rvb.FB_ALPHA^0xFFFF8000))/32768L - (FB_B1 * rvb.FB_X)/32768L);\r
227  \r
228        rvb.iLastRVBLeft  = rvb.iRVBLeft;\r
229        rvb.iLastRVBRight = rvb.iRVBRight;\r
230 \r
231        rvb.iRVBLeft  = (g_buffer(rvb.MIX_DEST_A0)+g_buffer(rvb.MIX_DEST_B0))/3;\r
232        rvb.iRVBRight = (g_buffer(rvb.MIX_DEST_A1)+g_buffer(rvb.MIX_DEST_B1))/3;\r
233 \r
234        rvb.iRVBLeft  = (rvb.iRVBLeft  * rvb.VolLeft)  / 0x4000;\r
235        rvb.iRVBRight = (rvb.iRVBRight * rvb.VolRight) / 0x4000;\r
236 \r
237        rvb.CurrAddr++;\r
238        if(rvb.CurrAddr>0x3ffff) rvb.CurrAddr=rvb.StartAddr;\r
239 \r
240        return rvb.iLastRVBLeft+(rvb.iRVBLeft-rvb.iLastRVBLeft)/2;\r
241       }\r
242      else                                              // -> reverb off\r
243       {\r
244        rvb.iLastRVBLeft=rvb.iLastRVBRight=rvb.iRVBLeft=rvb.iRVBRight=0;\r
245       }\r
246 \r
247      rvb.CurrAddr++;\r
248      if(rvb.CurrAddr>0x3ffff) rvb.CurrAddr=rvb.StartAddr;\r
249     }\r
250 \r
251    return rvb.iLastRVBLeft;\r
252   }\r
253  else                                                  // easy fake reverb:\r
254   {\r
255    const int iRV=*sRVBPlay;                            // -> simply take the reverb mix buf value\r
256    *sRVBPlay++=0;                                      // -> init it after\r
257    if(sRVBPlay>=sRVBEnd) sRVBPlay=sRVBStart;           // -> and take care about wrap arounds\r
258    return iRV;                                         // -> return reverb mix buf val\r
259   }\r
260 }\r
261 \r
262 ////////////////////////////////////////////////////////////////////////\r
263 \r
264 INLINE int MixREVERBRight(void)\r
265 {\r
266  if(iUseReverb==0) return 0;\r
267  else\r
268  if(iUseReverb==2)                                     // Neill's reverb:\r
269   {\r
270    int i=rvb.iLastRVBRight+(rvb.iRVBRight-rvb.iLastRVBRight)/2;\r
271    rvb.iLastRVBRight=rvb.iRVBRight;\r
272    return i;                                           // -> just return the last right reverb val (little bit scaled by the previous right val)\r
273   }\r
274  else                                                  // easy fake reverb:\r
275   {\r
276    const int iRV=*sRVBPlay;                            // -> simply take the reverb mix buf value\r
277    *sRVBPlay++=0;                                      // -> init it after\r
278    if(sRVBPlay>=sRVBEnd) sRVBPlay=sRVBStart;           // -> and take care about wrap arounds\r
279    return iRV;                                         // -> return reverb mix buf val\r
280   }\r
281 }\r
282 \r
283 ////////////////////////////////////////////////////////////////////////\r
284 \r
285 #endif\r
286 \r
287 /*\r
288 -----------------------------------------------------------------------------\r
289 PSX reverb hardware notes\r
290 by Neill Corlett\r
291 -----------------------------------------------------------------------------\r
292 \r
293 Yadda yadda disclaimer yadda probably not perfect yadda well it's okay anyway\r
294 yadda yadda.\r
295 \r
296 -----------------------------------------------------------------------------\r
297 \r
298 Basics\r
299 ------\r
300 \r
301 - The reverb buffer is 22khz 16-bit mono PCM.\r
302 - It starts at the reverb address given by 1DA2, extends to\r
303   the end of sound RAM, and wraps back to the 1DA2 address.\r
304 \r
305 Setting the address at 1DA2 resets the current reverb work address.\r
306 \r
307 This work address ALWAYS increments every 1/22050 sec., regardless of\r
308 whether reverb is enabled (bit 7 of 1DAA set).\r
309 \r
310 And the contents of the reverb buffer ALWAYS play, scaled by the\r
311 "reverberation depth left/right" volumes (1D84/1D86).\r
312 (which, by the way, appear to be scaled so 3FFF=approx. 1.0, 4000=-1.0)\r
313 \r
314 -----------------------------------------------------------------------------\r
315 \r
316 Register names\r
317 --------------\r
318 \r
319 These are probably not their real names.\r
320 These are probably not even correct names.\r
321 We will use them anyway, because we can.\r
322 \r
323 1DC0: FB_SRC_A       (offset)\r
324 1DC2: FB_SRC_B       (offset)\r
325 1DC4: IIR_ALPHA      (coef.)\r
326 1DC6: ACC_COEF_A     (coef.)\r
327 1DC8: ACC_COEF_B     (coef.)\r
328 1DCA: ACC_COEF_C     (coef.)\r
329 1DCC: ACC_COEF_D     (coef.)\r
330 1DCE: IIR_COEF       (coef.)\r
331 1DD0: FB_ALPHA       (coef.)\r
332 1DD2: FB_X           (coef.)\r
333 1DD4: IIR_DEST_A0    (offset)\r
334 1DD6: IIR_DEST_A1    (offset)\r
335 1DD8: ACC_SRC_A0     (offset)\r
336 1DDA: ACC_SRC_A1     (offset)\r
337 1DDC: ACC_SRC_B0     (offset)\r
338 1DDE: ACC_SRC_B1     (offset)\r
339 1DE0: IIR_SRC_A0     (offset)\r
340 1DE2: IIR_SRC_A1     (offset)\r
341 1DE4: IIR_DEST_B0    (offset)\r
342 1DE6: IIR_DEST_B1    (offset)\r
343 1DE8: ACC_SRC_C0     (offset)\r
344 1DEA: ACC_SRC_C1     (offset)\r
345 1DEC: ACC_SRC_D0     (offset)\r
346 1DEE: ACC_SRC_D1     (offset)\r
347 1DF0: IIR_SRC_B1     (offset)\r
348 1DF2: IIR_SRC_B0     (offset)\r
349 1DF4: MIX_DEST_A0    (offset)\r
350 1DF6: MIX_DEST_A1    (offset)\r
351 1DF8: MIX_DEST_B0    (offset)\r
352 1DFA: MIX_DEST_B1    (offset)\r
353 1DFC: IN_COEF_L      (coef.)\r
354 1DFE: IN_COEF_R      (coef.)\r
355 \r
356 The coefficients are signed fractional values.\r
357 -32768 would be -1.0\r
358  32768 would be  1.0 (if it were possible... the highest is of course 32767)\r
359 \r
360 The offsets are (byte/8) offsets into the reverb buffer.\r
361 i.e. you multiply them by 8, you get byte offsets.\r
362 You can also think of them as (samples/4) offsets.\r
363 They appear to be signed.  They can be negative.\r
364 None of the documented presets make them negative, though.\r
365 \r
366 Yes, 1DF0 and 1DF2 appear to be backwards.  Not a typo.\r
367 \r
368 -----------------------------------------------------------------------------\r
369 \r
370 What it does\r
371 ------------\r
372 \r
373 We take all reverb sources:\r
374 - regular channels that have the reverb bit on\r
375 - cd and external sources, if their reverb bits are on\r
376 and mix them into one stereo 44100hz signal.\r
377 \r
378 Lowpass/downsample that to 22050hz.  The PSX uses a proper bandlimiting\r
379 algorithm here, but I haven't figured out the hysterically exact specifics.\r
380 I use an 8-tap filter with these coefficients, which are nice but probably\r
381 not the real ones:\r
382 \r
383 0.037828187894\r
384 0.157538631280\r
385 0.321159685278\r
386 0.449322115345\r
387 0.449322115345\r
388 0.321159685278\r
389 0.157538631280\r
390 0.037828187894\r
391 \r
392 So we have two input samples (INPUT_SAMPLE_L, INPUT_SAMPLE_R) every 22050hz.\r
393 \r
394 * IN MY EMULATION, I divide these by 2 to make it clip less.\r
395   (and of course the L/R output coefficients are adjusted to compensate)\r
396   The real thing appears to not do this.\r
397 \r
398 At every 22050hz tick:\r
399 - If the reverb bit is enabled (bit 7 of 1DAA), execute the reverb\r
400   steady-state algorithm described below\r
401 - AFTERWARDS, retrieve the "wet out" L and R samples from the reverb buffer\r
402   (This part may not be exactly right and I guessed at the coefs. TODO: check later.)\r
403   L is: 0.333 * (buffer[MIX_DEST_A0] + buffer[MIX_DEST_B0])\r
404   R is: 0.333 * (buffer[MIX_DEST_A1] + buffer[MIX_DEST_B1])\r
405 - Advance the current buffer position by 1 sample\r
406 \r
407 The wet out L and R are then upsampled to 44100hz and played at the\r
408 "reverberation depth left/right" (1D84/1D86) volume, independent of the main\r
409 volume.\r
410 \r
411 -----------------------------------------------------------------------------\r
412 \r
413 Reverb steady-state\r
414 -------------------\r
415 \r
416 The reverb steady-state algorithm is fairly clever, and of course by\r
417 "clever" I mean "batshit insane".\r
418 \r
419 buffer[x] is relative to the current buffer position, not the beginning of\r
420 the buffer.  Note that all buffer offsets must wrap around so they're\r
421 contained within the reverb work area.\r
422 \r
423 Clipping is performed at the end... maybe also sooner, but definitely at\r
424 the end.\r
425 \r
426 IIR_INPUT_A0 = buffer[IIR_SRC_A0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L;\r
427 IIR_INPUT_A1 = buffer[IIR_SRC_A1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R;\r
428 IIR_INPUT_B0 = buffer[IIR_SRC_B0] * IIR_COEF + INPUT_SAMPLE_L * IN_COEF_L;\r
429 IIR_INPUT_B1 = buffer[IIR_SRC_B1] * IIR_COEF + INPUT_SAMPLE_R * IN_COEF_R;\r
430 \r
431 IIR_A0 = IIR_INPUT_A0 * IIR_ALPHA + buffer[IIR_DEST_A0] * (1.0 - IIR_ALPHA);\r
432 IIR_A1 = IIR_INPUT_A1 * IIR_ALPHA + buffer[IIR_DEST_A1] * (1.0 - IIR_ALPHA);\r
433 IIR_B0 = IIR_INPUT_B0 * IIR_ALPHA + buffer[IIR_DEST_B0] * (1.0 - IIR_ALPHA);\r
434 IIR_B1 = IIR_INPUT_B1 * IIR_ALPHA + buffer[IIR_DEST_B1] * (1.0 - IIR_ALPHA);\r
435 \r
436 buffer[IIR_DEST_A0 + 1sample] = IIR_A0;\r
437 buffer[IIR_DEST_A1 + 1sample] = IIR_A1;\r
438 buffer[IIR_DEST_B0 + 1sample] = IIR_B0;\r
439 buffer[IIR_DEST_B1 + 1sample] = IIR_B1;\r
440 \r
441 ACC0 = buffer[ACC_SRC_A0] * ACC_COEF_A +\r
442        buffer[ACC_SRC_B0] * ACC_COEF_B +\r
443        buffer[ACC_SRC_C0] * ACC_COEF_C +\r
444        buffer[ACC_SRC_D0] * ACC_COEF_D;\r
445 ACC1 = buffer[ACC_SRC_A1] * ACC_COEF_A +\r
446        buffer[ACC_SRC_B1] * ACC_COEF_B +\r
447        buffer[ACC_SRC_C1] * ACC_COEF_C +\r
448        buffer[ACC_SRC_D1] * ACC_COEF_D;\r
449 \r
450 FB_A0 = buffer[MIX_DEST_A0 - FB_SRC_A];\r
451 FB_A1 = buffer[MIX_DEST_A1 - FB_SRC_A];\r
452 FB_B0 = buffer[MIX_DEST_B0 - FB_SRC_B];\r
453 FB_B1 = buffer[MIX_DEST_B1 - FB_SRC_B];\r
454 \r
455 buffer[MIX_DEST_A0] = ACC0 - FB_A0 * FB_ALPHA;\r
456 buffer[MIX_DEST_A1] = ACC1 - FB_A1 * FB_ALPHA;\r
457 buffer[MIX_DEST_B0] = (FB_ALPHA * ACC0) - FB_A0 * (FB_ALPHA^0x8000) - FB_B0 * FB_X;\r
458 buffer[MIX_DEST_B1] = (FB_ALPHA * ACC1) - FB_A1 * (FB_ALPHA^0x8000) - FB_B1 * FB_X;\r
459 \r
460 -----------------------------------------------------------------------------\r
461 */\r
462 \r