2 * Copyright © 2016 Mozilla Foundation
4 * This program is made available under an ISC-style license. See the
5 * accompanying file LICENSE for details.
7 * Adapted from code based on libswresample's rematrix.c
12 #include "cubeb_mixer.h"
13 #include "cubeb-internal.h"
14 #include "cubeb_utils.h"
21 #include <type_traits>
23 #ifndef FF_ARRAY_ELEMS
24 #define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
27 #define CHANNELS_MAX 32
30 #define FRONT_CENTER 2
31 #define LOW_FREQUENCY 3
34 #define FRONT_LEFT_OF_CENTER 6
35 #define FRONT_RIGHT_OF_CENTER 7
40 #define TOP_FRONT_LEFT 12
41 #define TOP_FRONT_CENTER 13
42 #define TOP_FRONT_RIGHT 14
43 #define TOP_BACK_LEFT 15
44 #define TOP_BACK_CENTER 16
45 #define TOP_BACK_RIGHT 17
46 #define NUM_NAMED_CHANNELS 18
49 #define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */
52 #define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
54 #define SQRT3_2 1.22474487139158904909 /* sqrt(3/2) */
57 #define C15DB 1.189207115
59 #define C_15DB 0.840896415
60 #define C_30DB M_SQRT1_2
61 #define C_45DB 0.594603558
64 static cubeb_channel_layout
65 cubeb_channel_layout_check(cubeb_channel_layout l
, uint32_t c
)
67 if (l
== CUBEB_LAYOUT_UNDEFINED
) {
70 return CUBEB_LAYOUT_MONO
;
72 return CUBEB_LAYOUT_STEREO
;
79 cubeb_channel_layout_nb_channels(cubeb_channel_layout x
)
81 #if __GNUC__ || __clang__
82 return __builtin_popcount(x
);
84 x
-= (x
>> 1) & 0x55555555;
85 x
= (x
& 0x33333333) + ((x
>> 2) & 0x33333333);
86 x
= (x
+ (x
>> 4)) & 0x0F0F0F0F;
88 return (x
+ (x
>> 16)) & 0x3F;
93 MixerContext(cubeb_sample_format f
, uint32_t in_channels
,
94 cubeb_channel_layout in
, uint32_t out_channels
,
95 cubeb_channel_layout out
)
96 : _format(f
), _in_ch_layout(cubeb_channel_layout_check(in
, in_channels
)),
97 _out_ch_layout(cubeb_channel_layout_check(out
, out_channels
)),
98 _in_ch_count(in_channels
), _out_ch_count(out_channels
)
100 if (in_channels
!= cubeb_channel_layout_nb_channels(in
) ||
101 out_channels
!= cubeb_channel_layout_nb_channels(out
)) {
102 // Mismatch between channels and layout, aborting.
105 _valid
= init() >= 0;
108 static bool even(cubeb_channel_layout layout
)
113 if (layout
& (layout
- 1)) {
119 // Ensure that the layout is sane (that is have symmetrical left/right
120 // channels), if not, layout will be treated as mono.
121 static cubeb_channel_layout
clean_layout(cubeb_channel_layout layout
)
123 if (layout
&& layout
!= CHANNEL_FRONT_LEFT
&& !(layout
& (layout
- 1))) {
124 LOG("Treating layout as mono");
125 return CHANNEL_FRONT_CENTER
;
131 static bool sane_layout(cubeb_channel_layout layout
)
133 if (!(layout
& CUBEB_LAYOUT_3F
)) { // at least 1 front speaker
136 if (!even(layout
& (CHANNEL_FRONT_LEFT
|
137 CHANNEL_FRONT_RIGHT
))) { // no asymetric front
141 (CHANNEL_SIDE_LEFT
| CHANNEL_SIDE_RIGHT
))) { // no asymetric side
144 if (!even(layout
& (CHANNEL_BACK_LEFT
| CHANNEL_BACK_RIGHT
))) {
148 (CHANNEL_FRONT_LEFT_OF_CENTER
| CHANNEL_FRONT_RIGHT_OF_CENTER
))) {
151 if (cubeb_channel_layout_nb_channels(layout
) >= CHANNELS_MAX
) {
160 const cubeb_sample_format _format
;
161 const cubeb_channel_layout _in_ch_layout
; ///< input channel layout
162 const cubeb_channel_layout _out_ch_layout
; ///< output channel layout
163 const uint32_t _in_ch_count
; ///< input channel count
164 const uint32_t _out_ch_count
; ///< output channel count
165 const float _surround_mix_level
= C_30DB
; ///< surround mixing level
166 const float _center_mix_level
= C_30DB
; ///< center mixing level
167 const float _lfe_mix_level
= 1; ///< LFE mixing level
168 double _matrix
[CHANNELS_MAX
][CHANNELS_MAX
] = {
169 {0}}; ///< floating point rematrixing coefficients
170 float _matrix_flt
[CHANNELS_MAX
][CHANNELS_MAX
] = {
171 {0}}; ///< single precision floating point rematrixing coefficients
172 int32_t _matrix32
[CHANNELS_MAX
][CHANNELS_MAX
] = {
173 {0}}; ///< 17.15 fixed point rematrixing coefficients
174 uint8_t _matrix_ch
[CHANNELS_MAX
][CHANNELS_MAX
+ 1] = {
175 {0}}; ///< Lists of input channels per output channel that have non zero
176 ///< rematrixing coefficients
177 bool _clipping
= false; ///< Set to true if clipping detection is required
178 bool _valid
= false; ///< Set to true if context is valid.
182 MixerContext::auto_matrix()
184 double matrix
[NUM_NAMED_CHANNELS
][NUM_NAMED_CHANNELS
] = {{0}};
188 cubeb_channel_layout in_ch_layout
= clean_layout(_in_ch_layout
);
189 cubeb_channel_layout out_ch_layout
= clean_layout(_out_ch_layout
);
191 if (!sane_layout(in_ch_layout
)) {
192 // Channel Not Supported
193 LOG("Input Layout %x is not supported", _in_ch_layout
);
197 if (!sane_layout(out_ch_layout
)) {
198 LOG("Output Layout %x is not supported", _out_ch_layout
);
202 for (uint32_t i
= 0; i
< FF_ARRAY_ELEMS(matrix
); i
++) {
203 if (in_ch_layout
& out_ch_layout
& (1U << i
)) {
208 cubeb_channel_layout unaccounted
= in_ch_layout
& ~out_ch_layout
;
210 // Rematrixing is done via a matrix of coefficient that should be applied to
211 // all channels. Channels are treated as pair and must be symmetrical (if a
212 // left channel exists, the corresponding right should exist too) unless the
213 // output layout has similar layout. Channels are then mixed toward the front
214 // center or back center if they exist with a slight bias toward the front.
216 if (unaccounted
& CHANNEL_FRONT_CENTER
) {
217 if ((out_ch_layout
& CUBEB_LAYOUT_STEREO
) == CUBEB_LAYOUT_STEREO
) {
218 if (in_ch_layout
& CUBEB_LAYOUT_STEREO
) {
219 matrix
[FRONT_LEFT
][FRONT_CENTER
] += _center_mix_level
;
220 matrix
[FRONT_RIGHT
][FRONT_CENTER
] += _center_mix_level
;
222 matrix
[FRONT_LEFT
][FRONT_CENTER
] += M_SQRT1_2
;
223 matrix
[FRONT_RIGHT
][FRONT_CENTER
] += M_SQRT1_2
;
227 if (unaccounted
& CUBEB_LAYOUT_STEREO
) {
228 if (out_ch_layout
& CHANNEL_FRONT_CENTER
) {
229 matrix
[FRONT_CENTER
][FRONT_LEFT
] += M_SQRT1_2
;
230 matrix
[FRONT_CENTER
][FRONT_RIGHT
] += M_SQRT1_2
;
231 if (in_ch_layout
& CHANNEL_FRONT_CENTER
)
232 matrix
[FRONT_CENTER
][FRONT_CENTER
] = _center_mix_level
* M_SQRT2
;
236 if (unaccounted
& CHANNEL_BACK_CENTER
) {
237 if (out_ch_layout
& CHANNEL_BACK_LEFT
) {
238 matrix
[BACK_LEFT
][BACK_CENTER
] += M_SQRT1_2
;
239 matrix
[BACK_RIGHT
][BACK_CENTER
] += M_SQRT1_2
;
240 } else if (out_ch_layout
& CHANNEL_SIDE_LEFT
) {
241 matrix
[SIDE_LEFT
][BACK_CENTER
] += M_SQRT1_2
;
242 matrix
[SIDE_RIGHT
][BACK_CENTER
] += M_SQRT1_2
;
243 } else if (out_ch_layout
& CHANNEL_FRONT_LEFT
) {
244 matrix
[FRONT_LEFT
][BACK_CENTER
] += _surround_mix_level
* M_SQRT1_2
;
245 matrix
[FRONT_RIGHT
][BACK_CENTER
] += _surround_mix_level
* M_SQRT1_2
;
246 } else if (out_ch_layout
& CHANNEL_FRONT_CENTER
) {
247 matrix
[FRONT_CENTER
][BACK_CENTER
] += _surround_mix_level
* M_SQRT1_2
;
250 if (unaccounted
& CHANNEL_BACK_LEFT
) {
251 if (out_ch_layout
& CHANNEL_BACK_CENTER
) {
252 matrix
[BACK_CENTER
][BACK_LEFT
] += M_SQRT1_2
;
253 matrix
[BACK_CENTER
][BACK_RIGHT
] += M_SQRT1_2
;
254 } else if (out_ch_layout
& CHANNEL_SIDE_LEFT
) {
255 if (in_ch_layout
& CHANNEL_SIDE_LEFT
) {
256 matrix
[SIDE_LEFT
][BACK_LEFT
] += M_SQRT1_2
;
257 matrix
[SIDE_RIGHT
][BACK_RIGHT
] += M_SQRT1_2
;
259 matrix
[SIDE_LEFT
][BACK_LEFT
] += 1.0;
260 matrix
[SIDE_RIGHT
][BACK_RIGHT
] += 1.0;
262 } else if (out_ch_layout
& CHANNEL_FRONT_LEFT
) {
263 matrix
[FRONT_LEFT
][BACK_LEFT
] += _surround_mix_level
;
264 matrix
[FRONT_RIGHT
][BACK_RIGHT
] += _surround_mix_level
;
265 } else if (out_ch_layout
& CHANNEL_FRONT_CENTER
) {
266 matrix
[FRONT_CENTER
][BACK_LEFT
] += _surround_mix_level
* M_SQRT1_2
;
267 matrix
[FRONT_CENTER
][BACK_RIGHT
] += _surround_mix_level
* M_SQRT1_2
;
271 if (unaccounted
& CHANNEL_SIDE_LEFT
) {
272 if (out_ch_layout
& CHANNEL_BACK_LEFT
) {
273 /* if back channels do not exist in the input, just copy side
274 channels to back channels, otherwise mix side into back */
275 if (in_ch_layout
& CHANNEL_BACK_LEFT
) {
276 matrix
[BACK_LEFT
][SIDE_LEFT
] += M_SQRT1_2
;
277 matrix
[BACK_RIGHT
][SIDE_RIGHT
] += M_SQRT1_2
;
279 matrix
[BACK_LEFT
][SIDE_LEFT
] += 1.0;
280 matrix
[BACK_RIGHT
][SIDE_RIGHT
] += 1.0;
282 } else if (out_ch_layout
& CHANNEL_BACK_CENTER
) {
283 matrix
[BACK_CENTER
][SIDE_LEFT
] += M_SQRT1_2
;
284 matrix
[BACK_CENTER
][SIDE_RIGHT
] += M_SQRT1_2
;
285 } else if (out_ch_layout
& CHANNEL_FRONT_LEFT
) {
286 matrix
[FRONT_LEFT
][SIDE_LEFT
] += _surround_mix_level
;
287 matrix
[FRONT_RIGHT
][SIDE_RIGHT
] += _surround_mix_level
;
288 } else if (out_ch_layout
& CHANNEL_FRONT_CENTER
) {
289 matrix
[FRONT_CENTER
][SIDE_LEFT
] += _surround_mix_level
* M_SQRT1_2
;
290 matrix
[FRONT_CENTER
][SIDE_RIGHT
] += _surround_mix_level
* M_SQRT1_2
;
294 if (unaccounted
& CHANNEL_FRONT_LEFT_OF_CENTER
) {
295 if (out_ch_layout
& CHANNEL_FRONT_LEFT
) {
296 matrix
[FRONT_LEFT
][FRONT_LEFT_OF_CENTER
] += 1.0;
297 matrix
[FRONT_RIGHT
][FRONT_RIGHT_OF_CENTER
] += 1.0;
298 } else if (out_ch_layout
& CHANNEL_FRONT_CENTER
) {
299 matrix
[FRONT_CENTER
][FRONT_LEFT_OF_CENTER
] += M_SQRT1_2
;
300 matrix
[FRONT_CENTER
][FRONT_RIGHT_OF_CENTER
] += M_SQRT1_2
;
303 /* mix LFE into front left/right or center */
304 if (unaccounted
& CHANNEL_LOW_FREQUENCY
) {
305 if (out_ch_layout
& CHANNEL_FRONT_CENTER
) {
306 matrix
[FRONT_CENTER
][LOW_FREQUENCY
] += _lfe_mix_level
;
307 } else if (out_ch_layout
& CHANNEL_FRONT_LEFT
) {
308 matrix
[FRONT_LEFT
][LOW_FREQUENCY
] += _lfe_mix_level
* M_SQRT1_2
;
309 matrix
[FRONT_RIGHT
][LOW_FREQUENCY
] += _lfe_mix_level
* M_SQRT1_2
;
313 // Normalize the conversion matrix.
314 for (uint32_t out_i
= 0, i
= 0; i
< CHANNELS_MAX
; i
++) {
317 if ((out_ch_layout
& (1U << i
)) == 0) {
320 for (uint32_t j
= 0; j
< CHANNELS_MAX
; j
++) {
321 if ((in_ch_layout
& (1U << j
)) == 0) {
324 if (i
< FF_ARRAY_ELEMS(matrix
) && j
< FF_ARRAY_ELEMS(matrix
[0])) {
325 _matrix
[out_i
][in_i
] = matrix
[i
][j
];
327 _matrix
[out_i
][in_i
] =
328 i
== j
&& (in_ch_layout
& out_ch_layout
& (1U << i
));
330 sum
+= fabs(_matrix
[out_i
][in_i
]);
333 maxcoef
= std::max(maxcoef
, sum
);
337 if (_format
== CUBEB_SAMPLE_S16NE
) {
343 // Normalize matrix if needed.
344 if (maxcoef
> maxval
) {
346 for (uint32_t i
= 0; i
< CHANNELS_MAX
; i
++)
347 for (uint32_t j
= 0; j
< CHANNELS_MAX
; j
++) {
348 _matrix
[i
][j
] /= maxcoef
;
352 if (_format
== CUBEB_SAMPLE_FLOAT32NE
) {
353 for (uint32_t i
= 0; i
< FF_ARRAY_ELEMS(_matrix
); i
++) {
354 for (uint32_t j
= 0; j
< FF_ARRAY_ELEMS(_matrix
[0]); j
++) {
355 _matrix_flt
[i
][j
] = _matrix
[i
][j
];
366 int r
= auto_matrix();
371 // Determine if matrix operation would overflow
372 if (_format
== CUBEB_SAMPLE_S16NE
) {
374 for (uint32_t i
= 0; i
< _out_ch_count
; i
++) {
378 for (uint32_t j
= 0; j
< _in_ch_count
; j
++) {
379 double target
= _matrix
[i
][j
] * 32768 + rem
;
380 int value
= lrintf(target
);
381 rem
+= target
- value
;
382 sum
+= std::abs(value
);
384 maxsum
= std::max(maxsum
, sum
);
386 if (maxsum
> 32768) {
391 // FIXME quantize for integers
392 for (uint32_t i
= 0; i
< CHANNELS_MAX
; i
++) {
394 for (uint32_t j
= 0; j
< CHANNELS_MAX
; j
++) {
395 _matrix32
[i
][j
] = lrintf(_matrix
[i
][j
] * 32768);
397 _matrix_ch
[i
][++ch_in
] = j
;
400 _matrix_ch
[i
][0] = ch_in
;
406 template <typename TYPE_SAMPLE
, typename TYPE_COEFF
, typename F
>
408 sum2(TYPE_SAMPLE
* out
, uint32_t stride_out
, const TYPE_SAMPLE
* in1
,
409 const TYPE_SAMPLE
* in2
, uint32_t stride_in
, TYPE_COEFF coeff1
,
410 TYPE_COEFF coeff2
, F
&& operand
, uint32_t frames
)
413 std::is_same
<TYPE_COEFF
, decltype(operand(coeff1
))>::value
,
414 "function must return the same type as used by coeff1 and coeff2");
415 for (uint32_t i
= 0; i
< frames
; i
++) {
416 *out
= operand(coeff1
* *in1
+ coeff2
* *in2
);
423 template <typename TYPE_SAMPLE
, typename TYPE_COEFF
, typename F
>
425 copy(TYPE_SAMPLE
* out
, uint32_t stride_out
, const TYPE_SAMPLE
* in
,
426 uint32_t stride_in
, TYPE_COEFF coeff
, F
&& operand
, uint32_t frames
)
428 static_assert(std::is_same
<TYPE_COEFF
, decltype(operand(coeff
))>::value
,
429 "function must return the same type as used by coeff");
430 for (uint32_t i
= 0; i
< frames
; i
++) {
431 *out
= operand(coeff
* *in
);
437 template <typename TYPE
, typename TYPE_COEFF
, size_t COLS
, typename F
>
439 rematrix(const MixerContext
* s
, TYPE
* aOut
, const TYPE
* aIn
,
440 const TYPE_COEFF (&matrix_coeff
)[COLS
][COLS
], F
&& aF
, uint32_t frames
)
443 std::is_same
<TYPE_COEFF
, decltype(aF(matrix_coeff
[0][0]))>::value
,
444 "function must return the same type as used by matrix_coeff");
446 for (uint32_t out_i
= 0; out_i
< s
->_out_ch_count
; out_i
++) {
447 TYPE
* out
= aOut
+ out_i
;
448 switch (s
->_matrix_ch
[out_i
][0]) {
450 for (uint32_t i
= 0; i
< frames
; i
++) {
451 out
[i
* s
->_out_ch_count
] = 0;
455 int in_i
= s
->_matrix_ch
[out_i
][1];
456 copy(out
, s
->_out_ch_count
, aIn
+ in_i
, s
->_in_ch_count
,
457 matrix_coeff
[out_i
][in_i
], aF
, frames
);
460 sum2(out
, s
->_out_ch_count
, aIn
+ s
->_matrix_ch
[out_i
][1],
461 aIn
+ s
->_matrix_ch
[out_i
][2], s
->_in_ch_count
,
462 matrix_coeff
[out_i
][s
->_matrix_ch
[out_i
][1]],
463 matrix_coeff
[out_i
][s
->_matrix_ch
[out_i
][2]], aF
, frames
);
466 for (uint32_t i
= 0; i
< frames
; i
++) {
468 for (uint32_t j
= 0; j
< s
->_matrix_ch
[out_i
][0]; j
++) {
469 uint32_t in_i
= s
->_matrix_ch
[out_i
][1 + j
];
470 v
+= *(aIn
+ in_i
+ i
* s
->_in_ch_count
) * matrix_coeff
[out_i
][in_i
];
472 out
[i
* s
->_out_ch_count
] = aF(v
);
481 cubeb_mixer(cubeb_sample_format format
, uint32_t in_channels
,
482 cubeb_channel_layout in_layout
, uint32_t out_channels
,
483 cubeb_channel_layout out_layout
)
484 : _context(format
, in_channels
, in_layout
, out_channels
, out_layout
)
488 template <typename T
>
489 void copy_and_trunc(size_t frames
, const T
* input_buffer
,
490 T
* output_buffer
) const
492 if (_context
._in_ch_count
<= _context
._out_ch_count
) {
493 // Not enough channels to copy, fill the gaps with silence.
494 if (_context
._in_ch_count
== 1 && _context
._out_ch_count
>= 2) {
495 // Special case for upmixing mono input to stereo and more. We will
496 // duplicate the mono channel to the first two channels. On most system,
497 // the first two channels are for left and right. It is commonly
498 // expected that mono will on both left+right channels
499 for (uint32_t i
= 0; i
< frames
; i
++) {
500 output_buffer
[0] = output_buffer
[1] = *input_buffer
;
501 PodZero(output_buffer
+ 2, _context
._out_ch_count
- 2);
502 output_buffer
+= _context
._out_ch_count
;
507 for (uint32_t i
= 0; i
< frames
; i
++) {
508 PodCopy(output_buffer
, input_buffer
, _context
._in_ch_count
);
509 output_buffer
+= _context
._in_ch_count
;
510 input_buffer
+= _context
._in_ch_count
;
511 PodZero(output_buffer
, _context
._out_ch_count
- _context
._in_ch_count
);
512 output_buffer
+= _context
._out_ch_count
- _context
._in_ch_count
;
515 for (uint32_t i
= 0; i
< frames
; i
++) {
516 PodCopy(output_buffer
, input_buffer
, _context
._out_ch_count
);
517 output_buffer
+= _context
._out_ch_count
;
518 input_buffer
+= _context
._in_ch_count
;
523 int mix(size_t frames
, const void * input_buffer
, size_t input_buffer_size
,
524 void * output_buffer
, size_t output_buffer_size
) const
526 if (frames
<= 0 || _context
._out_ch_count
== 0) {
530 // Check if output buffer is of sufficient size.
531 size_t size_read_needed
=
532 frames
* _context
._in_ch_count
* cubeb_sample_size(_context
._format
);
533 if (input_buffer_size
< size_read_needed
) {
534 // We don't have enough data to read!
537 if (output_buffer_size
* _context
._in_ch_count
<
538 size_read_needed
* _context
._out_ch_count
) {
543 // The channel layouts were invalid or unsupported, instead we will simply
544 // either drop the extra channels, or fill with silence the missing ones
545 if (_context
._format
== CUBEB_SAMPLE_FLOAT32NE
) {
546 copy_and_trunc(frames
, static_cast<const float *>(input_buffer
),
547 static_cast<float *>(output_buffer
));
549 assert(_context
._format
== CUBEB_SAMPLE_S16NE
);
550 copy_and_trunc(frames
, static_cast<const int16_t *>(input_buffer
),
551 reinterpret_cast<int16_t *>(output_buffer
));
556 switch (_context
._format
) {
557 case CUBEB_SAMPLE_FLOAT32NE
: {
558 auto f
= [](float x
) { return x
; };
559 return rematrix(&_context
, static_cast<float *>(output_buffer
),
560 static_cast<const float *>(input_buffer
),
561 _context
._matrix_flt
, f
, frames
);
563 case CUBEB_SAMPLE_S16NE
:
564 if (_context
._clipping
) {
566 int y
= (x
+ 16384) >> 15;
567 // clip the signed integer value into the -32768,32767 range.
568 if ((y
+ 0x8000U
) & ~0xFFFF) {
569 return (y
>> 31) ^ 0x7FFF;
573 return rematrix(&_context
, static_cast<int16_t *>(output_buffer
),
574 static_cast<const int16_t *>(input_buffer
),
575 _context
._matrix32
, f
, frames
);
577 auto f
= [](int x
) { return (x
+ 16384) >> 15; };
578 return rematrix(&_context
, static_cast<int16_t *>(output_buffer
),
579 static_cast<const int16_t *>(input_buffer
),
580 _context
._matrix32
, f
, frames
);
591 // Return false if any of the input or ouput layout were invalid.
592 bool valid() const { return _context
._valid
; }
594 virtual ~cubeb_mixer(){};
596 MixerContext _context
;
600 cubeb_mixer_create(cubeb_sample_format format
, uint32_t in_channels
,
601 cubeb_channel_layout in_layout
, uint32_t out_channels
,
602 cubeb_channel_layout out_layout
)
604 return new cubeb_mixer(format
, in_channels
, in_layout
, out_channels
,
609 cubeb_mixer_destroy(cubeb_mixer
* mixer
)
615 cubeb_mixer_mix(cubeb_mixer
* mixer
, size_t frames
, const void * input_buffer
,
616 size_t input_buffer_size
, void * output_buffer
,
617 size_t output_buffer_size
)
619 return mixer
->mix(frames
, input_buffer
, input_buffer_size
, output_buffer
,