4 #include "bformatdec.h"
6 #include "filters/splitter.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) */
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
] = {
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. */
95 alignas(16) ALfloat Dual
[MAX_OUTPUT_CHANNELS
][NUM_BANDS
][MAX_AMBI_COEFFS
];
96 alignas(16) ALfloat Single
[MAX_OUTPUT_CHANNELS
][MAX_AMBI_COEFFS
];
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
];
110 ALfloat Gains
[NUM_BANDS
];
117 BFormatDec
*bformatdec_alloc()
119 return al_calloc(16, sizeof(BFormatDec
));
122 void bformatdec_free(BFormatDec
**dec
)
126 al_free((*dec
)->Samples
);
127 (*dec
)->Samples
= NULL
;
128 (*dec
)->SamplesHF
= NULL
;
129 (*dec
)->SamplesLF
= 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
] = {
141 const ALfloat
*coeff_scale
= N3D2N3DScale
;
146 al_free(dec
->Samples
);
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
;
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
;
168 bandsplit_init(&dec
->UpSampler
[i
].XOver
, ratio
);
169 if((conf
->ChanMask
&AMBI_PERIPHONIC_MASK
))
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
;
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
;
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
;
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
];
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
] *
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
] *
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
];
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
;
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
)
311 OutBuffer
= ASSUME_ALIGNED(OutBuffer
, 16);
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
)))
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
];
337 for(chan
= 0;chan
< OutChannels
;chan
++)
339 if(!(dec
->Enabled
&(1<<chan
)))
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
)
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-
367 for(i
= 0;i
< InChannels
;i
++)
369 /* First, split the first-order components into low and high frequency
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
)
390 for(i
= 0;i
< numchans
;i
++)
392 if(chans
[i
].Index
== acn
)
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
];
407 AmbiUpsampler
*ambiup_alloc()
409 return al_calloc(16, sizeof(AmbiUpsampler
));
412 void ambiup_free(struct AmbiUpsampler
**ambiup
)
421 void ambiup_reset(struct AmbiUpsampler
*ambiup
, const ALCdevice
*device
, ALfloat w_scale
, ALfloat xyz_scale
)
426 ratio
= 400.0f
/ (ALfloat
)device
->Frequency
;
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
];
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.
451 for(j
= 0;j
< device
->Dry
.NumChannels
;j
++)
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
;
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
)
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