Improve radius behavior with scaling of ambisonic coefficients
[openal-soft.git] / Alc / bformatdec.c
blobe32053c84680f9fc2e473b090305564917023c47
2 #include "config.h"
4 #include "bformatdec.h"
5 #include "ambdec.h"
6 #include "alu.h"
8 #include "threads.h"
9 #include "almalloc.h"
12 typedef struct BandSplitter {
13 ALfloat coeff;
14 ALfloat lp_z1;
15 ALfloat lp_z2;
16 ALfloat hp_z1;
17 } BandSplitter;
19 static void bandsplit_init(BandSplitter *splitter, ALfloat freq_mult)
21 ALfloat w = freq_mult * F_TAU;
22 ALfloat cw = cosf(w);
23 if(cw > FLT_EPSILON)
24 splitter->coeff = (sinf(w) - 1.0f) / cw;
25 else
26 splitter->coeff = cw * -0.5f;
28 splitter->lp_z1 = 0.0f;
29 splitter->lp_z2 = 0.0f;
30 splitter->hp_z1 = 0.0f;
33 static void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout,
34 const ALfloat *input, ALuint count)
36 ALfloat coeff, d, x;
37 ALuint i;
39 coeff = splitter->coeff*0.5f + 0.5f;
40 for(i = 0;i < count;i++)
42 x = input[i];
44 d = (x - splitter->lp_z1) * coeff;
45 x = splitter->lp_z1 + d;
46 splitter->lp_z1 = x + d;
48 d = (x - splitter->lp_z2) * coeff;
49 x = splitter->lp_z2 + d;
50 splitter->lp_z2 = x + d;
52 lpout[i] = x;
55 coeff = splitter->coeff;
56 for(i = 0;i < count;i++)
58 x = input[i];
60 d = x - coeff*splitter->hp_z1;
61 x = splitter->hp_z1 + coeff*d;
62 splitter->hp_z1 = d;
64 hpout[i] = x - lpout[i];
69 static const ALfloat UnitScale[MAX_AMBI_COEFFS] = {
70 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
71 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
73 static const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = {
74 1.000000000f, /* ACN 0 (W), sqrt(1) */
75 1.732050808f, /* ACN 1 (Y), sqrt(3) */
76 1.732050808f, /* ACN 2 (Z), sqrt(3) */
77 1.732050808f, /* ACN 3 (X), sqrt(3) */
78 2.236067978f, /* ACN 4 (V), sqrt(5) */
79 2.236067978f, /* ACN 5 (T), sqrt(5) */
80 2.236067978f, /* ACN 6 (R), sqrt(5) */
81 2.236067978f, /* ACN 7 (S), sqrt(5) */
82 2.236067978f, /* ACN 8 (U), sqrt(5) */
83 2.645751311f, /* ACN 9 (Q), sqrt(7) */
84 2.645751311f, /* ACN 10 (O), sqrt(7) */
85 2.645751311f, /* ACN 11 (M), sqrt(7) */
86 2.645751311f, /* ACN 12 (K), sqrt(7) */
87 2.645751311f, /* ACN 13 (L), sqrt(7) */
88 2.645751311f, /* ACN 14 (N), sqrt(7) */
89 2.645751311f, /* ACN 15 (P), sqrt(7) */
91 static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
92 1.414213562f, /* ACN 0 (W), sqrt(2) */
93 1.732050808f, /* ACN 1 (Y), sqrt(3) */
94 1.732050808f, /* ACN 2 (Z), sqrt(3) */
95 1.732050808f, /* ACN 3 (X), sqrt(3) */
96 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */
97 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */
98 2.236067978f, /* ACN 6 (R), sqrt(5) */
99 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */
100 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */
101 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */
102 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */
103 2.231093404f, /* ACN 11 (M), sqrt(224/45) */
104 2.645751311f, /* ACN 12 (K), sqrt(7) */
105 2.231093404f, /* ACN 13 (L), sqrt(224/45) */
106 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */
107 2.091650066f, /* ACN 15 (P), sqrt(35/8) */
111 static const ALfloat SquareMatrixHF[4][MAX_AMBI_COEFFS] = {
112 { 0.353553f, 0.204094f, 0.0f, 0.204094f },
113 { 0.353553f, -0.204094f, 0.0f, 0.204094f },
114 { 0.353553f, 0.204094f, 0.0f, -0.204094f },
115 { 0.353553f, -0.204094f, 0.0f, -0.204094f },
117 static const ALfloat SquareMatrixLF[4][MAX_AMBI_COEFFS] = {
118 { 0.25f, 0.204094f, 0.0f, 0.204094f },
119 { 0.25f, -0.204094f, 0.0f, 0.204094f },
120 { 0.25f, 0.204094f, 0.0f, -0.204094f },
121 { 0.25f, -0.204094f, 0.0f, -0.204094f },
123 static ALfloat SquareEncoder[4][MAX_AMBI_COEFFS];
125 static const ALfloat CubeMatrixHF[8][MAX_AMBI_COEFFS] = {
126 { 0.25f, 0.14425f, 0.14425f, 0.14425f },
127 { 0.25f, -0.14425f, 0.14425f, 0.14425f },
128 { 0.25f, 0.14425f, 0.14425f, -0.14425f },
129 { 0.25f, -0.14425f, 0.14425f, -0.14425f },
130 { 0.25f, 0.14425f, -0.14425f, 0.14425f },
131 { 0.25f, -0.14425f, -0.14425f, 0.14425f },
132 { 0.25f, 0.14425f, -0.14425f, -0.14425f },
133 { 0.25f, -0.14425f, -0.14425f, -0.14425f },
135 static const ALfloat CubeMatrixLF[8][MAX_AMBI_COEFFS] = {
136 { 0.125f, 0.125f, 0.125f, 0.125f },
137 { 0.125f, -0.125f, 0.125f, 0.125f },
138 { 0.125f, 0.125f, 0.125f, -0.125f },
139 { 0.125f, -0.125f, 0.125f, -0.125f },
140 { 0.125f, 0.125f, -0.125f, 0.125f },
141 { 0.125f, -0.125f, -0.125f, 0.125f },
142 { 0.125f, 0.125f, -0.125f, -0.125f },
143 { 0.125f, -0.125f, -0.125f, -0.125f },
145 static ALfloat CubeEncoder[8][MAX_AMBI_COEFFS];
147 static alonce_flag encoder_inited = AL_ONCE_FLAG_INIT;
149 static void init_encoder(void)
151 ALuint i, j;
153 CalcXYZCoeffs(-0.577350269f, 0.577350269f, -0.577350269f, 0.0f, CubeEncoder[0]);
154 CalcXYZCoeffs( 0.577350269f, 0.577350269f, -0.577350269f, 0.0f, CubeEncoder[1]);
155 CalcXYZCoeffs(-0.577350269f, 0.577350269f, 0.577350269f, 0.0f, CubeEncoder[2]);
156 CalcXYZCoeffs( 0.577350269f, 0.577350269f, 0.577350269f, 0.0f, CubeEncoder[3]);
157 CalcXYZCoeffs(-0.577350269f, -0.577350269f, -0.577350269f, 0.0f, CubeEncoder[4]);
158 CalcXYZCoeffs( 0.577350269f, -0.577350269f, -0.577350269f, 0.0f, CubeEncoder[5]);
159 CalcXYZCoeffs(-0.577350269f, -0.577350269f, 0.577350269f, 0.0f, CubeEncoder[6]);
160 CalcXYZCoeffs( 0.577350269f, -0.577350269f, 0.577350269f, 0.0f, CubeEncoder[7]);
162 CalcXYZCoeffs(-0.707106781f, 0.0f, -0.707106781f, 0.0f, SquareEncoder[0]);
163 CalcXYZCoeffs( 0.707106781f, 0.0f, -0.707106781f, 0.0f, SquareEncoder[1]);
164 CalcXYZCoeffs(-0.707106781f, 0.0f, 0.707106781f, 0.0f, SquareEncoder[2]);
165 CalcXYZCoeffs( 0.707106781f, 0.0f, 0.707106781f, 0.0f, SquareEncoder[3]);
167 for(i = 0;i < 4;i++)
169 /* Remove the skipped height-related coefficients for 2D rendering. */
170 SquareEncoder[i][2] = SquareEncoder[i][3];
171 SquareEncoder[i][3] = SquareEncoder[i][4];
172 SquareEncoder[i][4] = SquareEncoder[i][8];
173 SquareEncoder[i][5] = SquareEncoder[i][9];
174 SquareEncoder[i][6] = SquareEncoder[i][15];
175 for(j = 7;j < MAX_AMBI_COEFFS;j++)
176 SquareEncoder[i][j] = 0.0f;
181 #define MAX_DELAY_LENGTH 128
183 /* NOTE: Low-frequency (LF) fields and BandSplitter filters are unused with
184 * single-band decoding
186 typedef struct BFormatDec {
187 ALboolean Enabled[MAX_OUTPUT_CHANNELS];
189 alignas(16) ALfloat MatrixHF[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS];
190 alignas(16) ALfloat MatrixLF[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS];
192 BandSplitter XOver[MAX_AMBI_COEFFS];
194 ALfloat (*Samples)[BUFFERSIZE];
195 /* These two alias into Samples */
196 ALfloat (*SamplesHF)[BUFFERSIZE];
197 ALfloat (*SamplesLF)[BUFFERSIZE];
199 alignas(16) ALfloat ChannelMix[BUFFERSIZE];
201 struct {
202 alignas(16) ALfloat Buffer[MAX_DELAY_LENGTH];
203 ALuint Length; /* Valid range is [0...MAX_DELAY_LENGTH). */
204 } Delay[MAX_OUTPUT_CHANNELS];
206 struct {
207 BandSplitter XOver[4];
209 const ALfloat (*restrict MatrixHF)[MAX_AMBI_COEFFS];
210 const ALfloat (*restrict MatrixLF)[MAX_AMBI_COEFFS];
211 const ALfloat (*restrict Encoder)[MAX_AMBI_COEFFS];
212 ALuint NumChannels;
213 } UpSampler;
215 ALuint NumChannels;
216 ALboolean DualBand;
217 ALboolean Periphonic;
218 } BFormatDec;
220 BFormatDec *bformatdec_alloc()
222 alcall_once(&encoder_inited, init_encoder);
223 return al_calloc(16, sizeof(BFormatDec));
226 void bformatdec_free(BFormatDec *dec)
228 if(dec)
230 al_free(dec->Samples);
231 dec->Samples = NULL;
232 dec->SamplesHF = NULL;
233 dec->SamplesLF = NULL;
235 memset(dec, 0, sizeof(*dec));
236 al_free(dec);
240 int bformatdec_getOrder(const struct BFormatDec *dec)
242 if(dec->Periphonic)
244 if(dec->NumChannels > 9) return 3;
245 if(dec->NumChannels > 4) return 2;
246 if(dec->NumChannels > 1) return 1;
248 else
250 if(dec->NumChannels > 5) return 3;
251 if(dec->NumChannels > 3) return 2;
252 if(dec->NumChannels > 1) return 1;
254 return 0;
257 void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS], int flags)
259 static const ALuint map2DTo3D[7] = {
260 0, 1, 3, 4, 8, 9, 15
262 const ALfloat *coeff_scale = UnitScale;
263 ALfloat distgain[MAX_OUTPUT_CHANNELS];
264 ALfloat maxdist, ratio;
265 ALuint i;
267 al_free(dec->Samples);
268 dec->Samples = NULL;
269 dec->SamplesHF = NULL;
270 dec->SamplesLF = NULL;
272 dec->NumChannels = chancount;
273 dec->Samples = al_calloc(16, dec->NumChannels*2 * sizeof(dec->Samples[0]));
274 dec->SamplesHF = dec->Samples;
275 dec->SamplesLF = dec->SamplesHF + dec->NumChannels;
277 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
278 dec->Enabled[i] = AL_FALSE;
279 for(i = 0;i < conf->NumSpeakers;i++)
280 dec->Enabled[chanmap[i]] = AL_TRUE;
282 if(conf->CoeffScale == ADS_SN3D)
283 coeff_scale = SN3D2N3DScale;
284 else if(conf->CoeffScale == ADS_FuMa)
285 coeff_scale = FuMa2N3DScale;
287 ratio = 400.0f / (ALfloat)srate;
288 for(i = 0;i < 4;i++)
289 bandsplit_init(&dec->UpSampler.XOver[i], ratio);
290 if((conf->ChanMask & ~0x831b))
292 dec->UpSampler.MatrixHF = CubeMatrixHF;
293 dec->UpSampler.MatrixLF = CubeMatrixLF;
294 dec->UpSampler.Encoder = (const ALfloat(*)[MAX_AMBI_COEFFS])CubeEncoder;
295 dec->UpSampler.NumChannels = 8;
296 dec->Periphonic = AL_TRUE;
298 else
300 dec->UpSampler.MatrixHF = SquareMatrixHF;
301 dec->UpSampler.MatrixLF = SquareMatrixLF;
302 dec->UpSampler.Encoder = (const ALfloat(*)[MAX_AMBI_COEFFS])SquareEncoder;
303 dec->UpSampler.NumChannels = 4;
304 dec->Periphonic = AL_FALSE;
307 maxdist = 0.0f;
308 for(i = 0;i < conf->NumSpeakers;i++)
310 maxdist = maxf(maxdist, conf->Speakers[i].Distance);
311 distgain[i] = 1.0f;
314 memset(dec->Delay, 0, sizeof(dec->Delay));
315 if((flags&BFDF_DistanceComp) && maxdist > 0.0f)
317 for(i = 0;i < conf->NumSpeakers;i++)
319 ALuint chan = chanmap[i];
320 ALfloat delay;
322 /* Distance compensation only delays in steps of the sample rate.
323 * This is a bit less accurate since the delay time falls to the
324 * nearest sample time, but it's far simpler as it doesn't have to
325 * deal with phase offsets. This means at 48khz, for instance, the
326 * distance delay will be in steps of about 7 millimeters.
328 delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC *
329 (ALfloat)srate + 0.5f);
330 if(delay >= (ALfloat)MAX_DELAY_LENGTH)
331 ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n",
332 al_string_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH);
334 dec->Delay[chan].Length = (ALuint)clampf(delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1));
335 distgain[i] = conf->Speakers[i].Distance / maxdist;
336 TRACE("Channel %u \"%s\" distance compensation: %u samples, %f gain\n", chan,
337 al_string_get_cstr(conf->Speakers[i].Name), dec->Delay[chan].Length, distgain[i]
342 if(conf->FreqBands == 1)
344 dec->DualBand = AL_FALSE;
345 ratio = 1.0f;
347 else
349 dec->DualBand = AL_TRUE;
351 ratio = conf->XOverFreq / (ALfloat)srate;
352 for(i = 0;i < MAX_AMBI_COEFFS;i++)
353 bandsplit_init(&dec->XOver[i], ratio);
355 ratio = powf(10.0f, conf->XOverRatio / 40.0f);
356 memset(dec->MatrixLF, 0, sizeof(dec->MatrixLF));
357 for(i = 0;i < conf->NumSpeakers;i++)
359 ALuint chan = chanmap[i];
360 ALuint j, k = 0;
361 ALfloat gain;
363 if(!dec->Periphonic)
365 for(j = 0;j < 7;j++)
367 ALuint l = map2DTo3D[j];
368 if(j == 0) gain = conf->LFOrderGain[0] / ratio;
369 else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
370 else if(j == 3) gain = conf->LFOrderGain[2] / ratio;
371 else if(j == 5) gain = conf->LFOrderGain[3] / ratio;
372 if((conf->ChanMask&(1<<l)))
373 dec->MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[l] *
374 gain * distgain[i];
377 else
379 for(j = 0;j < MAX_AMBI_COEFFS;j++)
381 if(j == 0) gain = conf->LFOrderGain[0] / ratio;
382 else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
383 else if(j == 4) gain = conf->LFOrderGain[2] / ratio;
384 else if(j == 9) gain = conf->LFOrderGain[3] / ratio;
385 if((conf->ChanMask&(1<<j)))
386 dec->MatrixLF[chan][j] = conf->LFMatrix[i][k++] / coeff_scale[j] *
387 gain * distgain[i];
393 memset(dec->MatrixHF, 0, sizeof(dec->MatrixHF));
394 for(i = 0;i < conf->NumSpeakers;i++)
396 ALuint chan = chanmap[i];
397 ALuint j, k = 0;
398 ALfloat gain;
400 if(!dec->Periphonic)
402 for(j = 0;j < 7;j++)
404 ALuint l = map2DTo3D[j];
405 if(j == 0) gain = conf->HFOrderGain[0] * ratio;
406 else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
407 else if(j == 3) gain = conf->HFOrderGain[2] * ratio;
408 else if(j == 5) gain = conf->HFOrderGain[3] * ratio;
409 if((conf->ChanMask&(1<<l)))
410 dec->MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] *
411 gain * distgain[i];
414 else
416 for(j = 0;j < MAX_AMBI_COEFFS;j++)
418 if(j == 0) gain = conf->HFOrderGain[0] * ratio;
419 else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
420 else if(j == 4) gain = conf->HFOrderGain[2] * ratio;
421 else if(j == 9) gain = conf->HFOrderGain[3] * ratio;
422 if((conf->ChanMask&(1<<j)))
423 dec->MatrixHF[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] *
424 gain * distgain[i];
431 static void apply_row(ALfloat *out, const ALfloat *mtx, ALfloat (*restrict in)[BUFFERSIZE], ALuint inchans, ALuint todo)
433 ALuint c, i;
435 for(c = 0;c < inchans;c++)
437 ALfloat gain = mtx[c];
438 if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
439 continue;
440 for(i = 0;i < todo;i++)
441 out[i] += in[c][i] * gain;
445 void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo)
447 ALuint chan, i;
449 if(dec->DualBand)
451 for(i = 0;i < dec->NumChannels;i++)
452 bandsplit_process(&dec->XOver[i], dec->SamplesHF[i], dec->SamplesLF[i],
453 InSamples[i], SamplesToDo);
455 for(chan = 0;chan < OutChannels;chan++)
457 if(!dec->Enabled[chan])
458 continue;
460 memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat));
461 apply_row(dec->ChannelMix, dec->MatrixHF[chan], dec->SamplesHF,
462 dec->NumChannels, SamplesToDo);
463 apply_row(dec->ChannelMix, dec->MatrixLF[chan], dec->SamplesLF,
464 dec->NumChannels, SamplesToDo);
466 if(dec->Delay[chan].Length > 0)
468 const ALuint base = dec->Delay[chan].Length;
469 if(SamplesToDo >= base)
471 for(i = 0;i < base;i++)
472 OutBuffer[chan][i] += dec->Delay[chan].Buffer[i];
473 for(;i < SamplesToDo;i++)
474 OutBuffer[chan][i] += dec->ChannelMix[i-base];
475 memcpy(dec->Delay[chan].Buffer, &dec->ChannelMix[SamplesToDo-base],
476 base*sizeof(ALfloat));
478 else
480 for(i = 0;i < SamplesToDo;i++)
481 OutBuffer[chan][i] += dec->Delay[chan].Buffer[i];
482 memmove(dec->Delay[chan].Buffer, dec->Delay[chan].Buffer+SamplesToDo,
483 base - SamplesToDo);
484 memcpy(dec->Delay[chan].Buffer+base-SamplesToDo, dec->ChannelMix,
485 SamplesToDo*sizeof(ALfloat));
488 else for(i = 0;i < SamplesToDo;i++)
489 OutBuffer[chan][i] += dec->ChannelMix[i];
492 else
494 for(chan = 0;chan < OutChannels;chan++)
496 if(!dec->Enabled[chan])
497 continue;
499 memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat));
500 apply_row(dec->ChannelMix, dec->MatrixHF[chan], InSamples,
501 dec->NumChannels, SamplesToDo);
503 if(dec->Delay[chan].Length > 0)
505 const ALuint base = dec->Delay[chan].Length;
506 if(SamplesToDo >= base)
508 for(i = 0;i < base;i++)
509 OutBuffer[chan][i] += dec->Delay[chan].Buffer[i];
510 for(;i < SamplesToDo;i++)
511 OutBuffer[chan][i] += dec->ChannelMix[i-base];
512 memcpy(dec->Delay[chan].Buffer, &dec->ChannelMix[SamplesToDo-base],
513 base*sizeof(ALfloat));
515 else
517 for(i = 0;i < SamplesToDo;i++)
518 OutBuffer[chan][i] += dec->Delay[chan].Buffer[i];
519 memmove(dec->Delay[chan].Buffer, dec->Delay[chan].Buffer+SamplesToDo,
520 base - SamplesToDo);
521 memcpy(dec->Delay[chan].Buffer+base-SamplesToDo, dec->ChannelMix,
522 SamplesToDo*sizeof(ALfloat));
525 else for(i = 0;i < SamplesToDo;i++)
526 OutBuffer[chan][i] += dec->ChannelMix[i];
532 void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint InChannels, ALuint SamplesToDo)
534 ALuint i, j, k;
536 /* First, split the first-order components into low and high frequency
537 * bands. This assumes SamplesHF and SamplesLF have enough space for first-
538 * order content (to which, this up-sampler is only used with second-order
539 * or higher decoding, so it will).
541 for(i = 0;i < InChannels;i++)
542 bandsplit_process(&dec->UpSampler.XOver[i], dec->SamplesHF[i], dec->SamplesLF[i],
543 InSamples[i], SamplesToDo);
545 /* This up-sampler is very simplistic. It essentially decodes the first-
546 * order content to a square channel array (or cube if height is desired),
547 * then encodes those points onto the higher order soundfield.
549 for(k = 0;k < dec->UpSampler.NumChannels;k++)
551 memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat));
552 apply_row(dec->ChannelMix, dec->UpSampler.MatrixHF[k], dec->SamplesHF,
553 InChannels, SamplesToDo);
554 apply_row(dec->ChannelMix, dec->UpSampler.MatrixLF[k], dec->SamplesLF,
555 InChannels, SamplesToDo);
557 for(j = 0;j < dec->NumChannels;j++)
559 ALfloat gain = dec->UpSampler.Encoder[k][j];
560 if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
561 continue;
562 for(i = 0;i < SamplesToDo;i++)
563 OutBuffer[j][i] += dec->ChannelMix[i] * gain;