Clean up some more loops
[openal-soft.git] / Alc / bformatdec.cpp
blob6e8f9ca62c4295c796a2eed4dd36062afab1cb98
2 #include "config.h"
4 #include <array>
5 #include <vector>
6 #include <numeric>
7 #include <functional>
9 #include "bformatdec.h"
10 #include "ambdec.h"
11 #include "filters/splitter.h"
12 #include "alu.h"
14 #include "threads.h"
15 #include "almalloc.h"
18 /* NOTE: These are scale factors as applied to Ambisonics content. Decoder
19 * coefficients should be divided by these values to get proper N3D scalings.
21 const ALfloat N3D2N3DScale[MAX_AMBI_COEFFS] = {
22 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
23 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
25 const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = {
26 1.000000000f, /* ACN 0 (W), sqrt(1) */
27 1.732050808f, /* ACN 1 (Y), sqrt(3) */
28 1.732050808f, /* ACN 2 (Z), sqrt(3) */
29 1.732050808f, /* ACN 3 (X), sqrt(3) */
30 2.236067978f, /* ACN 4 (V), sqrt(5) */
31 2.236067978f, /* ACN 5 (T), sqrt(5) */
32 2.236067978f, /* ACN 6 (R), sqrt(5) */
33 2.236067978f, /* ACN 7 (S), sqrt(5) */
34 2.236067978f, /* ACN 8 (U), sqrt(5) */
35 2.645751311f, /* ACN 9 (Q), sqrt(7) */
36 2.645751311f, /* ACN 10 (O), sqrt(7) */
37 2.645751311f, /* ACN 11 (M), sqrt(7) */
38 2.645751311f, /* ACN 12 (K), sqrt(7) */
39 2.645751311f, /* ACN 13 (L), sqrt(7) */
40 2.645751311f, /* ACN 14 (N), sqrt(7) */
41 2.645751311f, /* ACN 15 (P), sqrt(7) */
43 const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
44 1.414213562f, /* ACN 0 (W), sqrt(2) */
45 1.732050808f, /* ACN 1 (Y), sqrt(3) */
46 1.732050808f, /* ACN 2 (Z), sqrt(3) */
47 1.732050808f, /* ACN 3 (X), sqrt(3) */
48 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */
49 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */
50 2.236067978f, /* ACN 6 (R), sqrt(5) */
51 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */
52 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */
53 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */
54 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */
55 2.231093404f, /* ACN 11 (M), sqrt(224/45) */
56 2.645751311f, /* ACN 12 (K), sqrt(7) */
57 2.231093404f, /* ACN 13 (L), sqrt(224/45) */
58 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */
59 2.091650066f, /* ACN 15 (P), sqrt(35/8) */
63 namespace {
65 #define HF_BAND 0
66 #define LF_BAND 1
67 static_assert(BFormatDec::NumBands == 2, "Unexpected BFormatDec::NumBands");
68 static_assert(AmbiUpsampler::NumBands == 2, "Unexpected AmbiUpsampler::NumBands");
70 /* These points are in AL coordinates! */
71 constexpr ALfloat Ambi3DPoints[8][3] = {
72 { -0.577350269f, 0.577350269f, -0.577350269f },
73 { 0.577350269f, 0.577350269f, -0.577350269f },
74 { -0.577350269f, 0.577350269f, 0.577350269f },
75 { 0.577350269f, 0.577350269f, 0.577350269f },
76 { -0.577350269f, -0.577350269f, -0.577350269f },
77 { 0.577350269f, -0.577350269f, -0.577350269f },
78 { -0.577350269f, -0.577350269f, 0.577350269f },
79 { 0.577350269f, -0.577350269f, 0.577350269f },
81 constexpr ALfloat Ambi3DDecoder[8][MAX_AMBI_COEFFS] = {
82 { 0.125f, 0.125f, 0.125f, 0.125f },
83 { 0.125f, -0.125f, 0.125f, 0.125f },
84 { 0.125f, 0.125f, 0.125f, -0.125f },
85 { 0.125f, -0.125f, 0.125f, -0.125f },
86 { 0.125f, 0.125f, -0.125f, 0.125f },
87 { 0.125f, -0.125f, -0.125f, 0.125f },
88 { 0.125f, 0.125f, -0.125f, -0.125f },
89 { 0.125f, -0.125f, -0.125f, -0.125f },
91 constexpr ALfloat Ambi3DDecoderHFScale[MAX_AMBI_COEFFS] = {
92 2.0f,
93 1.15470054f, 1.15470054f, 1.15470054f
97 #define INVALID_UPSAMPLE_INDEX INT_MAX
98 ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn)
100 ALsizei i;
101 for(i = 0;i < numchans;i++)
103 if(chans[i].Index == acn)
104 return i;
106 return INVALID_UPSAMPLE_INDEX;
108 #define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a))
110 } // namespace
113 void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS])
115 static constexpr ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = {
116 0, 1, 3, 4, 8, 9, 15
118 const ALfloat *coeff_scale = N3D2N3DScale;
120 dec->Samples.clear();
121 dec->SamplesHF = nullptr;
122 dec->SamplesLF = nullptr;
124 dec->NumChannels = chancount;
125 dec->Samples.resize(dec->NumChannels * 2);
126 dec->SamplesHF = dec->Samples.data();
127 dec->SamplesLF = dec->SamplesHF + dec->NumChannels;
129 dec->Enabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+conf->NumSpeakers, 0u,
130 [](ALuint mask, const ALsizei &chan) noexcept -> ALuint
131 { return mask | (1 << chan); }
134 if(conf->CoeffScale == AmbDecScale::SN3D)
135 coeff_scale = SN3D2N3DScale;
136 else if(conf->CoeffScale == AmbDecScale::FuMa)
137 coeff_scale = FuMa2N3DScale;
139 float ratio{400.0f / (float)srate};
140 for(auto &chan : dec->UpSampler)
142 chan.XOver.init(ratio);
143 chan.XOver.clear();
144 std::fill(std::begin(chan.Gains), std::end(chan.Gains), 0.0f);
147 const bool periphonic{(conf->ChanMask&AMBI_PERIPHONIC_MASK) != 0};
148 if(periphonic)
150 dec->UpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H3P :
151 (conf->ChanMask > 0xf) ? W_SCALE_2H2P : 1.0f;
152 dec->UpSampler[0].Gains[LF_BAND] = 1.0f;
153 for(ALsizei i{1};i < 4;i++)
155 dec->UpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H3P :
156 (conf->ChanMask > 0xf) ? XYZ_SCALE_2H2P : 1.0f;
157 dec->UpSampler[i].Gains[LF_BAND] = 1.0f;
160 else
162 dec->UpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H0P :
163 (conf->ChanMask > 0xf) ? W_SCALE_2H0P : 1.0f;
164 dec->UpSampler[0].Gains[LF_BAND] = 1.0f;
165 for(ALsizei i{1};i < 3;i++)
167 dec->UpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H0P :
168 (conf->ChanMask > 0xf) ? XYZ_SCALE_2H0P : 1.0f;
169 dec->UpSampler[i].Gains[LF_BAND] = 1.0f;
171 dec->UpSampler[3].Gains[HF_BAND] = 0.0f;
172 dec->UpSampler[3].Gains[LF_BAND] = 0.0f;
175 memset(&dec->Matrix, 0, sizeof(dec->Matrix));
176 if(conf->FreqBands == 1)
178 dec->DualBand = AL_FALSE;
179 for(ALsizei i{0};i < conf->NumSpeakers;i++)
181 ALsizei chan = chanmap[i];
182 ALfloat gain;
183 ALsizei j, k;
185 if(!periphonic)
187 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
189 ALsizei l = map2DTo3D[j];
190 if(j == 0) gain = conf->HFOrderGain[0];
191 else if(j == 1) gain = conf->HFOrderGain[1];
192 else if(j == 3) gain = conf->HFOrderGain[2];
193 else if(j == 5) gain = conf->HFOrderGain[3];
194 if((conf->ChanMask&(1<<l)))
195 dec->Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] *
196 gain;
199 else
201 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
203 if(j == 0) gain = conf->HFOrderGain[0];
204 else if(j == 1) gain = conf->HFOrderGain[1];
205 else if(j == 4) gain = conf->HFOrderGain[2];
206 else if(j == 9) gain = conf->HFOrderGain[3];
207 if((conf->ChanMask&(1<<j)))
208 dec->Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] *
209 gain;
214 else
216 using namespace std::placeholders;
217 dec->DualBand = AL_TRUE;
219 ratio = conf->XOverFreq / (ALfloat)srate;
220 std::for_each(std::begin(dec->XOver), std::end(dec->XOver),
221 std::bind(std::mem_fn(&BandSplitter::init), _1, ratio));
223 ratio = powf(10.0f, conf->XOverRatio / 40.0f);
224 for(ALsizei i{0};i < conf->NumSpeakers;i++)
226 ALsizei chan = chanmap[i];
227 ALfloat gain;
228 ALsizei j, k;
230 if(!periphonic)
232 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
234 ALsizei l = map2DTo3D[j];
235 if(j == 0) gain = conf->HFOrderGain[0] * ratio;
236 else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
237 else if(j == 3) gain = conf->HFOrderGain[2] * ratio;
238 else if(j == 5) gain = conf->HFOrderGain[3] * ratio;
239 if((conf->ChanMask&(1<<l)))
240 dec->Matrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] /
241 coeff_scale[l] * gain;
243 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
245 ALsizei l = map2DTo3D[j];
246 if(j == 0) gain = conf->LFOrderGain[0] / ratio;
247 else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
248 else if(j == 3) gain = conf->LFOrderGain[2] / ratio;
249 else if(j == 5) gain = conf->LFOrderGain[3] / ratio;
250 if((conf->ChanMask&(1<<l)))
251 dec->Matrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] /
252 coeff_scale[l] * gain;
255 else
257 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
259 if(j == 0) gain = conf->HFOrderGain[0] * ratio;
260 else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
261 else if(j == 4) gain = conf->HFOrderGain[2] * ratio;
262 else if(j == 9) gain = conf->HFOrderGain[3] * ratio;
263 if((conf->ChanMask&(1<<j)))
264 dec->Matrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] /
265 coeff_scale[j] * gain;
267 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
269 if(j == 0) gain = conf->LFOrderGain[0] / ratio;
270 else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
271 else if(j == 4) gain = conf->LFOrderGain[2] / ratio;
272 else if(j == 9) gain = conf->LFOrderGain[3] / ratio;
273 if((conf->ChanMask&(1<<j)))
274 dec->Matrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] /
275 coeff_scale[j] * gain;
283 void bformatdec_process(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo)
285 ASSUME(OutChannels > 0);
286 ASSUME(SamplesToDo > 0);
288 ALsizei chan, i;
289 if(dec->DualBand)
291 for(i = 0;i < dec->NumChannels;i++)
292 dec->XOver[i].process(dec->SamplesHF[i].data(), dec->SamplesLF[i].data(), InSamples[i],
293 SamplesToDo);
295 for(chan = 0;chan < OutChannels;chan++)
297 if(UNLIKELY(!(dec->Enabled&(1<<chan))))
298 continue;
300 std::fill(std::begin(dec->ChannelMix), std::begin(dec->ChannelMix)+SamplesToDo, 0.0f);
301 MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][HF_BAND],
302 &reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(dec->SamplesHF[0]),
303 dec->NumChannels, 0, SamplesToDo
305 MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][LF_BAND],
306 &reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(dec->SamplesLF[0]),
307 dec->NumChannels, 0, SamplesToDo
310 std::transform(std::begin(dec->ChannelMix), std::begin(dec->ChannelMix)+SamplesToDo,
311 OutBuffer[chan], OutBuffer[chan], std::plus<float>());
314 else
316 for(chan = 0;chan < OutChannels;chan++)
318 if(UNLIKELY(!(dec->Enabled&(1<<chan))))
319 continue;
321 std::fill(std::begin(dec->ChannelMix), std::begin(dec->ChannelMix)+SamplesToDo, 0.0f);
322 MixRowSamples(dec->ChannelMix, dec->Matrix.Single[chan], InSamples,
323 dec->NumChannels, 0, SamplesToDo);
325 std::transform(std::begin(dec->ChannelMix), std::begin(dec->ChannelMix)+SamplesToDo,
326 OutBuffer[chan], OutBuffer[chan], std::plus<float>());
332 void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo)
334 ASSUME(InChannels > 0);
335 ASSUME(SamplesToDo > 0);
337 /* This up-sampler leverages the differences observed in dual-band second-
338 * and third-order decoder matrices compared to first-order. For the same
339 * output channel configuration, the low-frequency matrix has identical
340 * coefficients in the shared input channels, while the high-frequency
341 * matrix has extra scalars applied to the W channel and X/Y/Z channels.
342 * Mixing the first-order content into the higher-order stream with the
343 * appropriate counter-scales applied to the HF response results in the
344 * subsequent higher-order decode generating the same response as a first-
345 * order decode.
347 for(ALsizei i{0};i < InChannels;i++)
349 /* First, split the first-order components into low and high frequency
350 * bands.
352 dec->UpSampler[i].XOver.process(dec->Samples[HF_BAND].data(), dec->Samples[LF_BAND].data(),
353 InSamples[i], SamplesToDo
356 /* Now write each band to the output. */
357 MixRowSamples(OutBuffer[i], dec->UpSampler[i].Gains,
358 &reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(dec->Samples[0]),
359 BFormatDec::NumBands, 0, SamplesToDo
365 void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat w_scale, ALfloat xyz_scale)
367 using namespace std::placeholders;
369 float ratio{400.0f / (float)device->Frequency};
370 std::for_each(std::begin(ambiup->XOver), std::end(ambiup->XOver),
371 std::bind(std::mem_fn(&BandSplitter::init), _1, ratio));
373 memset(ambiup->Gains, 0, sizeof(ambiup->Gains));
374 if(device->Dry.CoeffCount > 0)
376 ALfloat encgains[8][MAX_OUTPUT_CHANNELS];
377 for(size_t k{0u};k < COUNTOF(Ambi3DPoints);k++)
379 ALfloat coeffs[MAX_AMBI_COEFFS] = { 0.0f };
380 CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs);
381 ComputePanGains(&device->Dry, coeffs, 1.0f, encgains[k]);
384 /* Combine the matrices that do the in->virt and virt->out conversions
385 * so we get a single in->out conversion. NOTE: the Encoder matrix
386 * (encgains) and output are transposed, so the input channels line up
387 * with the rows and the output channels line up with the columns.
389 for(ALsizei i{0};i < 4;i++)
391 for(ALsizei j{0};j < device->Dry.NumChannels;j++)
393 ALdouble gain = 0.0;
394 for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++)
395 gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j];
396 ambiup->Gains[i][j][HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]);
397 ambiup->Gains[i][j][LF_BAND] = (ALfloat)gain;
401 else
403 for(ALsizei i{0};i < 4;i++)
405 ALsizei index = GetChannelForACN(device->Dry, i);
406 if(index != INVALID_UPSAMPLE_INDEX)
408 ALfloat scale = device->Dry.Ambi.Map[index].Scale;
409 ambiup->Gains[i][index][HF_BAND] = scale * ((i==0) ? w_scale : xyz_scale);
410 ambiup->Gains[i][index][LF_BAND] = scale;
416 void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], ALsizei SamplesToDo)
418 ASSUME(OutChannels > 0);
419 ASSUME(SamplesToDo > 0);
421 for(ALsizei i{0};i < 4;i++)
423 ambiup->XOver[i].process(ambiup->Samples[HF_BAND], ambiup->Samples[LF_BAND], InSamples[i],
424 SamplesToDo);
426 for(ALsizei j{0};j < OutChannels;j++)
427 MixRowSamples(OutBuffer[j], ambiup->Gains[i][j],
428 ambiup->Samples, AmbiUpsampler::NumBands, 0, SamplesToDo