A bit more cleanup
[openal-soft.git] / Alc / bformatdec.cpp
blob7af3a864b9f87c134de7d6318c5eba0ea9b19b31
2 #include "config.h"
4 #include <cmath>
5 #include <array>
6 #include <vector>
7 #include <numeric>
8 #include <algorithm>
9 #include <functional>
11 #include "bformatdec.h"
12 #include "ambdec.h"
13 #include "filters/splitter.h"
14 #include "alu.h"
16 #include "threads.h"
17 #include "almalloc.h"
20 /* NOTE: These are scale factors as applied to Ambisonics content. Decoder
21 * coefficients should be divided by these values to get proper N3D scalings.
23 const ALfloat N3D2N3DScale[MAX_AMBI_COEFFS] = {
24 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
25 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
27 const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = {
28 1.000000000f, /* ACN 0 (W), sqrt(1) */
29 1.732050808f, /* ACN 1 (Y), sqrt(3) */
30 1.732050808f, /* ACN 2 (Z), sqrt(3) */
31 1.732050808f, /* ACN 3 (X), sqrt(3) */
32 2.236067978f, /* ACN 4 (V), sqrt(5) */
33 2.236067978f, /* ACN 5 (T), sqrt(5) */
34 2.236067978f, /* ACN 6 (R), sqrt(5) */
35 2.236067978f, /* ACN 7 (S), sqrt(5) */
36 2.236067978f, /* ACN 8 (U), sqrt(5) */
37 2.645751311f, /* ACN 9 (Q), sqrt(7) */
38 2.645751311f, /* ACN 10 (O), sqrt(7) */
39 2.645751311f, /* ACN 11 (M), sqrt(7) */
40 2.645751311f, /* ACN 12 (K), sqrt(7) */
41 2.645751311f, /* ACN 13 (L), sqrt(7) */
42 2.645751311f, /* ACN 14 (N), sqrt(7) */
43 2.645751311f, /* ACN 15 (P), sqrt(7) */
45 const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
46 1.414213562f, /* ACN 0 (W), sqrt(2) */
47 1.732050808f, /* ACN 1 (Y), sqrt(3) */
48 1.732050808f, /* ACN 2 (Z), sqrt(3) */
49 1.732050808f, /* ACN 3 (X), sqrt(3) */
50 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */
51 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */
52 2.236067978f, /* ACN 6 (R), sqrt(5) */
53 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */
54 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */
55 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */
56 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */
57 2.231093404f, /* ACN 11 (M), sqrt(224/45) */
58 2.645751311f, /* ACN 12 (K), sqrt(7) */
59 2.231093404f, /* ACN 13 (L), sqrt(224/45) */
60 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */
61 2.091650066f, /* ACN 15 (P), sqrt(35/8) */
65 namespace {
67 #define HF_BAND 0
68 #define LF_BAND 1
69 static_assert(BFormatDec::sNumBands == 2, "Unexpected BFormatDec::sNumBands");
70 static_assert(AmbiUpsampler::sNumBands == 2, "Unexpected AmbiUpsampler::sNumBands");
72 /* These points are in AL coordinates! */
73 constexpr ALfloat Ambi3DPoints[8][3] = {
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 },
80 { -0.577350269f, -0.577350269f, 0.577350269f },
81 { 0.577350269f, -0.577350269f, 0.577350269f },
83 constexpr ALfloat Ambi3DDecoder[8][MAX_AMBI_COEFFS] = {
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 },
90 { 0.125f, 0.125f, -0.125f, -0.125f },
91 { 0.125f, -0.125f, -0.125f, -0.125f },
93 constexpr ALfloat Ambi3DDecoderHFScale[MAX_AMBI_COEFFS] = {
94 2.0f,
95 1.15470054f, 1.15470054f, 1.15470054f
99 #define INVALID_UPSAMPLE_INDEX INT_MAX
100 ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn)
102 ALsizei i;
103 for(i = 0;i < numchans;i++)
105 if(chans[i].Index == acn)
106 return i;
108 return INVALID_UPSAMPLE_INDEX;
110 #define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a))
112 } // namespace
115 void BFormatDec::reset(const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei (&chanmap)[MAX_OUTPUT_CHANNELS])
117 static constexpr ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = {
118 0, 1, 3, 4, 8, 9, 15
120 const ALfloat *coeff_scale = N3D2N3DScale;
122 mSamples.clear();
123 mSamplesHF = nullptr;
124 mSamplesLF = nullptr;
126 mNumChannels = chancount;
127 mSamples.resize(mNumChannels * 2);
128 mSamplesHF = mSamples.data();
129 mSamplesLF = mSamplesHF + mNumChannels;
131 mEnabled = std::accumulate(std::begin(chanmap), std::begin(chanmap)+conf->NumSpeakers, 0u,
132 [](ALuint mask, const ALsizei &chan) noexcept -> ALuint
133 { return mask | (1 << chan); }
136 if(conf->CoeffScale == AmbDecScale::SN3D)
137 coeff_scale = SN3D2N3DScale;
138 else if(conf->CoeffScale == AmbDecScale::FuMa)
139 coeff_scale = FuMa2N3DScale;
141 mUpSampler[0].XOver.init(400.0f / (float)srate);
142 std::fill(std::begin(mUpSampler[0].Gains), std::end(mUpSampler[0].Gains), 0.0f);
143 std::fill(std::begin(mUpSampler)+1, std::end(mUpSampler), mUpSampler[0]);
145 const bool periphonic{(conf->ChanMask&AMBI_PERIPHONIC_MASK) != 0};
146 if(periphonic)
148 mUpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H3P :
149 (conf->ChanMask > 0xf) ? W_SCALE_2H2P : 1.0f;
150 mUpSampler[0].Gains[LF_BAND] = 1.0f;
151 for(ALsizei i{1};i < 4;i++)
153 mUpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H3P :
154 (conf->ChanMask > 0xf) ? XYZ_SCALE_2H2P : 1.0f;
155 mUpSampler[i].Gains[LF_BAND] = 1.0f;
158 else
160 mUpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H0P :
161 (conf->ChanMask > 0xf) ? W_SCALE_2H0P : 1.0f;
162 mUpSampler[0].Gains[LF_BAND] = 1.0f;
163 for(ALsizei i{1};i < 3;i++)
165 mUpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H0P :
166 (conf->ChanMask > 0xf) ? XYZ_SCALE_2H0P : 1.0f;
167 mUpSampler[i].Gains[LF_BAND] = 1.0f;
169 mUpSampler[3].Gains[HF_BAND] = 0.0f;
170 mUpSampler[3].Gains[LF_BAND] = 0.0f;
173 memset(&mMatrix, 0, sizeof(mMatrix));
174 if(conf->FreqBands == 1)
176 mDualBand = AL_FALSE;
177 for(ALsizei i{0};i < conf->NumSpeakers;i++)
179 ALsizei chan = chanmap[i];
180 ALfloat gain;
181 ALsizei j, k;
183 if(!periphonic)
185 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
187 ALsizei l = map2DTo3D[j];
188 if(j == 0) gain = conf->HFOrderGain[0];
189 else if(j == 1) gain = conf->HFOrderGain[1];
190 else if(j == 3) gain = conf->HFOrderGain[2];
191 else if(j == 5) gain = conf->HFOrderGain[3];
192 if((conf->ChanMask&(1<<l)))
193 mMatrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] * gain;
196 else
198 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
200 if(j == 0) gain = conf->HFOrderGain[0];
201 else if(j == 1) gain = conf->HFOrderGain[1];
202 else if(j == 4) gain = conf->HFOrderGain[2];
203 else if(j == 9) gain = conf->HFOrderGain[3];
204 if((conf->ChanMask&(1<<j)))
205 mMatrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * gain;
210 else
212 mDualBand = AL_TRUE;
214 mXOver[0].init(conf->XOverFreq / (float)srate);
215 std::fill(std::begin(mXOver)+1, std::end(mXOver), mXOver[0]);
217 float ratio{std::pow(10.0f, conf->XOverRatio / 40.0f)};
218 for(ALsizei i{0};i < conf->NumSpeakers;i++)
220 ALsizei chan = chanmap[i];
222 ALfloat gain{};
223 if(!periphonic)
225 for(ALsizei j{0},k{0};j < MAX_AMBI2D_COEFFS;j++)
227 ALsizei l = map2DTo3D[j];
228 if(j == 0) gain = conf->HFOrderGain[0] * ratio;
229 else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
230 else if(j == 3) gain = conf->HFOrderGain[2] * ratio;
231 else if(j == 5) gain = conf->HFOrderGain[3] * ratio;
232 if((conf->ChanMask&(1<<l)))
233 mMatrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / coeff_scale[l] *
234 gain;
236 for(ALsizei j{0},k{0};j < MAX_AMBI2D_COEFFS;j++)
238 ALsizei l = map2DTo3D[j];
239 if(j == 0) gain = conf->LFOrderGain[0] / ratio;
240 else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
241 else if(j == 3) gain = conf->LFOrderGain[2] / ratio;
242 else if(j == 5) gain = conf->LFOrderGain[3] / ratio;
243 if((conf->ChanMask&(1<<l)))
244 mMatrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] / coeff_scale[l] *
245 gain;
248 else
250 for(ALsizei j{0},k{0};j < MAX_AMBI_COEFFS;j++)
252 if(j == 0) gain = conf->HFOrderGain[0] * ratio;
253 else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
254 else if(j == 4) gain = conf->HFOrderGain[2] * ratio;
255 else if(j == 9) gain = conf->HFOrderGain[3] * ratio;
256 if((conf->ChanMask&(1<<j)))
257 mMatrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / coeff_scale[j] *
258 gain;
260 for(ALsizei j{0},k{0};j < MAX_AMBI_COEFFS;j++)
262 if(j == 0) gain = conf->LFOrderGain[0] / ratio;
263 else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
264 else if(j == 4) gain = conf->LFOrderGain[2] / ratio;
265 else if(j == 9) gain = conf->LFOrderGain[3] / ratio;
266 if((conf->ChanMask&(1<<j)))
267 mMatrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] / coeff_scale[j] *
268 gain;
275 void BFormatDec::process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei SamplesToDo)
277 ASSUME(OutChannels > 0);
278 ASSUME(SamplesToDo > 0);
280 ALsizei chan, i;
281 if(mDualBand)
283 for(i = 0;i < mNumChannels;i++)
284 mXOver[i].process(mSamplesHF[i].data(), mSamplesLF[i].data(), InSamples[i],
285 SamplesToDo);
287 for(chan = 0;chan < OutChannels;chan++)
289 if(UNLIKELY(!(mEnabled&(1<<chan))))
290 continue;
292 std::fill(std::begin(mChannelMix), std::begin(mChannelMix)+SamplesToDo, 0.0f);
293 MixRowSamples(mChannelMix, mMatrix.Dual[chan][HF_BAND],
294 &reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(mSamplesHF[0]),
295 mNumChannels, 0, SamplesToDo
297 MixRowSamples(mChannelMix, mMatrix.Dual[chan][LF_BAND],
298 &reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(mSamplesLF[0]),
299 mNumChannels, 0, SamplesToDo
302 std::transform(std::begin(mChannelMix), std::begin(mChannelMix)+SamplesToDo,
303 OutBuffer[chan], OutBuffer[chan], std::plus<float>());
306 else
308 for(chan = 0;chan < OutChannels;chan++)
310 if(UNLIKELY(!(mEnabled&(1<<chan))))
311 continue;
313 std::fill(std::begin(mChannelMix), std::begin(mChannelMix)+SamplesToDo, 0.0f);
314 MixRowSamples(mChannelMix, mMatrix.Single[chan], InSamples,
315 mNumChannels, 0, SamplesToDo);
317 std::transform(std::begin(mChannelMix), std::begin(mChannelMix)+SamplesToDo,
318 OutBuffer[chan], OutBuffer[chan], std::plus<float>());
323 void BFormatDec::upSample(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei InChannels, const ALsizei SamplesToDo)
325 ASSUME(InChannels > 0);
326 ASSUME(SamplesToDo > 0);
328 /* This up-sampler leverages the differences observed in dual-band second-
329 * and third-order decoder matrices compared to first-order. For the same
330 * output channel configuration, the low-frequency matrix has identical
331 * coefficients in the shared input channels, while the high-frequency
332 * matrix has extra scalars applied to the W channel and X/Y/Z channels.
333 * Mixing the first-order content into the higher-order stream with the
334 * appropriate counter-scales applied to the HF response results in the
335 * subsequent higher-order decode generating the same response as a first-
336 * order decode.
338 for(ALsizei i{0};i < InChannels;i++)
340 /* First, split the first-order components into low and high frequency
341 * bands.
343 mUpSampler[i].XOver.process(mSamples[HF_BAND].data(), mSamples[LF_BAND].data(),
344 InSamples[i], SamplesToDo);
346 /* Now write each band to the output. */
347 MixRowSamples(OutBuffer[i], mUpSampler[i].Gains,
348 &reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(mSamples[0]),
349 sNumBands, 0, SamplesToDo);
354 void AmbiUpsampler::reset(const ALCdevice *device, const ALfloat w_scale, const ALfloat xyz_scale)
356 using namespace std::placeholders;
358 mXOver[0].init(400.0f / (float)device->Frequency);
359 std::fill(std::begin(mXOver)+1, std::end(mXOver), mXOver[0]);
361 memset(mGains, 0, sizeof(mGains));
362 if(device->Dry.CoeffCount > 0)
364 ALfloat encgains[8][MAX_OUTPUT_CHANNELS];
365 for(size_t k{0u};k < COUNTOF(Ambi3DPoints);k++)
367 ALfloat coeffs[MAX_AMBI_COEFFS] = { 0.0f };
368 CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs);
369 ComputePanGains(&device->Dry, coeffs, 1.0f, encgains[k]);
372 /* Combine the matrices that do the in->virt and virt->out conversions
373 * so we get a single in->out conversion. NOTE: the Encoder matrix
374 * (encgains) and output are transposed, so the input channels line up
375 * with the rows and the output channels line up with the columns.
377 for(ALsizei i{0};i < 4;i++)
379 for(ALsizei j{0};j < device->Dry.NumChannels;j++)
381 ALdouble gain = 0.0;
382 for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++)
383 gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j];
384 mGains[i][j][HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]);
385 mGains[i][j][LF_BAND] = (ALfloat)gain;
389 else
391 for(ALsizei i{0};i < 4;i++)
393 ALsizei index = GetChannelForACN(device->Dry, i);
394 if(index != INVALID_UPSAMPLE_INDEX)
396 ALfloat scale = device->Dry.Ambi.Map[index].Scale;
397 mGains[i][index][HF_BAND] = scale * ((i==0) ? w_scale : xyz_scale);
398 mGains[i][index][LF_BAND] = scale;
404 void AmbiUpsampler::process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei SamplesToDo)
406 ASSUME(OutChannels > 0);
407 ASSUME(SamplesToDo > 0);
409 for(ALsizei i{0};i < 4;i++)
411 mXOver[i].process(mSamples[HF_BAND], mSamples[LF_BAND], InSamples[i], SamplesToDo);
413 for(ALsizei j{0};j < OutChannels;j++)
414 MixRowSamples(OutBuffer[j], mGains[i][j], mSamples, sNumBands, 0, SamplesToDo);