Separate the delay line feeding from reading
[openal-soft.git] / Alc / bformatdec.c
blob588980832e58b95e99388c42f580a9a995ddd0ff
2 #include "config.h"
4 #include "bformatdec.h"
5 #include "ambdec.h"
6 #include "filters/splitter.h"
7 #include "alu.h"
9 #include "bool.h"
10 #include "threads.h"
11 #include "almalloc.h"
14 /* NOTE: These are scale factors as applied to Ambisonics content. Decoder
15 * coefficients should be divided by these values to get proper N3D scalings.
17 const ALfloat N3D2N3DScale[MAX_AMBI_COEFFS] = {
18 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
19 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
21 const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = {
22 1.000000000f, /* ACN 0 (W), sqrt(1) */
23 1.732050808f, /* ACN 1 (Y), sqrt(3) */
24 1.732050808f, /* ACN 2 (Z), sqrt(3) */
25 1.732050808f, /* ACN 3 (X), sqrt(3) */
26 2.236067978f, /* ACN 4 (V), sqrt(5) */
27 2.236067978f, /* ACN 5 (T), sqrt(5) */
28 2.236067978f, /* ACN 6 (R), sqrt(5) */
29 2.236067978f, /* ACN 7 (S), sqrt(5) */
30 2.236067978f, /* ACN 8 (U), sqrt(5) */
31 2.645751311f, /* ACN 9 (Q), sqrt(7) */
32 2.645751311f, /* ACN 10 (O), sqrt(7) */
33 2.645751311f, /* ACN 11 (M), sqrt(7) */
34 2.645751311f, /* ACN 12 (K), sqrt(7) */
35 2.645751311f, /* ACN 13 (L), sqrt(7) */
36 2.645751311f, /* ACN 14 (N), sqrt(7) */
37 2.645751311f, /* ACN 15 (P), sqrt(7) */
39 const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
40 1.414213562f, /* ACN 0 (W), sqrt(2) */
41 1.732050808f, /* ACN 1 (Y), sqrt(3) */
42 1.732050808f, /* ACN 2 (Z), sqrt(3) */
43 1.732050808f, /* ACN 3 (X), sqrt(3) */
44 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */
45 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */
46 2.236067978f, /* ACN 6 (R), sqrt(5) */
47 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */
48 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */
49 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */
50 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */
51 2.231093404f, /* ACN 11 (M), sqrt(224/45) */
52 2.645751311f, /* ACN 12 (K), sqrt(7) */
53 2.231093404f, /* ACN 13 (L), sqrt(224/45) */
54 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */
55 2.091650066f, /* ACN 15 (P), sqrt(35/8) */
59 #define HF_BAND 0
60 #define LF_BAND 1
61 #define NUM_BANDS 2
63 /* These points are in AL coordinates! */
64 static const ALfloat Ambi3DPoints[8][3] = {
65 { -0.577350269f, 0.577350269f, -0.577350269f },
66 { 0.577350269f, 0.577350269f, -0.577350269f },
67 { -0.577350269f, 0.577350269f, 0.577350269f },
68 { 0.577350269f, 0.577350269f, 0.577350269f },
69 { -0.577350269f, -0.577350269f, -0.577350269f },
70 { 0.577350269f, -0.577350269f, -0.577350269f },
71 { -0.577350269f, -0.577350269f, 0.577350269f },
72 { 0.577350269f, -0.577350269f, 0.577350269f },
74 static const ALfloat Ambi3DDecoder[8][MAX_AMBI_COEFFS] = {
75 { 0.125f, 0.125f, 0.125f, 0.125f },
76 { 0.125f, -0.125f, 0.125f, 0.125f },
77 { 0.125f, 0.125f, 0.125f, -0.125f },
78 { 0.125f, -0.125f, 0.125f, -0.125f },
79 { 0.125f, 0.125f, -0.125f, 0.125f },
80 { 0.125f, -0.125f, -0.125f, 0.125f },
81 { 0.125f, 0.125f, -0.125f, -0.125f },
82 { 0.125f, -0.125f, -0.125f, -0.125f },
84 static const ALfloat Ambi3DDecoderHFScale[MAX_AMBI_COEFFS] = {
85 2.0f,
86 1.15470054f, 1.15470054f, 1.15470054f
90 /* NOTE: BandSplitter filters are unused with single-band decoding */
91 typedef struct BFormatDec {
92 ALuint Enabled; /* Bitfield of enabled channels. */
94 union {
95 alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][NUM_BANDS][MAX_AMBI_COEFFS];
96 alignas(16) ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS];
97 } Matrix;
99 BandSplitter XOver[MAX_AMBI_COEFFS];
101 ALfloat (*Samples)[BUFFERSIZE];
102 /* These two alias into Samples */
103 ALfloat (*SamplesHF)[BUFFERSIZE];
104 ALfloat (*SamplesLF)[BUFFERSIZE];
106 alignas(16) ALfloat ChannelMix[BUFFERSIZE];
108 struct {
109 BandSplitter XOver;
110 ALfloat Gains[NUM_BANDS];
111 } UpSampler[4];
113 ALsizei NumChannels;
114 ALboolean DualBand;
115 } BFormatDec;
117 BFormatDec *bformatdec_alloc()
119 return al_calloc(16, sizeof(BFormatDec));
122 void bformatdec_free(BFormatDec **dec)
124 if(dec && *dec)
126 al_free((*dec)->Samples);
127 (*dec)->Samples = NULL;
128 (*dec)->SamplesHF = NULL;
129 (*dec)->SamplesLF = NULL;
131 al_free(*dec);
132 *dec = NULL;
136 void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS])
138 static const ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = {
139 0, 1, 3, 4, 8, 9, 15
141 const ALfloat *coeff_scale = N3D2N3DScale;
142 bool periphonic;
143 ALfloat ratio;
144 ALsizei i;
146 al_free(dec->Samples);
147 dec->Samples = NULL;
148 dec->SamplesHF = NULL;
149 dec->SamplesLF = NULL;
151 dec->NumChannels = chancount;
152 dec->Samples = al_calloc(16, dec->NumChannels*2 * sizeof(dec->Samples[0]));
153 dec->SamplesHF = dec->Samples;
154 dec->SamplesLF = dec->SamplesHF + dec->NumChannels;
156 dec->Enabled = 0;
157 for(i = 0;i < conf->NumSpeakers;i++)
158 dec->Enabled |= 1 << chanmap[i];
160 if(conf->CoeffScale == ADS_SN3D)
161 coeff_scale = SN3D2N3DScale;
162 else if(conf->CoeffScale == ADS_FuMa)
163 coeff_scale = FuMa2N3DScale;
165 memset(dec->UpSampler, 0, sizeof(dec->UpSampler));
166 ratio = 400.0f / (ALfloat)srate;
167 for(i = 0;i < 4;i++)
168 bandsplit_init(&dec->UpSampler[i].XOver, ratio);
169 if((conf->ChanMask&AMBI_PERIPHONIC_MASK))
171 periphonic = true;
173 dec->UpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H3P :
174 (conf->ChanMask > 0xf) ? W_SCALE_2H2P : 1.0f;
175 dec->UpSampler[0].Gains[LF_BAND] = 1.0f;
176 for(i = 1;i < 4;i++)
178 dec->UpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H3P :
179 (conf->ChanMask > 0xf) ? XYZ_SCALE_2H2P : 1.0f;
180 dec->UpSampler[i].Gains[LF_BAND] = 1.0f;
183 else
185 periphonic = false;
187 dec->UpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H0P :
188 (conf->ChanMask > 0xf) ? W_SCALE_2H0P : 1.0f;
189 dec->UpSampler[0].Gains[LF_BAND] = 1.0f;
190 for(i = 1;i < 3;i++)
192 dec->UpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H0P :
193 (conf->ChanMask > 0xf) ? XYZ_SCALE_2H0P : 1.0f;
194 dec->UpSampler[i].Gains[LF_BAND] = 1.0f;
196 dec->UpSampler[3].Gains[HF_BAND] = 0.0f;
197 dec->UpSampler[3].Gains[LF_BAND] = 0.0f;
200 memset(&dec->Matrix, 0, sizeof(dec->Matrix));
201 if(conf->FreqBands == 1)
203 dec->DualBand = AL_FALSE;
204 for(i = 0;i < conf->NumSpeakers;i++)
206 ALsizei chan = chanmap[i];
207 ALfloat gain;
208 ALsizei j, k;
210 if(!periphonic)
212 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
214 ALsizei l = map2DTo3D[j];
215 if(j == 0) gain = conf->HFOrderGain[0];
216 else if(j == 1) gain = conf->HFOrderGain[1];
217 else if(j == 3) gain = conf->HFOrderGain[2];
218 else if(j == 5) gain = conf->HFOrderGain[3];
219 if((conf->ChanMask&(1<<l)))
220 dec->Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] *
221 gain;
224 else
226 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
228 if(j == 0) gain = conf->HFOrderGain[0];
229 else if(j == 1) gain = conf->HFOrderGain[1];
230 else if(j == 4) gain = conf->HFOrderGain[2];
231 else if(j == 9) gain = conf->HFOrderGain[3];
232 if((conf->ChanMask&(1<<j)))
233 dec->Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] *
234 gain;
239 else
241 dec->DualBand = AL_TRUE;
243 ratio = conf->XOverFreq / (ALfloat)srate;
244 for(i = 0;i < MAX_AMBI_COEFFS;i++)
245 bandsplit_init(&dec->XOver[i], ratio);
247 ratio = powf(10.0f, conf->XOverRatio / 40.0f);
248 for(i = 0;i < conf->NumSpeakers;i++)
250 ALsizei chan = chanmap[i];
251 ALfloat gain;
252 ALsizei j, k;
254 if(!periphonic)
256 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
258 ALsizei l = map2DTo3D[j];
259 if(j == 0) gain = conf->HFOrderGain[0] * ratio;
260 else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
261 else if(j == 3) gain = conf->HFOrderGain[2] * ratio;
262 else if(j == 5) gain = conf->HFOrderGain[3] * ratio;
263 if((conf->ChanMask&(1<<l)))
264 dec->Matrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] /
265 coeff_scale[l] * gain;
267 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
269 ALsizei l = map2DTo3D[j];
270 if(j == 0) gain = conf->LFOrderGain[0] / ratio;
271 else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
272 else if(j == 3) gain = conf->LFOrderGain[2] / ratio;
273 else if(j == 5) gain = conf->LFOrderGain[3] / ratio;
274 if((conf->ChanMask&(1<<l)))
275 dec->Matrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] /
276 coeff_scale[l] * gain;
279 else
281 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
283 if(j == 0) gain = conf->HFOrderGain[0] * ratio;
284 else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
285 else if(j == 4) gain = conf->HFOrderGain[2] * ratio;
286 else if(j == 9) gain = conf->HFOrderGain[3] * ratio;
287 if((conf->ChanMask&(1<<j)))
288 dec->Matrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] /
289 coeff_scale[j] * gain;
291 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
293 if(j == 0) gain = conf->LFOrderGain[0] / ratio;
294 else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
295 else if(j == 4) gain = conf->LFOrderGain[2] / ratio;
296 else if(j == 9) gain = conf->LFOrderGain[3] / ratio;
297 if((conf->ChanMask&(1<<j)))
298 dec->Matrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] /
299 coeff_scale[j] * gain;
307 void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo)
309 ALsizei chan, i;
311 OutBuffer = ASSUME_ALIGNED(OutBuffer, 16);
312 if(dec->DualBand)
314 for(i = 0;i < dec->NumChannels;i++)
315 bandsplit_process(&dec->XOver[i], dec->SamplesHF[i], dec->SamplesLF[i],
316 InSamples[i], SamplesToDo);
318 for(chan = 0;chan < OutChannels;chan++)
320 if(!(dec->Enabled&(1<<chan)))
321 continue;
323 memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat));
324 MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][HF_BAND],
325 dec->SamplesHF, dec->NumChannels, 0, SamplesToDo
327 MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][LF_BAND],
328 dec->SamplesLF, dec->NumChannels, 0, SamplesToDo
331 for(i = 0;i < SamplesToDo;i++)
332 OutBuffer[chan][i] += dec->ChannelMix[i];
335 else
337 for(chan = 0;chan < OutChannels;chan++)
339 if(!(dec->Enabled&(1<<chan)))
340 continue;
342 memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat));
343 MixRowSamples(dec->ChannelMix, dec->Matrix.Single[chan], InSamples,
344 dec->NumChannels, 0, SamplesToDo);
346 for(i = 0;i < SamplesToDo;i++)
347 OutBuffer[chan][i] += dec->ChannelMix[i];
353 void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo)
355 ALsizei i;
357 /* This up-sampler leverages the differences observed in dual-band second-
358 * and third-order decoder matrices compared to first-order. For the same
359 * output channel configuration, the low-frequency matrix has identical
360 * coefficients in the shared input channels, while the high-frequency
361 * matrix has extra scalars applied to the W channel and X/Y/Z channels.
362 * Mixing the first-order content into the higher-order stream with the
363 * appropriate counter-scales applied to the HF response results in the
364 * subsequent higher-order decode generating the same response as a first-
365 * order decode.
367 for(i = 0;i < InChannels;i++)
369 /* First, split the first-order components into low and high frequency
370 * bands.
372 bandsplit_process(&dec->UpSampler[i].XOver,
373 dec->Samples[HF_BAND], dec->Samples[LF_BAND],
374 InSamples[i], SamplesToDo
377 /* Now write each band to the output. */
378 MixRowSamples(OutBuffer[i], dec->UpSampler[i].Gains,
379 dec->Samples, NUM_BANDS, 0, SamplesToDo
385 #define INVALID_UPSAMPLE_INDEX INT_MAX
387 static ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn)
389 ALsizei i;
390 for(i = 0;i < numchans;i++)
392 if(chans[i].Index == acn)
393 return i;
395 return INVALID_UPSAMPLE_INDEX;
397 #define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a))
399 typedef struct AmbiUpsampler {
400 alignas(16) ALfloat Samples[NUM_BANDS][BUFFERSIZE];
402 BandSplitter XOver[4];
404 ALfloat Gains[4][MAX_OUTPUT_CHANNELS][NUM_BANDS];
405 } AmbiUpsampler;
407 AmbiUpsampler *ambiup_alloc()
409 return al_calloc(16, sizeof(AmbiUpsampler));
412 void ambiup_free(struct AmbiUpsampler **ambiup)
414 if(ambiup)
416 al_free(*ambiup);
417 *ambiup = NULL;
421 void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat w_scale, ALfloat xyz_scale)
423 ALfloat ratio;
424 ALsizei i;
426 ratio = 400.0f / (ALfloat)device->Frequency;
427 for(i = 0;i < 4;i++)
428 bandsplit_init(&ambiup->XOver[i], ratio);
430 memset(ambiup->Gains, 0, sizeof(ambiup->Gains));
431 if(device->Dry.CoeffCount > 0)
433 ALfloat encgains[8][MAX_OUTPUT_CHANNELS];
434 ALsizei j;
435 size_t k;
437 for(k = 0;k < COUNTOF(Ambi3DPoints);k++)
439 ALfloat coeffs[MAX_AMBI_COEFFS] = { 0.0f };
440 CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs);
441 ComputeDryPanGains(&device->Dry, coeffs, 1.0f, encgains[k]);
444 /* Combine the matrices that do the in->virt and virt->out conversions
445 * so we get a single in->out conversion. NOTE: the Encoder matrix
446 * (encgains) and output are transposed, so the input channels line up
447 * with the rows and the output channels line up with the columns.
449 for(i = 0;i < 4;i++)
451 for(j = 0;j < device->Dry.NumChannels;j++)
453 ALdouble gain = 0.0;
454 for(k = 0;k < COUNTOF(Ambi3DDecoder);k++)
455 gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j];
456 ambiup->Gains[i][j][HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]);
457 ambiup->Gains[i][j][LF_BAND] = (ALfloat)gain;
461 else
463 for(i = 0;i < 4;i++)
465 ALsizei index = GetChannelForACN(device->Dry, i);
466 if(index != INVALID_UPSAMPLE_INDEX)
468 ALfloat scale = device->Dry.Ambi.Map[index].Scale;
469 ambiup->Gains[i][index][HF_BAND] = scale * ((i==0) ? w_scale : xyz_scale);
470 ambiup->Gains[i][index][LF_BAND] = scale;
476 void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo)
478 ALsizei i, j;
480 for(i = 0;i < 4;i++)
482 bandsplit_process(&ambiup->XOver[i],
483 ambiup->Samples[HF_BAND], ambiup->Samples[LF_BAND],
484 InSamples[i], SamplesToDo
487 for(j = 0;j < OutChannels;j++)
488 MixRowSamples(OutBuffer[j], ambiup->Gains[i][j],
489 ambiup->Samples, NUM_BANDS, 0, SamplesToDo