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 /* NOTE: These are scale factors as applied to Ambisonics content. Decoder
118 * coefficients should be divided by these values to get proper N3D scalings.
120 const ALfloat N3D2N3DScale
[MAX_AMBI_COEFFS
] = {
121 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
,
122 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
124 const ALfloat SN3D2N3DScale
[MAX_AMBI_COEFFS
] = {
125 1.000000000f
, /* ACN 0 (W), sqrt(1) */
126 1.732050808f
, /* ACN 1 (Y), sqrt(3) */
127 1.732050808f
, /* ACN 2 (Z), sqrt(3) */
128 1.732050808f
, /* ACN 3 (X), sqrt(3) */
129 2.236067978f
, /* ACN 4 (V), sqrt(5) */
130 2.236067978f
, /* ACN 5 (T), sqrt(5) */
131 2.236067978f
, /* ACN 6 (R), sqrt(5) */
132 2.236067978f
, /* ACN 7 (S), sqrt(5) */
133 2.236067978f
, /* ACN 8 (U), sqrt(5) */
134 2.645751311f
, /* ACN 9 (Q), sqrt(7) */
135 2.645751311f
, /* ACN 10 (O), sqrt(7) */
136 2.645751311f
, /* ACN 11 (M), sqrt(7) */
137 2.645751311f
, /* ACN 12 (K), sqrt(7) */
138 2.645751311f
, /* ACN 13 (L), sqrt(7) */
139 2.645751311f
, /* ACN 14 (N), sqrt(7) */
140 2.645751311f
, /* ACN 15 (P), sqrt(7) */
142 const ALfloat FuMa2N3DScale
[MAX_AMBI_COEFFS
] = {
143 1.414213562f
, /* ACN 0 (W), sqrt(2) */
144 1.732050808f
, /* ACN 1 (Y), sqrt(3) */
145 1.732050808f
, /* ACN 2 (Z), sqrt(3) */
146 1.732050808f
, /* ACN 3 (X), sqrt(3) */
147 1.936491673f
, /* ACN 4 (V), sqrt(15)/2 */
148 1.936491673f
, /* ACN 5 (T), sqrt(15)/2 */
149 2.236067978f
, /* ACN 6 (R), sqrt(5) */
150 1.936491673f
, /* ACN 7 (S), sqrt(15)/2 */
151 1.936491673f
, /* ACN 8 (U), sqrt(15)/2 */
152 2.091650066f
, /* ACN 9 (Q), sqrt(35/8) */
153 1.972026594f
, /* ACN 10 (O), sqrt(35)/3 */
154 2.231093404f
, /* ACN 11 (M), sqrt(224/45) */
155 2.645751311f
, /* ACN 12 (K), sqrt(7) */
156 2.231093404f
, /* ACN 13 (L), sqrt(224/45) */
157 1.972026594f
, /* ACN 14 (N), sqrt(35)/3 */
158 2.091650066f
, /* ACN 15 (P), sqrt(35/8) */
166 /* These points are in AL coordinates! */
167 static const ALfloat Ambi3DPoints
[8][3] = {
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
},
173 { 0.577350269f
, -0.577350269f
, -0.577350269f
},
174 { -0.577350269f
, -0.577350269f
, 0.577350269f
},
175 { 0.577350269f
, -0.577350269f
, 0.577350269f
},
177 static const ALfloat Ambi3DDecoder
[8][MAX_AMBI_COEFFS
] = {
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
},
183 { 0.125f
, -0.125f
, -0.125f
, 0.125f
},
184 { 0.125f
, 0.125f
, -0.125f
, -0.125f
},
185 { 0.125f
, -0.125f
, -0.125f
, -0.125f
},
187 static const ALfloat Ambi3DDecoderHFScale
[MAX_AMBI_COEFFS
] = {
189 1.15470054f
, 1.15470054f
, 1.15470054f
193 /* NOTE: BandSplitter filters are unused with single-band decoding */
194 typedef struct BFormatDec
{
195 ALuint Enabled
; /* Bitfield of enabled channels. */
198 alignas(16) ALfloat Dual
[MAX_OUTPUT_CHANNELS
][NUM_BANDS
][MAX_AMBI_COEFFS
];
199 alignas(16) ALfloat Single
[MAX_OUTPUT_CHANNELS
][MAX_AMBI_COEFFS
];
202 BandSplitter XOver
[MAX_AMBI_COEFFS
];
204 ALfloat (*Samples
)[BUFFERSIZE
];
205 /* These two alias into Samples */
206 ALfloat (*SamplesHF
)[BUFFERSIZE
];
207 ALfloat (*SamplesLF
)[BUFFERSIZE
];
209 alignas(16) ALfloat ChannelMix
[BUFFERSIZE
];
213 ALfloat Gains
[NUM_BANDS
];
220 BFormatDec
*bformatdec_alloc()
222 return al_calloc(16, sizeof(BFormatDec
));
225 void bformatdec_free(BFormatDec
**dec
)
229 al_free((*dec
)->Samples
);
230 (*dec
)->Samples
= NULL
;
231 (*dec
)->SamplesHF
= NULL
;
232 (*dec
)->SamplesLF
= NULL
;
239 void bformatdec_reset(BFormatDec
*dec
, const AmbDecConf
*conf
, ALsizei chancount
, ALuint srate
, const ALsizei chanmap
[MAX_OUTPUT_CHANNELS
])
241 static const ALsizei map2DTo3D
[MAX_AMBI2D_COEFFS
] = {
244 const ALfloat
*coeff_scale
= N3D2N3DScale
;
249 al_free(dec
->Samples
);
251 dec
->SamplesHF
= NULL
;
252 dec
->SamplesLF
= NULL
;
254 dec
->NumChannels
= chancount
;
255 dec
->Samples
= al_calloc(16, dec
->NumChannels
*2 * sizeof(dec
->Samples
[0]));
256 dec
->SamplesHF
= dec
->Samples
;
257 dec
->SamplesLF
= dec
->SamplesHF
+ dec
->NumChannels
;
260 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
261 dec
->Enabled
|= 1 << chanmap
[i
];
263 if(conf
->CoeffScale
== ADS_SN3D
)
264 coeff_scale
= SN3D2N3DScale
;
265 else if(conf
->CoeffScale
== ADS_FuMa
)
266 coeff_scale
= FuMa2N3DScale
;
268 memset(dec
->UpSampler
, 0, sizeof(dec
->UpSampler
));
269 ratio
= 400.0f
/ (ALfloat
)srate
;
271 bandsplit_init(&dec
->UpSampler
[i
].XOver
, ratio
);
272 if((conf
->ChanMask
&AMBI_PERIPHONIC_MASK
))
276 dec
->UpSampler
[0].Gains
[HF_BAND
] = (conf
->ChanMask
> 0x1ff) ? W_SCALE_3H3P
:
277 (conf
->ChanMask
> 0xf) ? W_SCALE_2H2P
: 1.0f
;
278 dec
->UpSampler
[0].Gains
[LF_BAND
] = 1.0f
;
281 dec
->UpSampler
[i
].Gains
[HF_BAND
] = (conf
->ChanMask
> 0x1ff) ? XYZ_SCALE_3H3P
:
282 (conf
->ChanMask
> 0xf) ? XYZ_SCALE_2H2P
: 1.0f
;
283 dec
->UpSampler
[i
].Gains
[LF_BAND
] = 1.0f
;
290 dec
->UpSampler
[0].Gains
[HF_BAND
] = (conf
->ChanMask
> 0x1ff) ? W_SCALE_3H0P
:
291 (conf
->ChanMask
> 0xf) ? W_SCALE_2H0P
: 1.0f
;
292 dec
->UpSampler
[0].Gains
[LF_BAND
] = 1.0f
;
295 dec
->UpSampler
[i
].Gains
[HF_BAND
] = (conf
->ChanMask
> 0x1ff) ? XYZ_SCALE_3H0P
:
296 (conf
->ChanMask
> 0xf) ? XYZ_SCALE_2H0P
: 1.0f
;
297 dec
->UpSampler
[i
].Gains
[LF_BAND
] = 1.0f
;
299 dec
->UpSampler
[3].Gains
[HF_BAND
] = 0.0f
;
300 dec
->UpSampler
[3].Gains
[LF_BAND
] = 0.0f
;
303 memset(&dec
->Matrix
, 0, sizeof(dec
->Matrix
));
304 if(conf
->FreqBands
== 1)
306 dec
->DualBand
= AL_FALSE
;
307 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
309 ALsizei chan
= chanmap
[i
];
315 for(j
= 0,k
= 0;j
< MAX_AMBI2D_COEFFS
;j
++)
317 ALsizei l
= map2DTo3D
[j
];
318 if(j
== 0) gain
= conf
->HFOrderGain
[0];
319 else if(j
== 1) gain
= conf
->HFOrderGain
[1];
320 else if(j
== 3) gain
= conf
->HFOrderGain
[2];
321 else if(j
== 5) gain
= conf
->HFOrderGain
[3];
322 if((conf
->ChanMask
&(1<<l
)))
323 dec
->Matrix
.Single
[chan
][j
] = conf
->HFMatrix
[i
][k
++] / coeff_scale
[l
] *
329 for(j
= 0,k
= 0;j
< MAX_AMBI_COEFFS
;j
++)
331 if(j
== 0) gain
= conf
->HFOrderGain
[0];
332 else if(j
== 1) gain
= conf
->HFOrderGain
[1];
333 else if(j
== 4) gain
= conf
->HFOrderGain
[2];
334 else if(j
== 9) gain
= conf
->HFOrderGain
[3];
335 if((conf
->ChanMask
&(1<<j
)))
336 dec
->Matrix
.Single
[chan
][j
] = conf
->HFMatrix
[i
][k
++] / coeff_scale
[j
] *
344 dec
->DualBand
= AL_TRUE
;
346 ratio
= conf
->XOverFreq
/ (ALfloat
)srate
;
347 for(i
= 0;i
< MAX_AMBI_COEFFS
;i
++)
348 bandsplit_init(&dec
->XOver
[i
], ratio
);
350 ratio
= powf(10.0f
, conf
->XOverRatio
/ 40.0f
);
351 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
353 ALsizei chan
= chanmap
[i
];
359 for(j
= 0,k
= 0;j
< MAX_AMBI2D_COEFFS
;j
++)
361 ALsizei l
= map2DTo3D
[j
];
362 if(j
== 0) gain
= conf
->HFOrderGain
[0] * ratio
;
363 else if(j
== 1) gain
= conf
->HFOrderGain
[1] * ratio
;
364 else if(j
== 3) gain
= conf
->HFOrderGain
[2] * ratio
;
365 else if(j
== 5) gain
= conf
->HFOrderGain
[3] * ratio
;
366 if((conf
->ChanMask
&(1<<l
)))
367 dec
->Matrix
.Dual
[chan
][HF_BAND
][j
] = conf
->HFMatrix
[i
][k
++] /
368 coeff_scale
[l
] * gain
;
370 for(j
= 0,k
= 0;j
< MAX_AMBI2D_COEFFS
;j
++)
372 ALsizei l
= map2DTo3D
[j
];
373 if(j
== 0) gain
= conf
->LFOrderGain
[0] / ratio
;
374 else if(j
== 1) gain
= conf
->LFOrderGain
[1] / ratio
;
375 else if(j
== 3) gain
= conf
->LFOrderGain
[2] / ratio
;
376 else if(j
== 5) gain
= conf
->LFOrderGain
[3] / ratio
;
377 if((conf
->ChanMask
&(1<<l
)))
378 dec
->Matrix
.Dual
[chan
][LF_BAND
][j
] = conf
->LFMatrix
[i
][k
++] /
379 coeff_scale
[l
] * gain
;
384 for(j
= 0,k
= 0;j
< MAX_AMBI_COEFFS
;j
++)
386 if(j
== 0) gain
= conf
->HFOrderGain
[0] * ratio
;
387 else if(j
== 1) gain
= conf
->HFOrderGain
[1] * ratio
;
388 else if(j
== 4) gain
= conf
->HFOrderGain
[2] * ratio
;
389 else if(j
== 9) gain
= conf
->HFOrderGain
[3] * ratio
;
390 if((conf
->ChanMask
&(1<<j
)))
391 dec
->Matrix
.Dual
[chan
][HF_BAND
][j
] = conf
->HFMatrix
[i
][k
++] /
392 coeff_scale
[j
] * gain
;
394 for(j
= 0,k
= 0;j
< MAX_AMBI_COEFFS
;j
++)
396 if(j
== 0) gain
= conf
->LFOrderGain
[0] / ratio
;
397 else if(j
== 1) gain
= conf
->LFOrderGain
[1] / ratio
;
398 else if(j
== 4) gain
= conf
->LFOrderGain
[2] / ratio
;
399 else if(j
== 9) gain
= conf
->LFOrderGain
[3] / ratio
;
400 if((conf
->ChanMask
&(1<<j
)))
401 dec
->Matrix
.Dual
[chan
][LF_BAND
][j
] = conf
->LFMatrix
[i
][k
++] /
402 coeff_scale
[j
] * gain
;
410 void bformatdec_process(struct BFormatDec
*dec
, ALfloat (*restrict OutBuffer
)[BUFFERSIZE
], ALsizei OutChannels
, const ALfloat (*restrict InSamples
)[BUFFERSIZE
], ALsizei SamplesToDo
)
414 OutBuffer
= ASSUME_ALIGNED(OutBuffer
, 16);
417 for(i
= 0;i
< dec
->NumChannels
;i
++)
418 bandsplit_process(&dec
->XOver
[i
], dec
->SamplesHF
[i
], dec
->SamplesLF
[i
],
419 InSamples
[i
], SamplesToDo
);
421 for(chan
= 0;chan
< OutChannels
;chan
++)
423 if(!(dec
->Enabled
&(1<<chan
)))
426 memset(dec
->ChannelMix
, 0, SamplesToDo
*sizeof(ALfloat
));
427 MixRowSamples(dec
->ChannelMix
, dec
->Matrix
.Dual
[chan
][HF_BAND
],
428 dec
->SamplesHF
, dec
->NumChannels
, 0, SamplesToDo
430 MixRowSamples(dec
->ChannelMix
, dec
->Matrix
.Dual
[chan
][LF_BAND
],
431 dec
->SamplesLF
, dec
->NumChannels
, 0, SamplesToDo
434 for(i
= 0;i
< SamplesToDo
;i
++)
435 OutBuffer
[chan
][i
] += dec
->ChannelMix
[i
];
440 for(chan
= 0;chan
< OutChannels
;chan
++)
442 if(!(dec
->Enabled
&(1<<chan
)))
445 memset(dec
->ChannelMix
, 0, SamplesToDo
*sizeof(ALfloat
));
446 MixRowSamples(dec
->ChannelMix
, dec
->Matrix
.Single
[chan
], InSamples
,
447 dec
->NumChannels
, 0, SamplesToDo
);
449 for(i
= 0;i
< SamplesToDo
;i
++)
450 OutBuffer
[chan
][i
] += dec
->ChannelMix
[i
];
456 void bformatdec_upSample(struct BFormatDec
*dec
, ALfloat (*restrict OutBuffer
)[BUFFERSIZE
], const ALfloat (*restrict InSamples
)[BUFFERSIZE
], ALsizei InChannels
, ALsizei SamplesToDo
)
460 /* This up-sampler leverages the differences observed in dual-band second-
461 * and third-order decoder matrices compared to first-order. For the same
462 * output channel configuration, the low-frequency matrix has identical
463 * coefficients in the shared input channels, while the high-frequency
464 * matrix has extra scalars applied to the W channel and X/Y/Z channels.
465 * Mixing the first-order content into the higher-order stream with the
466 * appropriate counter-scales applied to the HF response results in the
467 * subsequent higher-order decode generating the same response as a first-
470 for(i
= 0;i
< InChannels
;i
++)
472 /* First, split the first-order components into low and high frequency
475 bandsplit_process(&dec
->UpSampler
[i
].XOver
,
476 dec
->Samples
[HF_BAND
], dec
->Samples
[LF_BAND
],
477 InSamples
[i
], SamplesToDo
480 /* Now write each band to the output. */
481 MixRowSamples(OutBuffer
[i
], dec
->UpSampler
[i
].Gains
,
482 dec
->Samples
, NUM_BANDS
, 0, SamplesToDo
488 #define INVALID_UPSAMPLE_INDEX INT_MAX
490 static ALsizei
GetACNIndex(const BFChannelConfig
*chans
, ALsizei numchans
, ALsizei acn
)
493 for(i
= 0;i
< numchans
;i
++)
495 if(chans
[i
].Index
== acn
)
498 return INVALID_UPSAMPLE_INDEX
;
500 #define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a))
502 typedef struct AmbiUpsampler
{
503 alignas(16) ALfloat Samples
[NUM_BANDS
][BUFFERSIZE
];
505 BandSplitter XOver
[4];
507 ALfloat Gains
[4][MAX_OUTPUT_CHANNELS
][NUM_BANDS
];
510 AmbiUpsampler
*ambiup_alloc()
512 return al_calloc(16, sizeof(AmbiUpsampler
));
515 void ambiup_free(struct AmbiUpsampler
**ambiup
)
524 void ambiup_reset(struct AmbiUpsampler
*ambiup
, const ALCdevice
*device
, ALfloat w_scale
, ALfloat xyz_scale
)
529 ratio
= 400.0f
/ (ALfloat
)device
->Frequency
;
531 bandsplit_init(&ambiup
->XOver
[i
], ratio
);
533 memset(ambiup
->Gains
, 0, sizeof(ambiup
->Gains
));
534 if(device
->Dry
.CoeffCount
> 0)
536 ALfloat encgains
[8][MAX_OUTPUT_CHANNELS
];
540 for(k
= 0;k
< COUNTOF(Ambi3DPoints
);k
++)
542 ALfloat coeffs
[MAX_AMBI_COEFFS
] = { 0.0f
};
543 CalcDirectionCoeffs(Ambi3DPoints
[k
], 0.0f
, coeffs
);
544 ComputeDryPanGains(&device
->Dry
, coeffs
, 1.0f
, encgains
[k
]);
547 /* Combine the matrices that do the in->virt and virt->out conversions
548 * so we get a single in->out conversion. NOTE: the Encoder matrix
549 * (encgains) and output are transposed, so the input channels line up
550 * with the rows and the output channels line up with the columns.
554 for(j
= 0;j
< device
->Dry
.NumChannels
;j
++)
557 for(k
= 0;k
< COUNTOF(Ambi3DDecoder
);k
++)
558 gain
+= Ambi3DDecoder
[k
][i
] * encgains
[k
][j
];
559 ambiup
->Gains
[i
][j
][HF_BAND
] = gain
* Ambi3DDecoderHFScale
[i
];
560 ambiup
->Gains
[i
][j
][LF_BAND
] = gain
;
568 ALsizei index
= GetChannelForACN(device
->Dry
, i
);
569 if(index
!= INVALID_UPSAMPLE_INDEX
)
571 ALfloat scale
= device
->Dry
.Ambi
.Map
[index
].Scale
;
572 ambiup
->Gains
[i
][index
][HF_BAND
] = scale
* ((i
==0) ? w_scale
: xyz_scale
);
573 ambiup
->Gains
[i
][index
][LF_BAND
] = scale
;
579 void ambiup_process(struct AmbiUpsampler
*ambiup
, ALfloat (*restrict OutBuffer
)[BUFFERSIZE
], ALsizei OutChannels
, const ALfloat (*restrict InSamples
)[BUFFERSIZE
], ALsizei SamplesToDo
)
585 bandsplit_process(&ambiup
->XOver
[i
],
586 ambiup
->Samples
[HF_BAND
], ambiup
->Samples
[LF_BAND
],
587 InSamples
[i
], SamplesToDo
590 for(j
= 0;j
< OutChannels
;j
++)
591 MixRowSamples(OutBuffer
[j
], ambiup
->Gains
[i
][j
],
592 ambiup
->Samples
, NUM_BANDS
, 0, SamplesToDo