4 #include "bformatdec.h"
6 #include "mixer_defs.h"
14 void bandsplit_init(BandSplitter
*splitter
, ALfloat freq_mult
)
16 ALfloat w
= freq_mult
* 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 static const ALfloat UnitScale
[MAX_AMBI_COEFFS
] = {
79 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
,
80 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
82 static const ALfloat SN3D2N3DScale
[MAX_AMBI_COEFFS
] = {
83 1.000000000f
, /* ACN 0 (W), sqrt(1) */
84 1.732050808f
, /* ACN 1 (Y), sqrt(3) */
85 1.732050808f
, /* ACN 2 (Z), sqrt(3) */
86 1.732050808f
, /* ACN 3 (X), sqrt(3) */
87 2.236067978f
, /* ACN 4 (V), sqrt(5) */
88 2.236067978f
, /* ACN 5 (T), sqrt(5) */
89 2.236067978f
, /* ACN 6 (R), sqrt(5) */
90 2.236067978f
, /* ACN 7 (S), sqrt(5) */
91 2.236067978f
, /* ACN 8 (U), sqrt(5) */
92 2.645751311f
, /* ACN 9 (Q), sqrt(7) */
93 2.645751311f
, /* ACN 10 (O), sqrt(7) */
94 2.645751311f
, /* ACN 11 (M), sqrt(7) */
95 2.645751311f
, /* ACN 12 (K), sqrt(7) */
96 2.645751311f
, /* ACN 13 (L), sqrt(7) */
97 2.645751311f
, /* ACN 14 (N), sqrt(7) */
98 2.645751311f
, /* ACN 15 (P), sqrt(7) */
100 static const ALfloat FuMa2N3DScale
[MAX_AMBI_COEFFS
] = {
101 1.414213562f
, /* ACN 0 (W), sqrt(2) */
102 1.732050808f
, /* ACN 1 (Y), sqrt(3) */
103 1.732050808f
, /* ACN 2 (Z), sqrt(3) */
104 1.732050808f
, /* ACN 3 (X), sqrt(3) */
105 1.936491673f
, /* ACN 4 (V), sqrt(15)/2 */
106 1.936491673f
, /* ACN 5 (T), sqrt(15)/2 */
107 2.236067978f
, /* ACN 6 (R), sqrt(5) */
108 1.936491673f
, /* ACN 7 (S), sqrt(15)/2 */
109 1.936491673f
, /* ACN 8 (U), sqrt(15)/2 */
110 2.091650066f
, /* ACN 9 (Q), sqrt(35/8) */
111 1.972026594f
, /* ACN 10 (O), sqrt(35)/3 */
112 2.231093404f
, /* ACN 11 (M), sqrt(224/45) */
113 2.645751311f
, /* ACN 12 (K), sqrt(7) */
114 2.231093404f
, /* ACN 13 (L), sqrt(224/45) */
115 1.972026594f
, /* ACN 14 (N), sqrt(35)/3 */
116 2.091650066f
, /* ACN 15 (P), sqrt(35/8) */
126 /* These points are in AL coordinates! */
127 static const ALfloat Ambi3DPoints
[8][3] = {
128 { -0.577350269f
, 0.577350269f
, -0.577350269f
},
129 { 0.577350269f
, 0.577350269f
, -0.577350269f
},
130 { -0.577350269f
, 0.577350269f
, 0.577350269f
},
131 { 0.577350269f
, 0.577350269f
, 0.577350269f
},
132 { -0.577350269f
, -0.577350269f
, -0.577350269f
},
133 { 0.577350269f
, -0.577350269f
, -0.577350269f
},
134 { -0.577350269f
, -0.577350269f
, 0.577350269f
},
135 { 0.577350269f
, -0.577350269f
, 0.577350269f
},
137 static const ALfloat Ambi3DDecoder
[8][FB_Max
][MAX_AMBI_COEFFS
] = {
138 { { 0.25f
, 0.1443375672f
, 0.1443375672f
, 0.1443375672f
}, { 0.125f
, 0.125f
, 0.125f
, 0.125f
} },
139 { { 0.25f
, -0.1443375672f
, 0.1443375672f
, 0.1443375672f
}, { 0.125f
, -0.125f
, 0.125f
, 0.125f
} },
140 { { 0.25f
, 0.1443375672f
, 0.1443375672f
, -0.1443375672f
}, { 0.125f
, 0.125f
, 0.125f
, -0.125f
} },
141 { { 0.25f
, -0.1443375672f
, 0.1443375672f
, -0.1443375672f
}, { 0.125f
, -0.125f
, 0.125f
, -0.125f
} },
142 { { 0.25f
, 0.1443375672f
, -0.1443375672f
, 0.1443375672f
}, { 0.125f
, 0.125f
, -0.125f
, 0.125f
} },
143 { { 0.25f
, -0.1443375672f
, -0.1443375672f
, 0.1443375672f
}, { 0.125f
, -0.125f
, -0.125f
, 0.125f
} },
144 { { 0.25f
, 0.1443375672f
, -0.1443375672f
, -0.1443375672f
}, { 0.125f
, 0.125f
, -0.125f
, -0.125f
} },
145 { { 0.25f
, -0.1443375672f
, -0.1443375672f
, -0.1443375672f
}, { 0.125f
, -0.125f
, -0.125f
, -0.125f
} },
149 static RowMixerFunc MixMatrixRow
= MixRow_C
;
152 static alonce_flag bformatdec_inited
= AL_ONCE_FLAG_INIT
;
154 static void init_bformatdec(void)
156 MixMatrixRow
= SelectRowMixer();
160 /* NOTE: BandSplitter filters are unused with single-band decoding */
161 typedef struct BFormatDec
{
162 ALboolean Enabled
[MAX_OUTPUT_CHANNELS
];
165 alignas(16) ALfloat Dual
[MAX_OUTPUT_CHANNELS
][FB_Max
][MAX_AMBI_COEFFS
];
166 alignas(16) ALfloat Single
[MAX_OUTPUT_CHANNELS
][MAX_AMBI_COEFFS
];
169 BandSplitter XOver
[MAX_AMBI_COEFFS
];
171 ALfloat (*Samples
)[BUFFERSIZE
];
172 /* These two alias into Samples */
173 ALfloat (*SamplesHF
)[BUFFERSIZE
];
174 ALfloat (*SamplesLF
)[BUFFERSIZE
];
176 alignas(16) ALfloat ChannelMix
[BUFFERSIZE
];
180 ALfloat Gains
[FB_Max
];
187 BFormatDec
*bformatdec_alloc()
189 alcall_once(&bformatdec_inited
, init_bformatdec
);
190 return al_calloc(16, sizeof(BFormatDec
));
193 void bformatdec_free(BFormatDec
*dec
)
197 al_free(dec
->Samples
);
199 dec
->SamplesHF
= NULL
;
200 dec
->SamplesLF
= NULL
;
202 memset(dec
, 0, sizeof(*dec
));
207 void bformatdec_reset(BFormatDec
*dec
, const AmbDecConf
*conf
, ALsizei chancount
, ALuint srate
, const ALsizei chanmap
[MAX_OUTPUT_CHANNELS
])
209 static const ALsizei map2DTo3D
[MAX_AMBI2D_COEFFS
] = {
212 const ALfloat
*coeff_scale
= UnitScale
;
217 al_free(dec
->Samples
);
219 dec
->SamplesHF
= NULL
;
220 dec
->SamplesLF
= NULL
;
222 dec
->NumChannels
= chancount
;
223 dec
->Samples
= al_calloc(16, dec
->NumChannels
*2 * sizeof(dec
->Samples
[0]));
224 dec
->SamplesHF
= dec
->Samples
;
225 dec
->SamplesLF
= dec
->SamplesHF
+ dec
->NumChannels
;
227 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
228 dec
->Enabled
[i
] = AL_FALSE
;
229 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
230 dec
->Enabled
[chanmap
[i
]] = AL_TRUE
;
232 if(conf
->CoeffScale
== ADS_SN3D
)
233 coeff_scale
= SN3D2N3DScale
;
234 else if(conf
->CoeffScale
== ADS_FuMa
)
235 coeff_scale
= FuMa2N3DScale
;
237 memset(dec
->UpSampler
, 0, sizeof(dec
->UpSampler
));
238 ratio
= 400.0f
/ (ALfloat
)srate
;
240 bandsplit_init(&dec
->UpSampler
[i
].XOver
, ratio
);
241 if((conf
->ChanMask
&AMBI_PERIPHONIC_MASK
))
245 dec
->UpSampler
[0].Gains
[FB_HighFreq
] = (dec
->NumChannels
> 9) ? W_SCALE3D_THIRD
:
246 (dec
->NumChannels
> 4) ? W_SCALE3D_SECOND
: 1.0f
;
247 dec
->UpSampler
[0].Gains
[FB_LowFreq
] = 1.0f
;
250 dec
->UpSampler
[i
].Gains
[FB_HighFreq
] = (dec
->NumChannels
> 9) ? XYZ_SCALE3D_THIRD
:
251 (dec
->NumChannels
> 4) ? XYZ_SCALE3D_SECOND
: 1.0f
;
252 dec
->UpSampler
[i
].Gains
[FB_LowFreq
] = 1.0f
;
259 dec
->UpSampler
[0].Gains
[FB_HighFreq
] = (dec
->NumChannels
> 5) ? W_SCALE2D_THIRD
:
260 (dec
->NumChannels
> 3) ? W_SCALE2D_SECOND
: 1.0f
;
261 dec
->UpSampler
[0].Gains
[FB_LowFreq
] = 1.0f
;
264 dec
->UpSampler
[i
].Gains
[FB_HighFreq
] = (dec
->NumChannels
> 5) ? XYZ_SCALE2D_THIRD
:
265 (dec
->NumChannels
> 3) ? XYZ_SCALE2D_SECOND
: 1.0f
;
266 dec
->UpSampler
[i
].Gains
[FB_LowFreq
] = 1.0f
;
268 dec
->UpSampler
[3].Gains
[FB_HighFreq
] = 0.0f
;
269 dec
->UpSampler
[3].Gains
[FB_LowFreq
] = 0.0f
;
272 memset(&dec
->Matrix
, 0, sizeof(dec
->Matrix
));
273 if(conf
->FreqBands
== 1)
275 dec
->DualBand
= AL_FALSE
;
276 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
278 ALsizei chan
= chanmap
[i
];
284 for(j
= 0,k
= 0;j
< MAX_AMBI2D_COEFFS
;j
++)
286 ALsizei l
= map2DTo3D
[j
];
287 if(j
== 0) gain
= conf
->HFOrderGain
[0];
288 else if(j
== 1) gain
= conf
->HFOrderGain
[1];
289 else if(j
== 3) gain
= conf
->HFOrderGain
[2];
290 else if(j
== 5) gain
= conf
->HFOrderGain
[3];
291 if((conf
->ChanMask
&(1<<l
)))
292 dec
->Matrix
.Single
[chan
][j
] = conf
->HFMatrix
[i
][k
++] / coeff_scale
[l
] *
298 for(j
= 0,k
= 0;j
< MAX_AMBI_COEFFS
;j
++)
300 if(j
== 0) gain
= conf
->HFOrderGain
[0];
301 else if(j
== 1) gain
= conf
->HFOrderGain
[1];
302 else if(j
== 4) gain
= conf
->HFOrderGain
[2];
303 else if(j
== 9) gain
= conf
->HFOrderGain
[3];
304 if((conf
->ChanMask
&(1<<j
)))
305 dec
->Matrix
.Single
[chan
][j
] = conf
->HFMatrix
[i
][k
++] / coeff_scale
[j
] *
313 dec
->DualBand
= AL_TRUE
;
315 ratio
= conf
->XOverFreq
/ (ALfloat
)srate
;
316 for(i
= 0;i
< MAX_AMBI_COEFFS
;i
++)
317 bandsplit_init(&dec
->XOver
[i
], ratio
);
319 ratio
= powf(10.0f
, conf
->XOverRatio
/ 40.0f
);
320 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
322 ALsizei chan
= chanmap
[i
];
328 for(j
= 0,k
= 0;j
< MAX_AMBI2D_COEFFS
;j
++)
330 ALsizei l
= map2DTo3D
[j
];
331 if(j
== 0) gain
= conf
->HFOrderGain
[0] * ratio
;
332 else if(j
== 1) gain
= conf
->HFOrderGain
[1] * ratio
;
333 else if(j
== 3) gain
= conf
->HFOrderGain
[2] * ratio
;
334 else if(j
== 5) gain
= conf
->HFOrderGain
[3] * ratio
;
335 if((conf
->ChanMask
&(1<<l
)))
336 dec
->Matrix
.Dual
[chan
][FB_HighFreq
][j
] = conf
->HFMatrix
[i
][k
++] /
337 coeff_scale
[l
] * gain
;
339 for(j
= 0,k
= 0;j
< MAX_AMBI2D_COEFFS
;j
++)
341 ALsizei l
= map2DTo3D
[j
];
342 if(j
== 0) gain
= conf
->LFOrderGain
[0] / ratio
;
343 else if(j
== 1) gain
= conf
->LFOrderGain
[1] / ratio
;
344 else if(j
== 3) gain
= conf
->LFOrderGain
[2] / ratio
;
345 else if(j
== 5) gain
= conf
->LFOrderGain
[3] / ratio
;
346 if((conf
->ChanMask
&(1<<l
)))
347 dec
->Matrix
.Dual
[chan
][FB_LowFreq
][j
] = conf
->LFMatrix
[i
][k
++] /
348 coeff_scale
[l
] * gain
;
353 for(j
= 0,k
= 0;j
< MAX_AMBI_COEFFS
;j
++)
355 if(j
== 0) gain
= conf
->HFOrderGain
[0] * ratio
;
356 else if(j
== 1) gain
= conf
->HFOrderGain
[1] * ratio
;
357 else if(j
== 4) gain
= conf
->HFOrderGain
[2] * ratio
;
358 else if(j
== 9) gain
= conf
->HFOrderGain
[3] * ratio
;
359 if((conf
->ChanMask
&(1<<j
)))
360 dec
->Matrix
.Dual
[chan
][FB_HighFreq
][j
] = conf
->HFMatrix
[i
][k
++] /
361 coeff_scale
[j
] * gain
;
363 for(j
= 0,k
= 0;j
< MAX_AMBI_COEFFS
;j
++)
365 if(j
== 0) gain
= conf
->LFOrderGain
[0] / ratio
;
366 else if(j
== 1) gain
= conf
->LFOrderGain
[1] / ratio
;
367 else if(j
== 4) gain
= conf
->LFOrderGain
[2] / ratio
;
368 else if(j
== 9) gain
= conf
->LFOrderGain
[3] / ratio
;
369 if((conf
->ChanMask
&(1<<j
)))
370 dec
->Matrix
.Dual
[chan
][FB_LowFreq
][j
] = conf
->LFMatrix
[i
][k
++] /
371 coeff_scale
[j
] * gain
;
379 void bformatdec_process(struct BFormatDec
*dec
, ALfloat (*restrict OutBuffer
)[BUFFERSIZE
], ALsizei OutChannels
, const ALfloat (*restrict InSamples
)[BUFFERSIZE
], ALsizei SamplesToDo
)
383 OutBuffer
= ASSUME_ALIGNED(OutBuffer
, 16);
386 for(i
= 0;i
< dec
->NumChannels
;i
++)
387 bandsplit_process(&dec
->XOver
[i
], dec
->SamplesHF
[i
], dec
->SamplesLF
[i
],
388 InSamples
[i
], SamplesToDo
);
390 for(chan
= 0;chan
< OutChannels
;chan
++)
392 if(!dec
->Enabled
[chan
])
395 memset(dec
->ChannelMix
, 0, SamplesToDo
*sizeof(ALfloat
));
396 MixMatrixRow(dec
->ChannelMix
, dec
->Matrix
.Dual
[chan
][FB_HighFreq
],
397 SAFE_CONST(ALfloatBUFFERSIZE
*,dec
->SamplesHF
), dec
->NumChannels
, 0,
400 MixMatrixRow(dec
->ChannelMix
, dec
->Matrix
.Dual
[chan
][FB_LowFreq
],
401 SAFE_CONST(ALfloatBUFFERSIZE
*,dec
->SamplesLF
), dec
->NumChannels
, 0,
405 for(i
= 0;i
< SamplesToDo
;i
++)
406 OutBuffer
[chan
][i
] += dec
->ChannelMix
[i
];
411 for(chan
= 0;chan
< OutChannels
;chan
++)
413 if(!dec
->Enabled
[chan
])
416 memset(dec
->ChannelMix
, 0, SamplesToDo
*sizeof(ALfloat
));
417 MixMatrixRow(dec
->ChannelMix
, dec
->Matrix
.Single
[chan
], InSamples
,
418 dec
->NumChannels
, 0, SamplesToDo
);
420 for(i
= 0;i
< SamplesToDo
;i
++)
421 OutBuffer
[chan
][i
] += dec
->ChannelMix
[i
];
427 void bformatdec_upSample(struct BFormatDec
*dec
, ALfloat (*restrict OutBuffer
)[BUFFERSIZE
], const ALfloat (*restrict InSamples
)[BUFFERSIZE
], ALsizei InChannels
, ALsizei SamplesToDo
)
431 /* This up-sampler leverages the differences observed in dual-band second-
432 * and third-order decoder matrices compared to first-order. For the same
433 * output channel configuration, the low-frequency matrix has identical
434 * coefficients in the shared input channels, while the high-frequency
435 * matrix has extra scalars applied to the W channel and X/Y/Z channels.
436 * Mixing the first-order content into the higher-order stream with the
437 * appropriate counter-scales applied to the HF response results in the
438 * subsequent higher-order decode generating the same response as a first-
441 for(i
= 0;i
< InChannels
;i
++)
443 /* First, split the first-order components into low and high frequency
446 bandsplit_process(&dec
->UpSampler
[i
].XOver
,
447 dec
->Samples
[FB_HighFreq
], dec
->Samples
[FB_LowFreq
],
448 InSamples
[i
], SamplesToDo
451 /* Now write each band to the output. */
452 MixMatrixRow(OutBuffer
[i
], dec
->UpSampler
[i
].Gains
,
453 SAFE_CONST(ALfloatBUFFERSIZE
*,dec
->Samples
), FB_Max
, 0,
460 #define INVALID_UPSAMPLE_INDEX INT_MAX
462 static ALsizei
GetACNIndex(const BFChannelConfig
*chans
, ALsizei numchans
, ALsizei acn
)
465 for(i
= 0;i
< numchans
;i
++)
467 if(chans
[i
].Index
== acn
)
470 return INVALID_UPSAMPLE_INDEX
;
472 #define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a))
474 typedef struct AmbiUpsampler
{
475 alignas(16) ALfloat Samples
[FB_Max
][BUFFERSIZE
];
477 BandSplitter XOver
[4];
479 ALfloat Gains
[4][MAX_OUTPUT_CHANNELS
][FB_Max
];
482 AmbiUpsampler
*ambiup_alloc()
484 alcall_once(&bformatdec_inited
, init_bformatdec
);
485 return al_calloc(16, sizeof(AmbiUpsampler
));
488 void ambiup_free(struct AmbiUpsampler
*ambiup
)
493 void ambiup_reset(struct AmbiUpsampler
*ambiup
, const ALCdevice
*device
)
498 ratio
= 400.0f
/ (ALfloat
)device
->Frequency
;
500 bandsplit_init(&ambiup
->XOver
[i
], ratio
);
502 memset(ambiup
->Gains
, 0, sizeof(ambiup
->Gains
));
503 if(device
->Dry
.CoeffCount
> 0)
505 ALfloat encgains
[8][MAX_OUTPUT_CHANNELS
];
509 for(i
= 0;i
< COUNTOF(Ambi3DPoints
);i
++)
511 ALfloat coeffs
[MAX_AMBI_COEFFS
] = { 0.0f
};
512 CalcDirectionCoeffs(Ambi3DPoints
[i
], 0.0f
, coeffs
);
513 ComputePanningGains(device
->Dry
, coeffs
, 1.0f
, encgains
[i
]);
516 /* Combine the matrices that do the in->virt and virt->out conversions
517 * so we get a single in->out conversion. NOTE: the Encoder matrix
518 * (encgains) and output are transposed, so the input channels line up
519 * with the rows and the output channels line up with the columns.
523 for(j
= 0;j
< device
->Dry
.NumChannels
;j
++)
525 ALfloat hfgain
=0.0f
, lfgain
=0.0f
;
526 for(k
= 0;k
< COUNTOF(Ambi3DDecoder
);k
++)
528 hfgain
+= Ambi3DDecoder
[k
][FB_HighFreq
][i
]*encgains
[k
][j
];
529 lfgain
+= Ambi3DDecoder
[k
][FB_LowFreq
][i
]*encgains
[k
][j
];
531 ambiup
->Gains
[i
][j
][FB_HighFreq
] = hfgain
;
532 ambiup
->Gains
[i
][j
][FB_LowFreq
] = lfgain
;
538 /* Assumes full 3D/periphonic on the input and output mixes! */
539 ALfloat w_scale
= (device
->Dry
.NumChannels
> 9) ? W_SCALE3D_THIRD
:
540 (device
->Dry
.NumChannels
> 4) ? W_SCALE3D_SECOND
: 1.0f
;
541 ALfloat xyz_scale
= (device
->Dry
.NumChannels
> 9) ? XYZ_SCALE3D_THIRD
:
542 (device
->Dry
.NumChannels
> 4) ? XYZ_SCALE3D_SECOND
: 1.0f
;
545 ALsizei index
= GetChannelForACN(device
->Dry
, i
);
546 if(index
!= INVALID_UPSAMPLE_INDEX
)
548 ALfloat scale
= device
->Dry
.Ambi
.Map
[index
].Scale
;
549 ambiup
->Gains
[i
][index
][FB_HighFreq
] = scale
* ((i
==0) ? w_scale
: xyz_scale
);
550 ambiup
->Gains
[i
][index
][FB_LowFreq
] = scale
;
556 void ambiup_process(struct AmbiUpsampler
*ambiup
, ALfloat (*restrict OutBuffer
)[BUFFERSIZE
], ALsizei OutChannels
, const ALfloat (*restrict InSamples
)[BUFFERSIZE
], ALsizei SamplesToDo
)
562 bandsplit_process(&ambiup
->XOver
[i
],
563 ambiup
->Samples
[FB_HighFreq
], ambiup
->Samples
[FB_LowFreq
],
564 InSamples
[i
], SamplesToDo
567 for(j
= 0;j
< OutChannels
;j
++)
568 MixMatrixRow(OutBuffer
[j
], ambiup
->Gains
[i
][j
],
569 SAFE_CONST(ALfloatBUFFERSIZE
*,ambiup
->Samples
), FB_Max
, 0,