I guess -1 isn't allowed for the output
[openal-soft.git] / Alc / bformatdec.c
blobba6daac53998503dd0e8a94930246ed56e2fae76
2 #include "config.h"
4 #include "bformatdec.h"
5 #include "ambdec.h"
6 #include "mixer_defs.h"
7 #include "alu.h"
9 #include "bool.h"
10 #include "threads.h"
11 #include "almalloc.h"
14 void bandsplit_init(BandSplitter *splitter, ALfloat freq_mult)
16 ALfloat w = freq_mult * F_TAU;
17 ALfloat cw = cosf(w);
18 if(cw > FLT_EPSILON)
19 splitter->coeff = (sinf(w) - 1.0f) / cw;
20 else
21 splitter->coeff = cw * -0.5f;
23 splitter->lp_z1 = 0.0f;
24 splitter->lp_z2 = 0.0f;
25 splitter->hp_z1 = 0.0f;
28 void bandsplit_clear(BandSplitter *splitter)
30 splitter->lp_z1 = 0.0f;
31 splitter->lp_z2 = 0.0f;
32 splitter->hp_z1 = 0.0f;
35 void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout,
36 const ALfloat *input, ALsizei count)
38 ALfloat coeff, d, x;
39 ALfloat z1, z2;
40 ALsizei i;
42 coeff = splitter->coeff*0.5f + 0.5f;
43 z1 = splitter->lp_z1;
44 z2 = splitter->lp_z2;
45 for(i = 0;i < count;i++)
47 x = input[i];
49 d = (x - z1) * coeff;
50 x = z1 + d;
51 z1 = x + d;
53 d = (x - z2) * coeff;
54 x = z2 + d;
55 z2 = x + d;
57 lpout[i] = x;
59 splitter->lp_z1 = z1;
60 splitter->lp_z2 = z2;
62 coeff = splitter->coeff;
63 z1 = splitter->hp_z1;
64 for(i = 0;i < count;i++)
66 x = input[i];
68 d = x - coeff*z1;
69 x = z1 + coeff*d;
70 z1 = d;
72 hpout[i] = x - lpout[i];
74 splitter->hp_z1 = z1;
78 void splitterap_init(SplitterAllpass *splitter, ALfloat freq_mult)
80 ALfloat w = freq_mult * F_TAU;
81 ALfloat cw = cosf(w);
82 if(cw > FLT_EPSILON)
83 splitter->coeff = (sinf(w) - 1.0f) / cw;
84 else
85 splitter->coeff = cw * -0.5f;
87 splitter->z1 = 0.0f;
90 void splitterap_clear(SplitterAllpass *splitter)
92 splitter->z1 = 0.0f;
95 void splitterap_process(SplitterAllpass *splitter, ALfloat *restrict samples, ALsizei count)
97 ALfloat coeff, d, x;
98 ALfloat z1;
99 ALsizei i;
101 coeff = splitter->coeff;
102 z1 = splitter->z1;
103 for(i = 0;i < count;i++)
105 x = samples[i];
107 d = x - coeff*z1;
108 x = z1 + coeff*d;
109 z1 = d;
111 samples[i] = x;
113 splitter->z1 = z1;
117 static const ALfloat UnitScale[MAX_AMBI_COEFFS] = {
118 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
119 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
121 static const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = {
122 1.000000000f, /* ACN 0 (W), sqrt(1) */
123 1.732050808f, /* ACN 1 (Y), sqrt(3) */
124 1.732050808f, /* ACN 2 (Z), sqrt(3) */
125 1.732050808f, /* ACN 3 (X), sqrt(3) */
126 2.236067978f, /* ACN 4 (V), sqrt(5) */
127 2.236067978f, /* ACN 5 (T), sqrt(5) */
128 2.236067978f, /* ACN 6 (R), sqrt(5) */
129 2.236067978f, /* ACN 7 (S), sqrt(5) */
130 2.236067978f, /* ACN 8 (U), sqrt(5) */
131 2.645751311f, /* ACN 9 (Q), sqrt(7) */
132 2.645751311f, /* ACN 10 (O), sqrt(7) */
133 2.645751311f, /* ACN 11 (M), sqrt(7) */
134 2.645751311f, /* ACN 12 (K), sqrt(7) */
135 2.645751311f, /* ACN 13 (L), sqrt(7) */
136 2.645751311f, /* ACN 14 (N), sqrt(7) */
137 2.645751311f, /* ACN 15 (P), sqrt(7) */
139 static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
140 1.414213562f, /* ACN 0 (W), sqrt(2) */
141 1.732050808f, /* ACN 1 (Y), sqrt(3) */
142 1.732050808f, /* ACN 2 (Z), sqrt(3) */
143 1.732050808f, /* ACN 3 (X), sqrt(3) */
144 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */
145 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */
146 2.236067978f, /* ACN 6 (R), sqrt(5) */
147 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */
148 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */
149 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */
150 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */
151 2.231093404f, /* ACN 11 (M), sqrt(224/45) */
152 2.645751311f, /* ACN 12 (K), sqrt(7) */
153 2.231093404f, /* ACN 13 (L), sqrt(224/45) */
154 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */
155 2.091650066f, /* ACN 15 (P), sqrt(35/8) */
159 enum FreqBand {
160 FB_HighFreq,
161 FB_LowFreq,
162 FB_Max
165 /* These points are in AL coordinates! */
166 static const ALfloat Ambi3DPoints[8][3] = {
167 { -0.577350269f, 0.577350269f, -0.577350269f },
168 { 0.577350269f, 0.577350269f, -0.577350269f },
169 { -0.577350269f, 0.577350269f, 0.577350269f },
170 { 0.577350269f, 0.577350269f, 0.577350269f },
171 { -0.577350269f, -0.577350269f, -0.577350269f },
172 { 0.577350269f, -0.577350269f, -0.577350269f },
173 { -0.577350269f, -0.577350269f, 0.577350269f },
174 { 0.577350269f, -0.577350269f, 0.577350269f },
176 static const ALfloat Ambi3DDecoder[8][FB_Max][MAX_AMBI_COEFFS] = {
177 { { 0.25f, 0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, 0.125f, 0.125f } },
178 { { 0.25f, -0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, 0.125f, 0.125f } },
179 { { 0.25f, 0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, 0.125f, -0.125f } },
180 { { 0.25f, -0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, 0.125f, -0.125f } },
181 { { 0.25f, 0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, -0.125f, 0.125f } },
182 { { 0.25f, -0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, -0.125f, 0.125f } },
183 { { 0.25f, 0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, -0.125f, -0.125f } },
184 { { 0.25f, -0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, -0.125f, -0.125f } },
188 static RowMixerFunc MixMatrixRow = MixRow_C;
191 static alonce_flag bformatdec_inited = AL_ONCE_FLAG_INIT;
193 static void init_bformatdec(void)
195 MixMatrixRow = SelectRowMixer();
199 /* NOTE: BandSplitter filters are unused with single-band decoding */
200 typedef struct BFormatDec {
201 ALboolean Enabled[MAX_OUTPUT_CHANNELS];
203 union {
204 alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][FB_Max][MAX_AMBI_COEFFS];
205 alignas(16) ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS];
206 } Matrix;
208 BandSplitter XOver[MAX_AMBI_COEFFS];
210 ALfloat (*Samples)[BUFFERSIZE];
211 /* These two alias into Samples */
212 ALfloat (*SamplesHF)[BUFFERSIZE];
213 ALfloat (*SamplesLF)[BUFFERSIZE];
215 alignas(16) ALfloat ChannelMix[BUFFERSIZE];
217 struct {
218 BandSplitter XOver;
219 ALfloat Gains[FB_Max];
220 } UpSampler[4];
222 ALsizei NumChannels;
223 ALboolean DualBand;
224 } BFormatDec;
226 BFormatDec *bformatdec_alloc()
228 alcall_once(&bformatdec_inited, init_bformatdec);
229 return al_calloc(16, sizeof(BFormatDec));
232 void bformatdec_free(BFormatDec *dec)
234 if(dec)
236 al_free(dec->Samples);
237 dec->Samples = NULL;
238 dec->SamplesHF = NULL;
239 dec->SamplesLF = NULL;
241 memset(dec, 0, sizeof(*dec));
242 al_free(dec);
246 void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS])
248 static const ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = {
249 0, 1, 3, 4, 8, 9, 15
251 const ALfloat *coeff_scale = UnitScale;
252 bool periphonic;
253 ALfloat ratio;
254 ALsizei i;
256 al_free(dec->Samples);
257 dec->Samples = NULL;
258 dec->SamplesHF = NULL;
259 dec->SamplesLF = NULL;
261 dec->NumChannels = chancount;
262 dec->Samples = al_calloc(16, dec->NumChannels*2 * sizeof(dec->Samples[0]));
263 dec->SamplesHF = dec->Samples;
264 dec->SamplesLF = dec->SamplesHF + dec->NumChannels;
266 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
267 dec->Enabled[i] = AL_FALSE;
268 for(i = 0;i < conf->NumSpeakers;i++)
269 dec->Enabled[chanmap[i]] = AL_TRUE;
271 if(conf->CoeffScale == ADS_SN3D)
272 coeff_scale = SN3D2N3DScale;
273 else if(conf->CoeffScale == ADS_FuMa)
274 coeff_scale = FuMa2N3DScale;
276 memset(dec->UpSampler, 0, sizeof(dec->UpSampler));
277 ratio = 400.0f / (ALfloat)srate;
278 for(i = 0;i < 4;i++)
279 bandsplit_init(&dec->UpSampler[i].XOver, ratio);
280 if((conf->ChanMask&AMBI_PERIPHONIC_MASK))
282 periphonic = true;
284 dec->UpSampler[0].Gains[FB_HighFreq] = (dec->NumChannels > 9) ? W_SCALE3D_THIRD :
285 (dec->NumChannels > 4) ? W_SCALE3D_SECOND : 1.0f;
286 dec->UpSampler[0].Gains[FB_LowFreq] = 1.0f;
287 for(i = 1;i < 4;i++)
289 dec->UpSampler[i].Gains[FB_HighFreq] = (dec->NumChannels > 9) ? XYZ_SCALE3D_THIRD :
290 (dec->NumChannels > 4) ? XYZ_SCALE3D_SECOND : 1.0f;
291 dec->UpSampler[i].Gains[FB_LowFreq] = 1.0f;
294 else
296 periphonic = false;
298 dec->UpSampler[0].Gains[FB_HighFreq] = (dec->NumChannels > 5) ? W_SCALE2D_THIRD :
299 (dec->NumChannels > 3) ? W_SCALE2D_SECOND : 1.0f;
300 dec->UpSampler[0].Gains[FB_LowFreq] = 1.0f;
301 for(i = 1;i < 3;i++)
303 dec->UpSampler[i].Gains[FB_HighFreq] = (dec->NumChannels > 5) ? XYZ_SCALE2D_THIRD :
304 (dec->NumChannels > 3) ? XYZ_SCALE2D_SECOND : 1.0f;
305 dec->UpSampler[i].Gains[FB_LowFreq] = 1.0f;
307 dec->UpSampler[3].Gains[FB_HighFreq] = 0.0f;
308 dec->UpSampler[3].Gains[FB_LowFreq] = 0.0f;
311 memset(&dec->Matrix, 0, sizeof(dec->Matrix));
312 if(conf->FreqBands == 1)
314 dec->DualBand = AL_FALSE;
315 for(i = 0;i < conf->NumSpeakers;i++)
317 ALsizei chan = chanmap[i];
318 ALfloat gain;
319 ALsizei j, k;
321 if(!periphonic)
323 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
325 ALsizei l = map2DTo3D[j];
326 if(j == 0) gain = conf->HFOrderGain[0];
327 else if(j == 1) gain = conf->HFOrderGain[1];
328 else if(j == 3) gain = conf->HFOrderGain[2];
329 else if(j == 5) gain = conf->HFOrderGain[3];
330 if((conf->ChanMask&(1<<l)))
331 dec->Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] *
332 gain;
335 else
337 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
339 if(j == 0) gain = conf->HFOrderGain[0];
340 else if(j == 1) gain = conf->HFOrderGain[1];
341 else if(j == 4) gain = conf->HFOrderGain[2];
342 else if(j == 9) gain = conf->HFOrderGain[3];
343 if((conf->ChanMask&(1<<j)))
344 dec->Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] *
345 gain;
350 else
352 dec->DualBand = AL_TRUE;
354 ratio = conf->XOverFreq / (ALfloat)srate;
355 for(i = 0;i < MAX_AMBI_COEFFS;i++)
356 bandsplit_init(&dec->XOver[i], ratio);
358 ratio = powf(10.0f, conf->XOverRatio / 40.0f);
359 for(i = 0;i < conf->NumSpeakers;i++)
361 ALsizei chan = chanmap[i];
362 ALfloat gain;
363 ALsizei j, k;
365 if(!periphonic)
367 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
369 ALsizei l = map2DTo3D[j];
370 if(j == 0) gain = conf->HFOrderGain[0] * ratio;
371 else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
372 else if(j == 3) gain = conf->HFOrderGain[2] * ratio;
373 else if(j == 5) gain = conf->HFOrderGain[3] * ratio;
374 if((conf->ChanMask&(1<<l)))
375 dec->Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] /
376 coeff_scale[l] * gain;
378 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
380 ALsizei l = map2DTo3D[j];
381 if(j == 0) gain = conf->LFOrderGain[0] / ratio;
382 else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
383 else if(j == 3) gain = conf->LFOrderGain[2] / ratio;
384 else if(j == 5) gain = conf->LFOrderGain[3] / ratio;
385 if((conf->ChanMask&(1<<l)))
386 dec->Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] /
387 coeff_scale[l] * gain;
390 else
392 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
394 if(j == 0) gain = conf->HFOrderGain[0] * ratio;
395 else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
396 else if(j == 4) gain = conf->HFOrderGain[2] * ratio;
397 else if(j == 9) gain = conf->HFOrderGain[3] * ratio;
398 if((conf->ChanMask&(1<<j)))
399 dec->Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] /
400 coeff_scale[j] * gain;
402 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
404 if(j == 0) gain = conf->LFOrderGain[0] / ratio;
405 else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
406 else if(j == 4) gain = conf->LFOrderGain[2] / ratio;
407 else if(j == 9) gain = conf->LFOrderGain[3] / ratio;
408 if((conf->ChanMask&(1<<j)))
409 dec->Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] /
410 coeff_scale[j] * gain;
418 void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo)
420 ALsizei chan, i;
422 OutBuffer = ASSUME_ALIGNED(OutBuffer, 16);
423 if(dec->DualBand)
425 for(i = 0;i < dec->NumChannels;i++)
426 bandsplit_process(&dec->XOver[i], dec->SamplesHF[i], dec->SamplesLF[i],
427 InSamples[i], SamplesToDo);
429 for(chan = 0;chan < OutChannels;chan++)
431 if(!dec->Enabled[chan])
432 continue;
434 memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat));
435 MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_HighFreq],
436 SAFE_CONST(ALfloatBUFFERSIZE*,dec->SamplesHF), dec->NumChannels, 0,
437 SamplesToDo
439 MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_LowFreq],
440 SAFE_CONST(ALfloatBUFFERSIZE*,dec->SamplesLF), dec->NumChannels, 0,
441 SamplesToDo
444 for(i = 0;i < SamplesToDo;i++)
445 OutBuffer[chan][i] += dec->ChannelMix[i];
448 else
450 for(chan = 0;chan < OutChannels;chan++)
452 if(!dec->Enabled[chan])
453 continue;
455 memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat));
456 MixMatrixRow(dec->ChannelMix, dec->Matrix.Single[chan], InSamples,
457 dec->NumChannels, 0, SamplesToDo);
459 for(i = 0;i < SamplesToDo;i++)
460 OutBuffer[chan][i] += dec->ChannelMix[i];
466 void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo)
468 ALsizei i;
470 /* This up-sampler leverages the differences observed in dual-band second-
471 * and third-order decoder matrices compared to first-order. For the same
472 * output channel configuration, the low-frequency matrix has identical
473 * coefficients in the shared input channels, while the high-frequency
474 * matrix has extra scalars applied to the W channel and X/Y/Z channels.
475 * Mixing the first-order content into the higher-order stream with the
476 * appropriate counter-scales applied to the HF response results in the
477 * subsequent higher-order decode generating the same response as a first-
478 * order decode.
480 for(i = 0;i < InChannels;i++)
482 /* First, split the first-order components into low and high frequency
483 * bands.
485 bandsplit_process(&dec->UpSampler[i].XOver,
486 dec->Samples[FB_HighFreq], dec->Samples[FB_LowFreq],
487 InSamples[i], SamplesToDo
490 /* Now write each band to the output. */
491 MixMatrixRow(OutBuffer[i], dec->UpSampler[i].Gains,
492 SAFE_CONST(ALfloatBUFFERSIZE*,dec->Samples), FB_Max, 0,
493 SamplesToDo
499 #define INVALID_UPSAMPLE_INDEX INT_MAX
501 static ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn)
503 ALsizei i;
504 for(i = 0;i < numchans;i++)
506 if(chans[i].Index == acn)
507 return i;
509 return INVALID_UPSAMPLE_INDEX;
511 #define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a))
513 typedef struct AmbiUpsampler {
514 alignas(16) ALfloat Samples[FB_Max][BUFFERSIZE];
516 BandSplitter XOver[4];
518 ALfloat Gains[4][MAX_OUTPUT_CHANNELS][FB_Max];
519 } AmbiUpsampler;
521 AmbiUpsampler *ambiup_alloc()
523 alcall_once(&bformatdec_inited, init_bformatdec);
524 return al_calloc(16, sizeof(AmbiUpsampler));
527 void ambiup_free(struct AmbiUpsampler *ambiup)
529 al_free(ambiup);
532 void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device)
534 ALfloat ratio;
535 size_t i;
537 ratio = 400.0f / (ALfloat)device->Frequency;
538 for(i = 0;i < 4;i++)
539 bandsplit_init(&ambiup->XOver[i], ratio);
541 memset(ambiup->Gains, 0, sizeof(ambiup->Gains));
542 if(device->Dry.CoeffCount > 0)
544 ALfloat encgains[8][MAX_OUTPUT_CHANNELS];
545 ALsizei j;
546 size_t k;
548 for(i = 0;i < COUNTOF(Ambi3DPoints);i++)
550 ALfloat coeffs[MAX_AMBI_COEFFS] = { 0.0f };
551 CalcDirectionCoeffs(Ambi3DPoints[i], 0.0f, coeffs);
552 ComputePanningGains(device->Dry, coeffs, 1.0f, encgains[i]);
555 /* Combine the matrices that do the in->virt and virt->out conversions
556 * so we get a single in->out conversion. NOTE: the Encoder matrix
557 * (encgains) and output are transposed, so the input channels line up
558 * with the rows and the output channels line up with the columns.
560 for(i = 0;i < 4;i++)
562 for(j = 0;j < device->Dry.NumChannels;j++)
564 ALfloat hfgain=0.0f, lfgain=0.0f;
565 for(k = 0;k < COUNTOF(Ambi3DDecoder);k++)
567 hfgain += Ambi3DDecoder[k][FB_HighFreq][i]*encgains[k][j];
568 lfgain += Ambi3DDecoder[k][FB_LowFreq][i]*encgains[k][j];
570 ambiup->Gains[i][j][FB_HighFreq] = hfgain;
571 ambiup->Gains[i][j][FB_LowFreq] = lfgain;
575 else
577 /* Assumes full 3D/periphonic on the input and output mixes! */
578 ALfloat w_scale = (device->Dry.NumChannels > 9) ? W_SCALE3D_THIRD :
579 (device->Dry.NumChannels > 4) ? W_SCALE3D_SECOND : 1.0f;
580 ALfloat xyz_scale = (device->Dry.NumChannels > 9) ? XYZ_SCALE3D_THIRD :
581 (device->Dry.NumChannels > 4) ? XYZ_SCALE3D_SECOND : 1.0f;
582 for(i = 0;i < 4;i++)
584 ALsizei index = GetChannelForACN(device->Dry, i);
585 if(index != INVALID_UPSAMPLE_INDEX)
587 ALfloat scale = device->Dry.Ambi.Map[index].Scale;
588 ambiup->Gains[i][index][FB_HighFreq] = scale * ((i==0) ? w_scale : xyz_scale);
589 ambiup->Gains[i][index][FB_LowFreq] = scale;
595 void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo)
597 ALsizei i, j;
599 for(i = 0;i < 4;i++)
601 bandsplit_process(&ambiup->XOver[i],
602 ambiup->Samples[FB_HighFreq], ambiup->Samples[FB_LowFreq],
603 InSamples[i], SamplesToDo
606 for(j = 0;j < OutChannels;j++)
607 MixMatrixRow(OutBuffer[j], ambiup->Gains[i][j],
608 SAFE_CONST(ALfloatBUFFERSIZE*,ambiup->Samples), FB_Max, 0,
609 SamplesToDo