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) */
165 /* These points are in AL coordinates! */
166 static const ALfloat Ambi3DPoints
[8][3] = {
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
},
173 { -0.577350269f
, -0.577350269f
, 0.577350269f
},
174 { 0.577350269f
, -0.577350269f
, 0.577350269f
},
176 static const ALfloat Ambi3DDecoder
[8][FB_Max
][MAX_AMBI_COEFFS
] = {
177 { { 0.25f
, 0.1443375672f
, 0.1443375672f
, 0.1443375672f
}, { 0.125f
, 0.125f
, 0.125f
, 0.125f
} },
178 { { 0.25f
, -0.1443375672f
, 0.1443375672f
, 0.1443375672f
}, { 0.125f
, -0.125f
, 0.125f
, 0.125f
} },
179 { { 0.25f
, 0.1443375672f
, 0.1443375672f
, -0.1443375672f
}, { 0.125f
, 0.125f
, 0.125f
, -0.125f
} },
180 { { 0.25f
, -0.1443375672f
, 0.1443375672f
, -0.1443375672f
}, { 0.125f
, -0.125f
, 0.125f
, -0.125f
} },
181 { { 0.25f
, 0.1443375672f
, -0.1443375672f
, 0.1443375672f
}, { 0.125f
, 0.125f
, -0.125f
, 0.125f
} },
182 { { 0.25f
, -0.1443375672f
, -0.1443375672f
, 0.1443375672f
}, { 0.125f
, -0.125f
, -0.125f
, 0.125f
} },
183 { { 0.25f
, 0.1443375672f
, -0.1443375672f
, -0.1443375672f
}, { 0.125f
, 0.125f
, -0.125f
, -0.125f
} },
184 { { 0.25f
, -0.1443375672f
, -0.1443375672f
, -0.1443375672f
}, { 0.125f
, -0.125f
, -0.125f
, -0.125f
} },
188 /* NOTE: BandSplitter filters are unused with single-band decoding */
189 typedef struct BFormatDec
{
190 ALboolean Enabled
[MAX_OUTPUT_CHANNELS
];
193 alignas(16) ALfloat Dual
[MAX_OUTPUT_CHANNELS
][FB_Max
][MAX_AMBI_COEFFS
];
194 alignas(16) ALfloat Single
[MAX_OUTPUT_CHANNELS
][MAX_AMBI_COEFFS
];
197 BandSplitter XOver
[MAX_AMBI_COEFFS
];
199 ALfloat (*Samples
)[BUFFERSIZE
];
200 /* These two alias into Samples */
201 ALfloat (*SamplesHF
)[BUFFERSIZE
];
202 ALfloat (*SamplesLF
)[BUFFERSIZE
];
204 alignas(16) ALfloat ChannelMix
[BUFFERSIZE
];
208 ALfloat Gains
[FB_Max
];
215 BFormatDec
*bformatdec_alloc()
217 return al_calloc(16, sizeof(BFormatDec
));
220 void bformatdec_free(BFormatDec
*dec
)
224 al_free(dec
->Samples
);
226 dec
->SamplesHF
= NULL
;
227 dec
->SamplesLF
= NULL
;
229 memset(dec
, 0, sizeof(*dec
));
234 void bformatdec_reset(BFormatDec
*dec
, const AmbDecConf
*conf
, ALsizei chancount
, ALuint srate
, const ALsizei chanmap
[MAX_OUTPUT_CHANNELS
])
236 static const ALsizei map2DTo3D
[MAX_AMBI2D_COEFFS
] = {
239 const ALfloat
*coeff_scale
= UnitScale
;
244 al_free(dec
->Samples
);
246 dec
->SamplesHF
= NULL
;
247 dec
->SamplesLF
= NULL
;
249 dec
->NumChannels
= chancount
;
250 dec
->Samples
= al_calloc(16, dec
->NumChannels
*2 * sizeof(dec
->Samples
[0]));
251 dec
->SamplesHF
= dec
->Samples
;
252 dec
->SamplesLF
= dec
->SamplesHF
+ dec
->NumChannels
;
254 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
255 dec
->Enabled
[i
] = AL_FALSE
;
256 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
257 dec
->Enabled
[chanmap
[i
]] = AL_TRUE
;
259 if(conf
->CoeffScale
== ADS_SN3D
)
260 coeff_scale
= SN3D2N3DScale
;
261 else if(conf
->CoeffScale
== ADS_FuMa
)
262 coeff_scale
= FuMa2N3DScale
;
264 memset(dec
->UpSampler
, 0, sizeof(dec
->UpSampler
));
265 ratio
= 400.0f
/ (ALfloat
)srate
;
267 bandsplit_init(&dec
->UpSampler
[i
].XOver
, ratio
);
268 if((conf
->ChanMask
&AMBI_PERIPHONIC_MASK
))
272 dec
->UpSampler
[0].Gains
[FB_HighFreq
] = (dec
->NumChannels
> 9) ? W_SCALE3D_THIRD
:
273 (dec
->NumChannels
> 4) ? W_SCALE3D_SECOND
: 1.0f
;
274 dec
->UpSampler
[0].Gains
[FB_LowFreq
] = 1.0f
;
277 dec
->UpSampler
[i
].Gains
[FB_HighFreq
] = (dec
->NumChannels
> 9) ? XYZ_SCALE3D_THIRD
:
278 (dec
->NumChannels
> 4) ? XYZ_SCALE3D_SECOND
: 1.0f
;
279 dec
->UpSampler
[i
].Gains
[FB_LowFreq
] = 1.0f
;
286 dec
->UpSampler
[0].Gains
[FB_HighFreq
] = (dec
->NumChannels
> 5) ? W_SCALE2D_THIRD
:
287 (dec
->NumChannels
> 3) ? W_SCALE2D_SECOND
: 1.0f
;
288 dec
->UpSampler
[0].Gains
[FB_LowFreq
] = 1.0f
;
291 dec
->UpSampler
[i
].Gains
[FB_HighFreq
] = (dec
->NumChannels
> 5) ? XYZ_SCALE2D_THIRD
:
292 (dec
->NumChannels
> 3) ? XYZ_SCALE2D_SECOND
: 1.0f
;
293 dec
->UpSampler
[i
].Gains
[FB_LowFreq
] = 1.0f
;
295 dec
->UpSampler
[3].Gains
[FB_HighFreq
] = 0.0f
;
296 dec
->UpSampler
[3].Gains
[FB_LowFreq
] = 0.0f
;
299 memset(&dec
->Matrix
, 0, sizeof(dec
->Matrix
));
300 if(conf
->FreqBands
== 1)
302 dec
->DualBand
= AL_FALSE
;
303 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
305 ALsizei chan
= chanmap
[i
];
311 for(j
= 0,k
= 0;j
< MAX_AMBI2D_COEFFS
;j
++)
313 ALsizei l
= map2DTo3D
[j
];
314 if(j
== 0) gain
= conf
->HFOrderGain
[0];
315 else if(j
== 1) gain
= conf
->HFOrderGain
[1];
316 else if(j
== 3) gain
= conf
->HFOrderGain
[2];
317 else if(j
== 5) gain
= conf
->HFOrderGain
[3];
318 if((conf
->ChanMask
&(1<<l
)))
319 dec
->Matrix
.Single
[chan
][j
] = conf
->HFMatrix
[i
][k
++] / coeff_scale
[l
] *
325 for(j
= 0,k
= 0;j
< MAX_AMBI_COEFFS
;j
++)
327 if(j
== 0) gain
= conf
->HFOrderGain
[0];
328 else if(j
== 1) gain
= conf
->HFOrderGain
[1];
329 else if(j
== 4) gain
= conf
->HFOrderGain
[2];
330 else if(j
== 9) gain
= conf
->HFOrderGain
[3];
331 if((conf
->ChanMask
&(1<<j
)))
332 dec
->Matrix
.Single
[chan
][j
] = conf
->HFMatrix
[i
][k
++] / coeff_scale
[j
] *
340 dec
->DualBand
= AL_TRUE
;
342 ratio
= conf
->XOverFreq
/ (ALfloat
)srate
;
343 for(i
= 0;i
< MAX_AMBI_COEFFS
;i
++)
344 bandsplit_init(&dec
->XOver
[i
], ratio
);
346 ratio
= powf(10.0f
, conf
->XOverRatio
/ 40.0f
);
347 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
349 ALsizei chan
= chanmap
[i
];
355 for(j
= 0,k
= 0;j
< MAX_AMBI2D_COEFFS
;j
++)
357 ALsizei l
= map2DTo3D
[j
];
358 if(j
== 0) gain
= conf
->HFOrderGain
[0] * ratio
;
359 else if(j
== 1) gain
= conf
->HFOrderGain
[1] * ratio
;
360 else if(j
== 3) gain
= conf
->HFOrderGain
[2] * ratio
;
361 else if(j
== 5) gain
= conf
->HFOrderGain
[3] * ratio
;
362 if((conf
->ChanMask
&(1<<l
)))
363 dec
->Matrix
.Dual
[chan
][FB_HighFreq
][j
] = conf
->HFMatrix
[i
][k
++] /
364 coeff_scale
[l
] * gain
;
366 for(j
= 0,k
= 0;j
< MAX_AMBI2D_COEFFS
;j
++)
368 ALsizei l
= map2DTo3D
[j
];
369 if(j
== 0) gain
= conf
->LFOrderGain
[0] / ratio
;
370 else if(j
== 1) gain
= conf
->LFOrderGain
[1] / ratio
;
371 else if(j
== 3) gain
= conf
->LFOrderGain
[2] / ratio
;
372 else if(j
== 5) gain
= conf
->LFOrderGain
[3] / ratio
;
373 if((conf
->ChanMask
&(1<<l
)))
374 dec
->Matrix
.Dual
[chan
][FB_LowFreq
][j
] = conf
->LFMatrix
[i
][k
++] /
375 coeff_scale
[l
] * gain
;
380 for(j
= 0,k
= 0;j
< MAX_AMBI_COEFFS
;j
++)
382 if(j
== 0) gain
= conf
->HFOrderGain
[0] * ratio
;
383 else if(j
== 1) gain
= conf
->HFOrderGain
[1] * ratio
;
384 else if(j
== 4) gain
= conf
->HFOrderGain
[2] * ratio
;
385 else if(j
== 9) gain
= conf
->HFOrderGain
[3] * ratio
;
386 if((conf
->ChanMask
&(1<<j
)))
387 dec
->Matrix
.Dual
[chan
][FB_HighFreq
][j
] = conf
->HFMatrix
[i
][k
++] /
388 coeff_scale
[j
] * gain
;
390 for(j
= 0,k
= 0;j
< MAX_AMBI_COEFFS
;j
++)
392 if(j
== 0) gain
= conf
->LFOrderGain
[0] / ratio
;
393 else if(j
== 1) gain
= conf
->LFOrderGain
[1] / ratio
;
394 else if(j
== 4) gain
= conf
->LFOrderGain
[2] / ratio
;
395 else if(j
== 9) gain
= conf
->LFOrderGain
[3] / ratio
;
396 if((conf
->ChanMask
&(1<<j
)))
397 dec
->Matrix
.Dual
[chan
][FB_LowFreq
][j
] = conf
->LFMatrix
[i
][k
++] /
398 coeff_scale
[j
] * gain
;
406 void bformatdec_process(struct BFormatDec
*dec
, ALfloat (*restrict OutBuffer
)[BUFFERSIZE
], ALsizei OutChannels
, const ALfloat (*restrict InSamples
)[BUFFERSIZE
], ALsizei SamplesToDo
)
410 OutBuffer
= ASSUME_ALIGNED(OutBuffer
, 16);
413 for(i
= 0;i
< dec
->NumChannels
;i
++)
414 bandsplit_process(&dec
->XOver
[i
], dec
->SamplesHF
[i
], dec
->SamplesLF
[i
],
415 InSamples
[i
], SamplesToDo
);
417 for(chan
= 0;chan
< OutChannels
;chan
++)
419 if(!dec
->Enabled
[chan
])
422 memset(dec
->ChannelMix
, 0, SamplesToDo
*sizeof(ALfloat
));
423 MixRowSamples(dec
->ChannelMix
, dec
->Matrix
.Dual
[chan
][FB_HighFreq
],
424 dec
->SamplesHF
, dec
->NumChannels
, 0, SamplesToDo
426 MixRowSamples(dec
->ChannelMix
, dec
->Matrix
.Dual
[chan
][FB_LowFreq
],
427 dec
->SamplesLF
, dec
->NumChannels
, 0, SamplesToDo
430 for(i
= 0;i
< SamplesToDo
;i
++)
431 OutBuffer
[chan
][i
] += dec
->ChannelMix
[i
];
436 for(chan
= 0;chan
< OutChannels
;chan
++)
438 if(!dec
->Enabled
[chan
])
441 memset(dec
->ChannelMix
, 0, SamplesToDo
*sizeof(ALfloat
));
442 MixRowSamples(dec
->ChannelMix
, dec
->Matrix
.Single
[chan
], InSamples
,
443 dec
->NumChannels
, 0, SamplesToDo
);
445 for(i
= 0;i
< SamplesToDo
;i
++)
446 OutBuffer
[chan
][i
] += dec
->ChannelMix
[i
];
452 void bformatdec_upSample(struct BFormatDec
*dec
, ALfloat (*restrict OutBuffer
)[BUFFERSIZE
], const ALfloat (*restrict InSamples
)[BUFFERSIZE
], ALsizei InChannels
, ALsizei SamplesToDo
)
456 /* This up-sampler leverages the differences observed in dual-band second-
457 * and third-order decoder matrices compared to first-order. For the same
458 * output channel configuration, the low-frequency matrix has identical
459 * coefficients in the shared input channels, while the high-frequency
460 * matrix has extra scalars applied to the W channel and X/Y/Z channels.
461 * Mixing the first-order content into the higher-order stream with the
462 * appropriate counter-scales applied to the HF response results in the
463 * subsequent higher-order decode generating the same response as a first-
466 for(i
= 0;i
< InChannels
;i
++)
468 /* First, split the first-order components into low and high frequency
471 bandsplit_process(&dec
->UpSampler
[i
].XOver
,
472 dec
->Samples
[FB_HighFreq
], dec
->Samples
[FB_LowFreq
],
473 InSamples
[i
], SamplesToDo
476 /* Now write each band to the output. */
477 MixRowSamples(OutBuffer
[i
], dec
->UpSampler
[i
].Gains
,
478 dec
->Samples
, FB_Max
, 0, SamplesToDo
484 #define INVALID_UPSAMPLE_INDEX INT_MAX
486 static ALsizei
GetACNIndex(const BFChannelConfig
*chans
, ALsizei numchans
, ALsizei acn
)
489 for(i
= 0;i
< numchans
;i
++)
491 if(chans
[i
].Index
== acn
)
494 return INVALID_UPSAMPLE_INDEX
;
496 #define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a))
498 typedef struct AmbiUpsampler
{
499 alignas(16) ALfloat Samples
[FB_Max
][BUFFERSIZE
];
501 BandSplitter XOver
[4];
503 ALfloat Gains
[4][MAX_OUTPUT_CHANNELS
][FB_Max
];
506 AmbiUpsampler
*ambiup_alloc()
508 return al_calloc(16, sizeof(AmbiUpsampler
));
511 void ambiup_free(struct AmbiUpsampler
*ambiup
)
516 void ambiup_reset(struct AmbiUpsampler
*ambiup
, const ALCdevice
*device
)
521 ratio
= 400.0f
/ (ALfloat
)device
->Frequency
;
523 bandsplit_init(&ambiup
->XOver
[i
], ratio
);
525 memset(ambiup
->Gains
, 0, sizeof(ambiup
->Gains
));
526 if(device
->Dry
.CoeffCount
> 0)
528 ALfloat encgains
[8][MAX_OUTPUT_CHANNELS
];
532 for(k
= 0;k
< COUNTOF(Ambi3DPoints
);k
++)
534 ALfloat coeffs
[MAX_AMBI_COEFFS
] = { 0.0f
};
535 CalcDirectionCoeffs(Ambi3DPoints
[k
], 0.0f
, coeffs
);
536 ComputeDryPanGains(&device
->Dry
, coeffs
, 1.0f
, encgains
[k
]);
539 /* Combine the matrices that do the in->virt and virt->out conversions
540 * so we get a single in->out conversion. NOTE: the Encoder matrix
541 * (encgains) and output are transposed, so the input channels line up
542 * with the rows and the output channels line up with the columns.
546 for(j
= 0;j
< device
->Dry
.NumChannels
;j
++)
548 ALfloat hfgain
=0.0f
, lfgain
=0.0f
;
549 for(k
= 0;k
< COUNTOF(Ambi3DDecoder
);k
++)
551 hfgain
+= Ambi3DDecoder
[k
][FB_HighFreq
][i
]*encgains
[k
][j
];
552 lfgain
+= Ambi3DDecoder
[k
][FB_LowFreq
][i
]*encgains
[k
][j
];
554 ambiup
->Gains
[i
][j
][FB_HighFreq
] = hfgain
;
555 ambiup
->Gains
[i
][j
][FB_LowFreq
] = lfgain
;
561 /* Assumes full 3D/periphonic on the input and output mixes! */
562 ALfloat w_scale
= (device
->Dry
.NumChannels
> 9) ? W_SCALE3D_THIRD
:
563 (device
->Dry
.NumChannels
> 4) ? W_SCALE3D_SECOND
: 1.0f
;
564 ALfloat xyz_scale
= (device
->Dry
.NumChannels
> 9) ? XYZ_SCALE3D_THIRD
:
565 (device
->Dry
.NumChannels
> 4) ? XYZ_SCALE3D_SECOND
: 1.0f
;
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
][FB_HighFreq
] = scale
* ((i
==0) ? w_scale
: xyz_scale
);
573 ambiup
->Gains
[i
][index
][FB_LowFreq
] = 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
[FB_HighFreq
], ambiup
->Samples
[FB_LowFreq
],
587 InSamples
[i
], SamplesToDo
590 for(j
= 0;j
< OutChannels
;j
++)
591 MixRowSamples(OutBuffer
[j
], ambiup
->Gains
[i
][j
],
592 ambiup
->Samples
, FB_Max
, 0, SamplesToDo