Use member functions for BFormatDec and AmbiUpsampler
[openal-soft.git] / Alc / bformatdec.cpp
blob00db03933f2723af33d8e15c6525af15ebf2e9b4
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::sNumBands == 2, "Unexpected BFormatDec::sNumBands");
68 static_assert(AmbiUpsampler::sNumBands == 2, "Unexpected AmbiUpsampler::sNumBands");
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(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 mSamples.clear();
121 mSamplesHF = nullptr;
122 mSamplesLF = nullptr;
124 mNumChannels = chancount;
125 mSamples.resize(mNumChannels * 2);
126 mSamplesHF = mSamples.data();
127 mSamplesLF = mSamplesHF + mNumChannels;
129 mEnabled = 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 : mUpSampler)
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 mUpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H3P :
151 (conf->ChanMask > 0xf) ? W_SCALE_2H2P : 1.0f;
152 mUpSampler[0].Gains[LF_BAND] = 1.0f;
153 for(ALsizei i{1};i < 4;i++)
155 mUpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H3P :
156 (conf->ChanMask > 0xf) ? XYZ_SCALE_2H2P : 1.0f;
157 mUpSampler[i].Gains[LF_BAND] = 1.0f;
160 else
162 mUpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H0P :
163 (conf->ChanMask > 0xf) ? W_SCALE_2H0P : 1.0f;
164 mUpSampler[0].Gains[LF_BAND] = 1.0f;
165 for(ALsizei i{1};i < 3;i++)
167 mUpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H0P :
168 (conf->ChanMask > 0xf) ? XYZ_SCALE_2H0P : 1.0f;
169 mUpSampler[i].Gains[LF_BAND] = 1.0f;
171 mUpSampler[3].Gains[HF_BAND] = 0.0f;
172 mUpSampler[3].Gains[LF_BAND] = 0.0f;
175 memset(&mMatrix, 0, sizeof(mMatrix));
176 if(conf->FreqBands == 1)
178 mDualBand = 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 mMatrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] * gain;
198 else
200 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
202 if(j == 0) gain = conf->HFOrderGain[0];
203 else if(j == 1) gain = conf->HFOrderGain[1];
204 else if(j == 4) gain = conf->HFOrderGain[2];
205 else if(j == 9) gain = conf->HFOrderGain[3];
206 if((conf->ChanMask&(1<<j)))
207 mMatrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] * gain;
212 else
214 using namespace std::placeholders;
215 mDualBand = AL_TRUE;
217 ratio = conf->XOverFreq / (ALfloat)srate;
218 std::for_each(std::begin(mXOver), std::end(mXOver),
219 std::bind(std::mem_fn(&BandSplitter::init), _1, ratio));
221 ratio = powf(10.0f, conf->XOverRatio / 40.0f);
222 for(ALsizei i{0};i < conf->NumSpeakers;i++)
224 ALsizei chan = chanmap[i];
225 ALfloat gain;
226 ALsizei j, k;
228 if(!periphonic)
230 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
232 ALsizei l = map2DTo3D[j];
233 if(j == 0) gain = conf->HFOrderGain[0] * ratio;
234 else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
235 else if(j == 3) gain = conf->HFOrderGain[2] * ratio;
236 else if(j == 5) gain = conf->HFOrderGain[3] * ratio;
237 if((conf->ChanMask&(1<<l)))
238 mMatrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / coeff_scale[l] *
239 gain;
241 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
243 ALsizei l = map2DTo3D[j];
244 if(j == 0) gain = conf->LFOrderGain[0] / ratio;
245 else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
246 else if(j == 3) gain = conf->LFOrderGain[2] / ratio;
247 else if(j == 5) gain = conf->LFOrderGain[3] / ratio;
248 if((conf->ChanMask&(1<<l)))
249 mMatrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] / coeff_scale[l] *
250 gain;
253 else
255 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
257 if(j == 0) gain = conf->HFOrderGain[0] * ratio;
258 else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
259 else if(j == 4) gain = conf->HFOrderGain[2] * ratio;
260 else if(j == 9) gain = conf->HFOrderGain[3] * ratio;
261 if((conf->ChanMask&(1<<j)))
262 mMatrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] / coeff_scale[j] *
263 gain;
265 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
267 if(j == 0) gain = conf->LFOrderGain[0] / ratio;
268 else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
269 else if(j == 4) gain = conf->LFOrderGain[2] / ratio;
270 else if(j == 9) gain = conf->LFOrderGain[3] / ratio;
271 if((conf->ChanMask&(1<<j)))
272 mMatrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] / coeff_scale[j] *
273 gain;
280 void BFormatDec::process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei SamplesToDo)
282 ASSUME(OutChannels > 0);
283 ASSUME(SamplesToDo > 0);
285 ALsizei chan, i;
286 if(mDualBand)
288 for(i = 0;i < mNumChannels;i++)
289 mXOver[i].process(mSamplesHF[i].data(), mSamplesLF[i].data(), InSamples[i],
290 SamplesToDo);
292 for(chan = 0;chan < OutChannels;chan++)
294 if(UNLIKELY(!(mEnabled&(1<<chan))))
295 continue;
297 std::fill(std::begin(mChannelMix), std::begin(mChannelMix)+SamplesToDo, 0.0f);
298 MixRowSamples(mChannelMix, mMatrix.Dual[chan][HF_BAND],
299 &reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(mSamplesHF[0]),
300 mNumChannels, 0, SamplesToDo
302 MixRowSamples(mChannelMix, mMatrix.Dual[chan][LF_BAND],
303 &reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(mSamplesLF[0]),
304 mNumChannels, 0, SamplesToDo
307 std::transform(std::begin(mChannelMix), std::begin(mChannelMix)+SamplesToDo,
308 OutBuffer[chan], OutBuffer[chan], std::plus<float>());
311 else
313 for(chan = 0;chan < OutChannels;chan++)
315 if(UNLIKELY(!(mEnabled&(1<<chan))))
316 continue;
318 std::fill(std::begin(mChannelMix), std::begin(mChannelMix)+SamplesToDo, 0.0f);
319 MixRowSamples(mChannelMix, mMatrix.Single[chan], InSamples,
320 mNumChannels, 0, SamplesToDo);
322 std::transform(std::begin(mChannelMix), std::begin(mChannelMix)+SamplesToDo,
323 OutBuffer[chan], OutBuffer[chan], std::plus<float>());
328 void BFormatDec::upSample(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei InChannels, const ALsizei SamplesToDo)
330 ASSUME(InChannels > 0);
331 ASSUME(SamplesToDo > 0);
333 /* This up-sampler leverages the differences observed in dual-band second-
334 * and third-order decoder matrices compared to first-order. For the same
335 * output channel configuration, the low-frequency matrix has identical
336 * coefficients in the shared input channels, while the high-frequency
337 * matrix has extra scalars applied to the W channel and X/Y/Z channels.
338 * Mixing the first-order content into the higher-order stream with the
339 * appropriate counter-scales applied to the HF response results in the
340 * subsequent higher-order decode generating the same response as a first-
341 * order decode.
343 for(ALsizei i{0};i < InChannels;i++)
345 /* First, split the first-order components into low and high frequency
346 * bands.
348 mUpSampler[i].XOver.process(mSamples[HF_BAND].data(), mSamples[LF_BAND].data(),
349 InSamples[i], SamplesToDo);
351 /* Now write each band to the output. */
352 MixRowSamples(OutBuffer[i], mUpSampler[i].Gains,
353 &reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(mSamples[0]),
354 sNumBands, 0, SamplesToDo);
359 void AmbiUpsampler::reset(const ALCdevice *device, const ALfloat w_scale, const ALfloat xyz_scale)
361 using namespace std::placeholders;
363 float ratio{400.0f / (float)device->Frequency};
364 std::for_each(std::begin(mXOver), std::end(mXOver),
365 std::bind(std::mem_fn(&BandSplitter::init), _1, ratio));
367 memset(mGains, 0, sizeof(mGains));
368 if(device->Dry.CoeffCount > 0)
370 ALfloat encgains[8][MAX_OUTPUT_CHANNELS];
371 for(size_t k{0u};k < COUNTOF(Ambi3DPoints);k++)
373 ALfloat coeffs[MAX_AMBI_COEFFS] = { 0.0f };
374 CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs);
375 ComputePanGains(&device->Dry, coeffs, 1.0f, encgains[k]);
378 /* Combine the matrices that do the in->virt and virt->out conversions
379 * so we get a single in->out conversion. NOTE: the Encoder matrix
380 * (encgains) and output are transposed, so the input channels line up
381 * with the rows and the output channels line up with the columns.
383 for(ALsizei i{0};i < 4;i++)
385 for(ALsizei j{0};j < device->Dry.NumChannels;j++)
387 ALdouble gain = 0.0;
388 for(size_t k{0u};k < COUNTOF(Ambi3DDecoder);k++)
389 gain += (ALdouble)Ambi3DDecoder[k][i] * encgains[k][j];
390 mGains[i][j][HF_BAND] = (ALfloat)(gain * Ambi3DDecoderHFScale[i]);
391 mGains[i][j][LF_BAND] = (ALfloat)gain;
395 else
397 for(ALsizei i{0};i < 4;i++)
399 ALsizei index = GetChannelForACN(device->Dry, i);
400 if(index != INVALID_UPSAMPLE_INDEX)
402 ALfloat scale = device->Dry.Ambi.Map[index].Scale;
403 mGains[i][index][HF_BAND] = scale * ((i==0) ? w_scale : xyz_scale);
404 mGains[i][index][LF_BAND] = scale;
410 void AmbiUpsampler::process(ALfloat (*RESTRICT OutBuffer)[BUFFERSIZE], const ALsizei OutChannels, const ALfloat (*RESTRICT InSamples)[BUFFERSIZE], const ALsizei SamplesToDo)
412 ASSUME(OutChannels > 0);
413 ASSUME(SamplesToDo > 0);
415 for(ALsizei i{0};i < 4;i++)
417 mXOver[i].process(mSamples[HF_BAND], mSamples[LF_BAND], InSamples[i], SamplesToDo);
419 for(ALsizei j{0};j < OutChannels;j++)
420 MixRowSamples(OutBuffer[j], mGains[i][j], mSamples, sNumBands, 0, SamplesToDo);