Add a property to force source spatialization on or off
[openal-soft.git] / Alc / bformatdec.c
blob92a2aecf1e9e71b37fffab5d9603415bd9ab1b12
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 static const ALfloat UnitScale[MAX_AMBI_COEFFS] = {
79 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
80 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
82 static const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = {
83 1.000000000f, /* ACN 0 (W), sqrt(1) */
84 1.732050808f, /* ACN 1 (Y), sqrt(3) */
85 1.732050808f, /* ACN 2 (Z), sqrt(3) */
86 1.732050808f, /* ACN 3 (X), sqrt(3) */
87 2.236067978f, /* ACN 4 (V), sqrt(5) */
88 2.236067978f, /* ACN 5 (T), sqrt(5) */
89 2.236067978f, /* ACN 6 (R), sqrt(5) */
90 2.236067978f, /* ACN 7 (S), sqrt(5) */
91 2.236067978f, /* ACN 8 (U), sqrt(5) */
92 2.645751311f, /* ACN 9 (Q), sqrt(7) */
93 2.645751311f, /* ACN 10 (O), sqrt(7) */
94 2.645751311f, /* ACN 11 (M), sqrt(7) */
95 2.645751311f, /* ACN 12 (K), sqrt(7) */
96 2.645751311f, /* ACN 13 (L), sqrt(7) */
97 2.645751311f, /* ACN 14 (N), sqrt(7) */
98 2.645751311f, /* ACN 15 (P), sqrt(7) */
100 static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
101 1.414213562f, /* ACN 0 (W), sqrt(2) */
102 1.732050808f, /* ACN 1 (Y), sqrt(3) */
103 1.732050808f, /* ACN 2 (Z), sqrt(3) */
104 1.732050808f, /* ACN 3 (X), sqrt(3) */
105 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */
106 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */
107 2.236067978f, /* ACN 6 (R), sqrt(5) */
108 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */
109 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */
110 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */
111 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */
112 2.231093404f, /* ACN 11 (M), sqrt(224/45) */
113 2.645751311f, /* ACN 12 (K), sqrt(7) */
114 2.231093404f, /* ACN 13 (L), sqrt(224/45) */
115 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */
116 2.091650066f, /* ACN 15 (P), sqrt(35/8) */
120 enum FreqBand {
121 FB_HighFreq,
122 FB_LowFreq,
123 FB_Max
126 /* These points are in AL coordinates! */
127 static const ALfloat Ambi3DPoints[8][3] = {
128 { -0.577350269f, 0.577350269f, -0.577350269f },
129 { 0.577350269f, 0.577350269f, -0.577350269f },
130 { -0.577350269f, 0.577350269f, 0.577350269f },
131 { 0.577350269f, 0.577350269f, 0.577350269f },
132 { -0.577350269f, -0.577350269f, -0.577350269f },
133 { 0.577350269f, -0.577350269f, -0.577350269f },
134 { -0.577350269f, -0.577350269f, 0.577350269f },
135 { 0.577350269f, -0.577350269f, 0.577350269f },
137 static const ALfloat Ambi3DDecoder[8][FB_Max][MAX_AMBI_COEFFS] = {
138 { { 0.25f, 0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, 0.125f, 0.125f } },
139 { { 0.25f, -0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, 0.125f, 0.125f } },
140 { { 0.25f, 0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, 0.125f, -0.125f } },
141 { { 0.25f, -0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, 0.125f, -0.125f } },
142 { { 0.25f, 0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, -0.125f, 0.125f } },
143 { { 0.25f, -0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, -0.125f, 0.125f } },
144 { { 0.25f, 0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, -0.125f, -0.125f } },
145 { { 0.25f, -0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, -0.125f, -0.125f } },
149 static RowMixerFunc MixMatrixRow = MixRow_C;
152 static alonce_flag bformatdec_inited = AL_ONCE_FLAG_INIT;
154 static void init_bformatdec(void)
156 MixMatrixRow = SelectRowMixer();
160 /* NOTE: BandSplitter filters are unused with single-band decoding */
161 typedef struct BFormatDec {
162 ALboolean Enabled[MAX_OUTPUT_CHANNELS];
164 union {
165 alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][FB_Max][MAX_AMBI_COEFFS];
166 alignas(16) ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS];
167 } Matrix;
169 BandSplitter XOver[MAX_AMBI_COEFFS];
171 ALfloat (*Samples)[BUFFERSIZE];
172 /* These two alias into Samples */
173 ALfloat (*SamplesHF)[BUFFERSIZE];
174 ALfloat (*SamplesLF)[BUFFERSIZE];
176 alignas(16) ALfloat ChannelMix[BUFFERSIZE];
178 struct {
179 BandSplitter XOver;
180 ALfloat Gains[FB_Max];
181 } UpSampler[4];
183 ALsizei NumChannels;
184 ALboolean DualBand;
185 } BFormatDec;
187 BFormatDec *bformatdec_alloc()
189 alcall_once(&bformatdec_inited, init_bformatdec);
190 return al_calloc(16, sizeof(BFormatDec));
193 void bformatdec_free(BFormatDec *dec)
195 if(dec)
197 al_free(dec->Samples);
198 dec->Samples = NULL;
199 dec->SamplesHF = NULL;
200 dec->SamplesLF = NULL;
202 memset(dec, 0, sizeof(*dec));
203 al_free(dec);
207 void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS])
209 static const ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = {
210 0, 1, 3, 4, 8, 9, 15
212 const ALfloat *coeff_scale = UnitScale;
213 bool periphonic;
214 ALfloat ratio;
215 ALsizei i;
217 al_free(dec->Samples);
218 dec->Samples = NULL;
219 dec->SamplesHF = NULL;
220 dec->SamplesLF = NULL;
222 dec->NumChannels = chancount;
223 dec->Samples = al_calloc(16, dec->NumChannels*2 * sizeof(dec->Samples[0]));
224 dec->SamplesHF = dec->Samples;
225 dec->SamplesLF = dec->SamplesHF + dec->NumChannels;
227 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
228 dec->Enabled[i] = AL_FALSE;
229 for(i = 0;i < conf->NumSpeakers;i++)
230 dec->Enabled[chanmap[i]] = AL_TRUE;
232 if(conf->CoeffScale == ADS_SN3D)
233 coeff_scale = SN3D2N3DScale;
234 else if(conf->CoeffScale == ADS_FuMa)
235 coeff_scale = FuMa2N3DScale;
237 memset(dec->UpSampler, 0, sizeof(dec->UpSampler));
238 ratio = 400.0f / (ALfloat)srate;
239 for(i = 0;i < 4;i++)
240 bandsplit_init(&dec->UpSampler[i].XOver, ratio);
241 if((conf->ChanMask&AMBI_PERIPHONIC_MASK))
243 periphonic = true;
245 dec->UpSampler[0].Gains[FB_HighFreq] = (dec->NumChannels > 9) ? W_SCALE3D_THIRD :
246 (dec->NumChannels > 4) ? W_SCALE3D_SECOND : 1.0f;
247 dec->UpSampler[0].Gains[FB_LowFreq] = 1.0f;
248 for(i = 1;i < 4;i++)
250 dec->UpSampler[i].Gains[FB_HighFreq] = (dec->NumChannels > 9) ? XYZ_SCALE3D_THIRD :
251 (dec->NumChannels > 4) ? XYZ_SCALE3D_SECOND : 1.0f;
252 dec->UpSampler[i].Gains[FB_LowFreq] = 1.0f;
255 else
257 periphonic = false;
259 dec->UpSampler[0].Gains[FB_HighFreq] = (dec->NumChannels > 5) ? W_SCALE2D_THIRD :
260 (dec->NumChannels > 3) ? W_SCALE2D_SECOND : 1.0f;
261 dec->UpSampler[0].Gains[FB_LowFreq] = 1.0f;
262 for(i = 1;i < 3;i++)
264 dec->UpSampler[i].Gains[FB_HighFreq] = (dec->NumChannels > 5) ? XYZ_SCALE2D_THIRD :
265 (dec->NumChannels > 3) ? XYZ_SCALE2D_SECOND : 1.0f;
266 dec->UpSampler[i].Gains[FB_LowFreq] = 1.0f;
268 dec->UpSampler[3].Gains[FB_HighFreq] = 0.0f;
269 dec->UpSampler[3].Gains[FB_LowFreq] = 0.0f;
272 memset(&dec->Matrix, 0, sizeof(dec->Matrix));
273 if(conf->FreqBands == 1)
275 dec->DualBand = AL_FALSE;
276 for(i = 0;i < conf->NumSpeakers;i++)
278 ALsizei chan = chanmap[i];
279 ALfloat gain;
280 ALsizei j, k;
282 if(!periphonic)
284 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
286 ALsizei l = map2DTo3D[j];
287 if(j == 0) gain = conf->HFOrderGain[0];
288 else if(j == 1) gain = conf->HFOrderGain[1];
289 else if(j == 3) gain = conf->HFOrderGain[2];
290 else if(j == 5) gain = conf->HFOrderGain[3];
291 if((conf->ChanMask&(1<<l)))
292 dec->Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] *
293 gain;
296 else
298 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
300 if(j == 0) gain = conf->HFOrderGain[0];
301 else if(j == 1) gain = conf->HFOrderGain[1];
302 else if(j == 4) gain = conf->HFOrderGain[2];
303 else if(j == 9) gain = conf->HFOrderGain[3];
304 if((conf->ChanMask&(1<<j)))
305 dec->Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] *
306 gain;
311 else
313 dec->DualBand = AL_TRUE;
315 ratio = conf->XOverFreq / (ALfloat)srate;
316 for(i = 0;i < MAX_AMBI_COEFFS;i++)
317 bandsplit_init(&dec->XOver[i], ratio);
319 ratio = powf(10.0f, conf->XOverRatio / 40.0f);
320 for(i = 0;i < conf->NumSpeakers;i++)
322 ALsizei chan = chanmap[i];
323 ALfloat gain;
324 ALsizei j, k;
326 if(!periphonic)
328 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
330 ALsizei l = map2DTo3D[j];
331 if(j == 0) gain = conf->HFOrderGain[0] * ratio;
332 else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
333 else if(j == 3) gain = conf->HFOrderGain[2] * ratio;
334 else if(j == 5) gain = conf->HFOrderGain[3] * ratio;
335 if((conf->ChanMask&(1<<l)))
336 dec->Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] /
337 coeff_scale[l] * gain;
339 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
341 ALsizei l = map2DTo3D[j];
342 if(j == 0) gain = conf->LFOrderGain[0] / ratio;
343 else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
344 else if(j == 3) gain = conf->LFOrderGain[2] / ratio;
345 else if(j == 5) gain = conf->LFOrderGain[3] / ratio;
346 if((conf->ChanMask&(1<<l)))
347 dec->Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] /
348 coeff_scale[l] * gain;
351 else
353 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
355 if(j == 0) gain = conf->HFOrderGain[0] * ratio;
356 else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
357 else if(j == 4) gain = conf->HFOrderGain[2] * ratio;
358 else if(j == 9) gain = conf->HFOrderGain[3] * ratio;
359 if((conf->ChanMask&(1<<j)))
360 dec->Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] /
361 coeff_scale[j] * gain;
363 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
365 if(j == 0) gain = conf->LFOrderGain[0] / ratio;
366 else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
367 else if(j == 4) gain = conf->LFOrderGain[2] / ratio;
368 else if(j == 9) gain = conf->LFOrderGain[3] / ratio;
369 if((conf->ChanMask&(1<<j)))
370 dec->Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] /
371 coeff_scale[j] * gain;
379 void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo)
381 ALsizei chan, i;
383 OutBuffer = ASSUME_ALIGNED(OutBuffer, 16);
384 if(dec->DualBand)
386 for(i = 0;i < dec->NumChannels;i++)
387 bandsplit_process(&dec->XOver[i], dec->SamplesHF[i], dec->SamplesLF[i],
388 InSamples[i], SamplesToDo);
390 for(chan = 0;chan < OutChannels;chan++)
392 if(!dec->Enabled[chan])
393 continue;
395 memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat));
396 MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_HighFreq],
397 SAFE_CONST(ALfloatBUFFERSIZE*,dec->SamplesHF), dec->NumChannels, 0,
398 SamplesToDo
400 MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_LowFreq],
401 SAFE_CONST(ALfloatBUFFERSIZE*,dec->SamplesLF), dec->NumChannels, 0,
402 SamplesToDo
405 for(i = 0;i < SamplesToDo;i++)
406 OutBuffer[chan][i] += dec->ChannelMix[i];
409 else
411 for(chan = 0;chan < OutChannels;chan++)
413 if(!dec->Enabled[chan])
414 continue;
416 memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat));
417 MixMatrixRow(dec->ChannelMix, dec->Matrix.Single[chan], InSamples,
418 dec->NumChannels, 0, SamplesToDo);
420 for(i = 0;i < SamplesToDo;i++)
421 OutBuffer[chan][i] += dec->ChannelMix[i];
427 void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo)
429 ALsizei i;
431 /* This up-sampler leverages the differences observed in dual-band second-
432 * and third-order decoder matrices compared to first-order. For the same
433 * output channel configuration, the low-frequency matrix has identical
434 * coefficients in the shared input channels, while the high-frequency
435 * matrix has extra scalars applied to the W channel and X/Y/Z channels.
436 * Mixing the first-order content into the higher-order stream with the
437 * appropriate counter-scales applied to the HF response results in the
438 * subsequent higher-order decode generating the same response as a first-
439 * order decode.
441 for(i = 0;i < InChannels;i++)
443 /* First, split the first-order components into low and high frequency
444 * bands.
446 bandsplit_process(&dec->UpSampler[i].XOver,
447 dec->Samples[FB_HighFreq], dec->Samples[FB_LowFreq],
448 InSamples[i], SamplesToDo
451 /* Now write each band to the output. */
452 MixMatrixRow(OutBuffer[i], dec->UpSampler[i].Gains,
453 SAFE_CONST(ALfloatBUFFERSIZE*,dec->Samples), FB_Max, 0,
454 SamplesToDo
460 #define INVALID_UPSAMPLE_INDEX INT_MAX
462 static ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn)
464 ALsizei i;
465 for(i = 0;i < numchans;i++)
467 if(chans[i].Index == acn)
468 return i;
470 return INVALID_UPSAMPLE_INDEX;
472 #define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a))
474 typedef struct AmbiUpsampler {
475 alignas(16) ALfloat Samples[FB_Max][BUFFERSIZE];
477 BandSplitter XOver[4];
479 ALfloat Gains[4][MAX_OUTPUT_CHANNELS][FB_Max];
480 } AmbiUpsampler;
482 AmbiUpsampler *ambiup_alloc()
484 alcall_once(&bformatdec_inited, init_bformatdec);
485 return al_calloc(16, sizeof(AmbiUpsampler));
488 void ambiup_free(struct AmbiUpsampler *ambiup)
490 al_free(ambiup);
493 void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device)
495 ALfloat ratio;
496 size_t i;
498 ratio = 400.0f / (ALfloat)device->Frequency;
499 for(i = 0;i < 4;i++)
500 bandsplit_init(&ambiup->XOver[i], ratio);
502 memset(ambiup->Gains, 0, sizeof(ambiup->Gains));
503 if(device->Dry.CoeffCount > 0)
505 ALfloat encgains[8][MAX_OUTPUT_CHANNELS];
506 ALsizei j;
507 size_t k;
509 for(i = 0;i < COUNTOF(Ambi3DPoints);i++)
511 ALfloat coeffs[MAX_AMBI_COEFFS] = { 0.0f };
512 CalcDirectionCoeffs(Ambi3DPoints[i], 0.0f, coeffs);
513 ComputePanningGains(device->Dry, coeffs, 1.0f, encgains[i]);
516 /* Combine the matrices that do the in->virt and virt->out conversions
517 * so we get a single in->out conversion. NOTE: the Encoder matrix
518 * (encgains) and output are transposed, so the input channels line up
519 * with the rows and the output channels line up with the columns.
521 for(i = 0;i < 4;i++)
523 for(j = 0;j < device->Dry.NumChannels;j++)
525 ALfloat hfgain=0.0f, lfgain=0.0f;
526 for(k = 0;k < COUNTOF(Ambi3DDecoder);k++)
528 hfgain += Ambi3DDecoder[k][FB_HighFreq][i]*encgains[k][j];
529 lfgain += Ambi3DDecoder[k][FB_LowFreq][i]*encgains[k][j];
531 ambiup->Gains[i][j][FB_HighFreq] = hfgain;
532 ambiup->Gains[i][j][FB_LowFreq] = lfgain;
536 else
538 /* Assumes full 3D/periphonic on the input and output mixes! */
539 ALfloat w_scale = (device->Dry.NumChannels > 9) ? W_SCALE3D_THIRD :
540 (device->Dry.NumChannels > 4) ? W_SCALE3D_SECOND : 1.0f;
541 ALfloat xyz_scale = (device->Dry.NumChannels > 9) ? XYZ_SCALE3D_THIRD :
542 (device->Dry.NumChannels > 4) ? XYZ_SCALE3D_SECOND : 1.0f;
543 for(i = 0;i < 4;i++)
545 ALsizei index = GetChannelForACN(device->Dry, i);
546 if(index != INVALID_UPSAMPLE_INDEX)
548 ALfloat scale = device->Dry.Ambi.Map[index].Scale;
549 ambiup->Gains[i][index][FB_HighFreq] = scale * ((i==0) ? w_scale : xyz_scale);
550 ambiup->Gains[i][index][FB_LowFreq] = scale;
556 void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo)
558 ALsizei i, j;
560 for(i = 0;i < 4;i++)
562 bandsplit_process(&ambiup->XOver[i],
563 ambiup->Samples[FB_HighFreq], ambiup->Samples[FB_LowFreq],
564 InSamples[i], SamplesToDo
567 for(j = 0;j < OutChannels;j++)
568 MixMatrixRow(OutBuffer[j], ambiup->Gains[i][j],
569 SAFE_CONST(ALfloatBUFFERSIZE*,ambiup->Samples), FB_Max, 0,
570 SamplesToDo