4 #include "bformatdec.h"
6 #include "mixer_defs.h"
14 void bandsplit_init(BandSplitter
*splitter
, ALfloat f0norm
)
16 ALfloat w
= f0norm
* F_TAU
;
19 splitter
->coeff
= (sinf(w
) - 1.0f
) / cw
;
21 splitter
->coeff
= cw
* -0.5f
;
23 splitter
->lp_z1
= 0.0f
;
24 splitter
->lp_z2
= 0.0f
;
25 splitter
->hp_z1
= 0.0f
;
28 void bandsplit_clear(BandSplitter
*splitter
)
30 splitter
->lp_z1
= 0.0f
;
31 splitter
->lp_z2
= 0.0f
;
32 splitter
->hp_z1
= 0.0f
;
35 void bandsplit_process(BandSplitter
*splitter
, ALfloat
*restrict hpout
, ALfloat
*restrict lpout
,
36 const ALfloat
*input
, ALsizei count
)
42 coeff
= splitter
->coeff
*0.5f
+ 0.5f
;
45 for(i
= 0;i
< count
;i
++)
62 coeff
= splitter
->coeff
;
64 for(i
= 0;i
< count
;i
++)
72 hpout
[i
] = x
- lpout
[i
];
78 void splitterap_init(SplitterAllpass
*splitter
, ALfloat f0norm
)
80 ALfloat w
= f0norm
* F_TAU
;
83 splitter
->coeff
= (sinf(w
) - 1.0f
) / cw
;
85 splitter
->coeff
= cw
* -0.5f
;
90 void splitterap_clear(SplitterAllpass
*splitter
)
95 void splitterap_process(SplitterAllpass
*splitter
, ALfloat
*restrict samples
, ALsizei count
)
101 coeff
= splitter
->coeff
;
103 for(i
= 0;i
< count
;i
++)
117 static const ALfloat UnitScale
[MAX_AMBI_COEFFS
] = {
118 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
,
119 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
121 static const ALfloat SN3D2N3DScale
[MAX_AMBI_COEFFS
] = {
122 1.000000000f
, /* ACN 0 (W), sqrt(1) */
123 1.732050808f
, /* ACN 1 (Y), sqrt(3) */
124 1.732050808f
, /* ACN 2 (Z), sqrt(3) */
125 1.732050808f
, /* ACN 3 (X), sqrt(3) */
126 2.236067978f
, /* ACN 4 (V), sqrt(5) */
127 2.236067978f
, /* ACN 5 (T), sqrt(5) */
128 2.236067978f
, /* ACN 6 (R), sqrt(5) */
129 2.236067978f
, /* ACN 7 (S), sqrt(5) */
130 2.236067978f
, /* ACN 8 (U), sqrt(5) */
131 2.645751311f
, /* ACN 9 (Q), sqrt(7) */
132 2.645751311f
, /* ACN 10 (O), sqrt(7) */
133 2.645751311f
, /* ACN 11 (M), sqrt(7) */
134 2.645751311f
, /* ACN 12 (K), sqrt(7) */
135 2.645751311f
, /* ACN 13 (L), sqrt(7) */
136 2.645751311f
, /* ACN 14 (N), sqrt(7) */
137 2.645751311f
, /* ACN 15 (P), sqrt(7) */
139 static const ALfloat FuMa2N3DScale
[MAX_AMBI_COEFFS
] = {
140 1.414213562f
, /* ACN 0 (W), sqrt(2) */
141 1.732050808f
, /* ACN 1 (Y), sqrt(3) */
142 1.732050808f
, /* ACN 2 (Z), sqrt(3) */
143 1.732050808f
, /* ACN 3 (X), sqrt(3) */
144 1.936491673f
, /* ACN 4 (V), sqrt(15)/2 */
145 1.936491673f
, /* ACN 5 (T), sqrt(15)/2 */
146 2.236067978f
, /* ACN 6 (R), sqrt(5) */
147 1.936491673f
, /* ACN 7 (S), sqrt(15)/2 */
148 1.936491673f
, /* ACN 8 (U), sqrt(15)/2 */
149 2.091650066f
, /* ACN 9 (Q), sqrt(35/8) */
150 1.972026594f
, /* ACN 10 (O), sqrt(35)/3 */
151 2.231093404f
, /* ACN 11 (M), sqrt(224/45) */
152 2.645751311f
, /* ACN 12 (K), sqrt(7) */
153 2.231093404f
, /* ACN 13 (L), sqrt(224/45) */
154 1.972026594f
, /* ACN 14 (N), sqrt(35)/3 */
155 2.091650066f
, /* ACN 15 (P), sqrt(35/8) */
163 /* These points are in AL coordinates! */
164 static const ALfloat Ambi3DPoints
[8][3] = {
165 { -0.577350269f
, 0.577350269f
, -0.577350269f
},
166 { 0.577350269f
, 0.577350269f
, -0.577350269f
},
167 { -0.577350269f
, 0.577350269f
, 0.577350269f
},
168 { 0.577350269f
, 0.577350269f
, 0.577350269f
},
169 { -0.577350269f
, -0.577350269f
, -0.577350269f
},
170 { 0.577350269f
, -0.577350269f
, -0.577350269f
},
171 { -0.577350269f
, -0.577350269f
, 0.577350269f
},
172 { 0.577350269f
, -0.577350269f
, 0.577350269f
},
174 static const ALfloat Ambi3DDecoder
[8][MAX_AMBI_COEFFS
] = {
175 { 0.125f
, 0.125f
, 0.125f
, 0.125f
},
176 { 0.125f
, -0.125f
, 0.125f
, 0.125f
},
177 { 0.125f
, 0.125f
, 0.125f
, -0.125f
},
178 { 0.125f
, -0.125f
, 0.125f
, -0.125f
},
179 { 0.125f
, 0.125f
, -0.125f
, 0.125f
},
180 { 0.125f
, -0.125f
, -0.125f
, 0.125f
},
181 { 0.125f
, 0.125f
, -0.125f
, -0.125f
},
182 { 0.125f
, -0.125f
, -0.125f
, -0.125f
},
184 static const ALfloat Ambi3DDecoderHFScale
[MAX_AMBI_COEFFS
] = {
186 1.15470054f
, 1.15470054f
, 1.15470054f
190 /* NOTE: BandSplitter filters are unused with single-band decoding */
191 typedef struct BFormatDec
{
192 ALuint Enabled
; /* Bitfield of enabled channels. */
195 alignas(16) ALfloat Dual
[MAX_OUTPUT_CHANNELS
][NUM_BANDS
][MAX_AMBI_COEFFS
];
196 alignas(16) ALfloat Single
[MAX_OUTPUT_CHANNELS
][MAX_AMBI_COEFFS
];
199 BandSplitter XOver
[MAX_AMBI_COEFFS
];
201 ALfloat (*Samples
)[BUFFERSIZE
];
202 /* These two alias into Samples */
203 ALfloat (*SamplesHF
)[BUFFERSIZE
];
204 ALfloat (*SamplesLF
)[BUFFERSIZE
];
206 alignas(16) ALfloat ChannelMix
[BUFFERSIZE
];
210 ALfloat Gains
[NUM_BANDS
];
217 BFormatDec
*bformatdec_alloc()
219 return al_calloc(16, sizeof(BFormatDec
));
222 void bformatdec_free(BFormatDec
**dec
)
226 al_free((*dec
)->Samples
);
227 (*dec
)->Samples
= NULL
;
228 (*dec
)->SamplesHF
= NULL
;
229 (*dec
)->SamplesLF
= NULL
;
236 void bformatdec_reset(BFormatDec
*dec
, const AmbDecConf
*conf
, ALsizei chancount
, ALuint srate
, const ALsizei chanmap
[MAX_OUTPUT_CHANNELS
])
238 static const ALsizei map2DTo3D
[MAX_AMBI2D_COEFFS
] = {
241 const ALfloat
*coeff_scale
= UnitScale
;
246 al_free(dec
->Samples
);
248 dec
->SamplesHF
= NULL
;
249 dec
->SamplesLF
= NULL
;
251 dec
->NumChannels
= chancount
;
252 dec
->Samples
= al_calloc(16, dec
->NumChannels
*2 * sizeof(dec
->Samples
[0]));
253 dec
->SamplesHF
= dec
->Samples
;
254 dec
->SamplesLF
= dec
->SamplesHF
+ dec
->NumChannels
;
257 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
258 dec
->Enabled
|= 1 << chanmap
[i
];
260 if(conf
->CoeffScale
== ADS_SN3D
)
261 coeff_scale
= SN3D2N3DScale
;
262 else if(conf
->CoeffScale
== ADS_FuMa
)
263 coeff_scale
= FuMa2N3DScale
;
265 memset(dec
->UpSampler
, 0, sizeof(dec
->UpSampler
));
266 ratio
= 400.0f
/ (ALfloat
)srate
;
268 bandsplit_init(&dec
->UpSampler
[i
].XOver
, ratio
);
269 if((conf
->ChanMask
&AMBI_PERIPHONIC_MASK
))
273 dec
->UpSampler
[0].Gains
[HF_BAND
] = (conf
->ChanMask
> 0x1ff) ? W_SCALE_3H3P
:
274 (conf
->ChanMask
> 0xf) ? W_SCALE_2H2P
: 1.0f
;
275 dec
->UpSampler
[0].Gains
[LF_BAND
] = 1.0f
;
278 dec
->UpSampler
[i
].Gains
[HF_BAND
] = (conf
->ChanMask
> 0x1ff) ? XYZ_SCALE_3H3P
:
279 (conf
->ChanMask
> 0xf) ? XYZ_SCALE_2H2P
: 1.0f
;
280 dec
->UpSampler
[i
].Gains
[LF_BAND
] = 1.0f
;
287 dec
->UpSampler
[0].Gains
[HF_BAND
] = (conf
->ChanMask
> 0x1ff) ? W_SCALE_3H0P
:
288 (conf
->ChanMask
> 0xf) ? W_SCALE_2H0P
: 1.0f
;
289 dec
->UpSampler
[0].Gains
[LF_BAND
] = 1.0f
;
292 dec
->UpSampler
[i
].Gains
[HF_BAND
] = (conf
->ChanMask
> 0x1ff) ? XYZ_SCALE_3H0P
:
293 (conf
->ChanMask
> 0xf) ? XYZ_SCALE_2H0P
: 1.0f
;
294 dec
->UpSampler
[i
].Gains
[LF_BAND
] = 1.0f
;
296 dec
->UpSampler
[3].Gains
[HF_BAND
] = 0.0f
;
297 dec
->UpSampler
[3].Gains
[LF_BAND
] = 0.0f
;
300 memset(&dec
->Matrix
, 0, sizeof(dec
->Matrix
));
301 if(conf
->FreqBands
== 1)
303 dec
->DualBand
= AL_FALSE
;
304 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
306 ALsizei chan
= chanmap
[i
];
312 for(j
= 0,k
= 0;j
< MAX_AMBI2D_COEFFS
;j
++)
314 ALsizei l
= map2DTo3D
[j
];
315 if(j
== 0) gain
= conf
->HFOrderGain
[0];
316 else if(j
== 1) gain
= conf
->HFOrderGain
[1];
317 else if(j
== 3) gain
= conf
->HFOrderGain
[2];
318 else if(j
== 5) gain
= conf
->HFOrderGain
[3];
319 if((conf
->ChanMask
&(1<<l
)))
320 dec
->Matrix
.Single
[chan
][j
] = conf
->HFMatrix
[i
][k
++] / coeff_scale
[l
] *
326 for(j
= 0,k
= 0;j
< MAX_AMBI_COEFFS
;j
++)
328 if(j
== 0) gain
= conf
->HFOrderGain
[0];
329 else if(j
== 1) gain
= conf
->HFOrderGain
[1];
330 else if(j
== 4) gain
= conf
->HFOrderGain
[2];
331 else if(j
== 9) gain
= conf
->HFOrderGain
[3];
332 if((conf
->ChanMask
&(1<<j
)))
333 dec
->Matrix
.Single
[chan
][j
] = conf
->HFMatrix
[i
][k
++] / coeff_scale
[j
] *
341 dec
->DualBand
= AL_TRUE
;
343 ratio
= conf
->XOverFreq
/ (ALfloat
)srate
;
344 for(i
= 0;i
< MAX_AMBI_COEFFS
;i
++)
345 bandsplit_init(&dec
->XOver
[i
], ratio
);
347 ratio
= powf(10.0f
, conf
->XOverRatio
/ 40.0f
);
348 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
350 ALsizei chan
= chanmap
[i
];
356 for(j
= 0,k
= 0;j
< MAX_AMBI2D_COEFFS
;j
++)
358 ALsizei l
= map2DTo3D
[j
];
359 if(j
== 0) gain
= conf
->HFOrderGain
[0] * ratio
;
360 else if(j
== 1) gain
= conf
->HFOrderGain
[1] * ratio
;
361 else if(j
== 3) gain
= conf
->HFOrderGain
[2] * ratio
;
362 else if(j
== 5) gain
= conf
->HFOrderGain
[3] * ratio
;
363 if((conf
->ChanMask
&(1<<l
)))
364 dec
->Matrix
.Dual
[chan
][HF_BAND
][j
] = conf
->HFMatrix
[i
][k
++] /
365 coeff_scale
[l
] * gain
;
367 for(j
= 0,k
= 0;j
< MAX_AMBI2D_COEFFS
;j
++)
369 ALsizei l
= map2DTo3D
[j
];
370 if(j
== 0) gain
= conf
->LFOrderGain
[0] / ratio
;
371 else if(j
== 1) gain
= conf
->LFOrderGain
[1] / ratio
;
372 else if(j
== 3) gain
= conf
->LFOrderGain
[2] / ratio
;
373 else if(j
== 5) gain
= conf
->LFOrderGain
[3] / ratio
;
374 if((conf
->ChanMask
&(1<<l
)))
375 dec
->Matrix
.Dual
[chan
][LF_BAND
][j
] = conf
->LFMatrix
[i
][k
++] /
376 coeff_scale
[l
] * gain
;
381 for(j
= 0,k
= 0;j
< MAX_AMBI_COEFFS
;j
++)
383 if(j
== 0) gain
= conf
->HFOrderGain
[0] * ratio
;
384 else if(j
== 1) gain
= conf
->HFOrderGain
[1] * ratio
;
385 else if(j
== 4) gain
= conf
->HFOrderGain
[2] * ratio
;
386 else if(j
== 9) gain
= conf
->HFOrderGain
[3] * ratio
;
387 if((conf
->ChanMask
&(1<<j
)))
388 dec
->Matrix
.Dual
[chan
][HF_BAND
][j
] = conf
->HFMatrix
[i
][k
++] /
389 coeff_scale
[j
] * gain
;
391 for(j
= 0,k
= 0;j
< MAX_AMBI_COEFFS
;j
++)
393 if(j
== 0) gain
= conf
->LFOrderGain
[0] / ratio
;
394 else if(j
== 1) gain
= conf
->LFOrderGain
[1] / ratio
;
395 else if(j
== 4) gain
= conf
->LFOrderGain
[2] / ratio
;
396 else if(j
== 9) gain
= conf
->LFOrderGain
[3] / ratio
;
397 if((conf
->ChanMask
&(1<<j
)))
398 dec
->Matrix
.Dual
[chan
][LF_BAND
][j
] = conf
->LFMatrix
[i
][k
++] /
399 coeff_scale
[j
] * gain
;
407 void bformatdec_process(struct BFormatDec
*dec
, ALfloat (*restrict OutBuffer
)[BUFFERSIZE
], ALsizei OutChannels
, const ALfloat (*restrict InSamples
)[BUFFERSIZE
], ALsizei SamplesToDo
)
411 OutBuffer
= ASSUME_ALIGNED(OutBuffer
, 16);
414 for(i
= 0;i
< dec
->NumChannels
;i
++)
415 bandsplit_process(&dec
->XOver
[i
], dec
->SamplesHF
[i
], dec
->SamplesLF
[i
],
416 InSamples
[i
], SamplesToDo
);
418 for(chan
= 0;chan
< OutChannels
;chan
++)
420 if(!(dec
->Enabled
&(1<<chan
)))
423 memset(dec
->ChannelMix
, 0, SamplesToDo
*sizeof(ALfloat
));
424 MixRowSamples(dec
->ChannelMix
, dec
->Matrix
.Dual
[chan
][HF_BAND
],
425 dec
->SamplesHF
, dec
->NumChannels
, 0, SamplesToDo
427 MixRowSamples(dec
->ChannelMix
, dec
->Matrix
.Dual
[chan
][LF_BAND
],
428 dec
->SamplesLF
, dec
->NumChannels
, 0, SamplesToDo
431 for(i
= 0;i
< SamplesToDo
;i
++)
432 OutBuffer
[chan
][i
] += dec
->ChannelMix
[i
];
437 for(chan
= 0;chan
< OutChannels
;chan
++)
439 if(!(dec
->Enabled
&(1<<chan
)))
442 memset(dec
->ChannelMix
, 0, SamplesToDo
*sizeof(ALfloat
));
443 MixRowSamples(dec
->ChannelMix
, dec
->Matrix
.Single
[chan
], InSamples
,
444 dec
->NumChannels
, 0, SamplesToDo
);
446 for(i
= 0;i
< SamplesToDo
;i
++)
447 OutBuffer
[chan
][i
] += dec
->ChannelMix
[i
];
453 void bformatdec_upSample(struct BFormatDec
*dec
, ALfloat (*restrict OutBuffer
)[BUFFERSIZE
], const ALfloat (*restrict InSamples
)[BUFFERSIZE
], ALsizei InChannels
, ALsizei SamplesToDo
)
457 /* This up-sampler leverages the differences observed in dual-band second-
458 * and third-order decoder matrices compared to first-order. For the same
459 * output channel configuration, the low-frequency matrix has identical
460 * coefficients in the shared input channels, while the high-frequency
461 * matrix has extra scalars applied to the W channel and X/Y/Z channels.
462 * Mixing the first-order content into the higher-order stream with the
463 * appropriate counter-scales applied to the HF response results in the
464 * subsequent higher-order decode generating the same response as a first-
467 for(i
= 0;i
< InChannels
;i
++)
469 /* First, split the first-order components into low and high frequency
472 bandsplit_process(&dec
->UpSampler
[i
].XOver
,
473 dec
->Samples
[HF_BAND
], dec
->Samples
[LF_BAND
],
474 InSamples
[i
], SamplesToDo
477 /* Now write each band to the output. */
478 MixRowSamples(OutBuffer
[i
], dec
->UpSampler
[i
].Gains
,
479 dec
->Samples
, NUM_BANDS
, 0, SamplesToDo
485 #define INVALID_UPSAMPLE_INDEX INT_MAX
487 static ALsizei
GetACNIndex(const BFChannelConfig
*chans
, ALsizei numchans
, ALsizei acn
)
490 for(i
= 0;i
< numchans
;i
++)
492 if(chans
[i
].Index
== acn
)
495 return INVALID_UPSAMPLE_INDEX
;
497 #define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a))
499 typedef struct AmbiUpsampler
{
500 alignas(16) ALfloat Samples
[NUM_BANDS
][BUFFERSIZE
];
502 BandSplitter XOver
[4];
504 ALfloat Gains
[4][MAX_OUTPUT_CHANNELS
][NUM_BANDS
];
507 AmbiUpsampler
*ambiup_alloc()
509 return al_calloc(16, sizeof(AmbiUpsampler
));
512 void ambiup_free(struct AmbiUpsampler
**ambiup
)
521 void ambiup_reset(struct AmbiUpsampler
*ambiup
, const ALCdevice
*device
, ALfloat w_scale
, ALfloat xyz_scale
)
526 ratio
= 400.0f
/ (ALfloat
)device
->Frequency
;
528 bandsplit_init(&ambiup
->XOver
[i
], ratio
);
530 memset(ambiup
->Gains
, 0, sizeof(ambiup
->Gains
));
531 if(device
->Dry
.CoeffCount
> 0)
533 ALfloat encgains
[8][MAX_OUTPUT_CHANNELS
];
537 for(k
= 0;k
< COUNTOF(Ambi3DPoints
);k
++)
539 ALfloat coeffs
[MAX_AMBI_COEFFS
] = { 0.0f
};
540 CalcDirectionCoeffs(Ambi3DPoints
[k
], 0.0f
, coeffs
);
541 ComputeDryPanGains(&device
->Dry
, coeffs
, 1.0f
, encgains
[k
]);
544 /* Combine the matrices that do the in->virt and virt->out conversions
545 * so we get a single in->out conversion. NOTE: the Encoder matrix
546 * (encgains) and output are transposed, so the input channels line up
547 * with the rows and the output channels line up with the columns.
551 for(j
= 0;j
< device
->Dry
.NumChannels
;j
++)
554 for(k
= 0;k
< COUNTOF(Ambi3DDecoder
);k
++)
555 gain
+= Ambi3DDecoder
[k
][i
] * encgains
[k
][j
];
556 ambiup
->Gains
[i
][j
][HF_BAND
] = gain
* Ambi3DDecoderHFScale
[i
];
557 ambiup
->Gains
[i
][j
][LF_BAND
] = gain
;
565 ALsizei index
= GetChannelForACN(device
->Dry
, i
);
566 if(index
!= INVALID_UPSAMPLE_INDEX
)
568 ALfloat scale
= device
->Dry
.Ambi
.Map
[index
].Scale
;
569 ambiup
->Gains
[i
][index
][HF_BAND
] = scale
* ((i
==0) ? w_scale
: xyz_scale
);
570 ambiup
->Gains
[i
][index
][LF_BAND
] = scale
;
576 void ambiup_process(struct AmbiUpsampler
*ambiup
, ALfloat (*restrict OutBuffer
)[BUFFERSIZE
], ALsizei OutChannels
, const ALfloat (*restrict InSamples
)[BUFFERSIZE
], ALsizei SamplesToDo
)
582 bandsplit_process(&ambiup
->XOver
[i
],
583 ambiup
->Samples
[HF_BAND
], ambiup
->Samples
[LF_BAND
],
584 InSamples
[i
], SamplesToDo
587 for(j
= 0;j
< OutChannels
;j
++)
588 MixRowSamples(OutBuffer
[j
], ambiup
->Gains
[i
][j
],
589 ambiup
->Samples
, NUM_BANDS
, 0, SamplesToDo