1 /*
2  * Copyright © 2016 Mozilla Foundation
3  *
4  * This program is made available under an ISC-style license.  See the
5  * accompanying file LICENSE for details.
6  *
7  * Adapted from code based on libswresample's rematrix.c
8  */
9 
10 #define NOMINMAX
11 
12 #include "cubeb_mixer.h"
13 #include "cubeb-internal.h"
14 #include "cubeb_utils.h"
15 #include <algorithm>
16 #include <cassert>
17 #include <climits>
18 #include <cmath>
19 #include <cstdlib>
20 #include <memory>
21 #include <type_traits>
22 
23 #ifndef FF_ARRAY_ELEMS
24 #define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
25 #endif
26 
27 #define CHANNELS_MAX 32
28 #define FRONT_LEFT 0
29 #define FRONT_RIGHT 1
30 #define FRONT_CENTER 2
31 #define LOW_FREQUENCY 3
32 #define BACK_LEFT 4
33 #define BACK_RIGHT 5
34 #define FRONT_LEFT_OF_CENTER 6
35 #define FRONT_RIGHT_OF_CENTER 7
36 #define BACK_CENTER 8
37 #define SIDE_LEFT 9
38 #define SIDE_RIGHT 10
39 #define TOP_CENTER 11
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
47 
48 #ifndef M_SQRT1_2
49 #define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */
50 #endif
51 #ifndef M_SQRT2
52 #define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
53 #endif
54 #define SQRT3_2 1.22474487139158904909 /* sqrt(3/2) */
55 
56 #define C30DB M_SQRT2
57 #define C15DB 1.189207115
58 #define C__0DB 1.0
59 #define C_15DB 0.840896415
60 #define C_30DB M_SQRT1_2
61 #define C_45DB 0.594603558
62 #define C_60DB 0.5
63 
64 static cubeb_channel_layout
cubeb_channel_layout_check(cubeb_channel_layout l,uint32_t c)65 cubeb_channel_layout_check(cubeb_channel_layout l, uint32_t c)
66 {
67   if (l == CUBEB_LAYOUT_UNDEFINED) {
68     switch (c) {
69     case 1:
70       return CUBEB_LAYOUT_MONO;
71     case 2:
72       return CUBEB_LAYOUT_STEREO;
73     }
74   }
75   return l;
76 }
77 
78 unsigned int
cubeb_channel_layout_nb_channels(cubeb_channel_layout x)79 cubeb_channel_layout_nb_channels(cubeb_channel_layout x)
80 {
81 #if __GNUC__ || __clang__
82   return __builtin_popcount(x);
83 #else
84   x -= (x >> 1) & 0x55555555;
85   x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
86   x = (x + (x >> 4)) & 0x0F0F0F0F;
87   x += x >> 8;
88   return (x + (x >> 16)) & 0x3F;
89 #endif
90 }
91 
92 struct MixerContext {
MixerContextMixerContext93   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)
99   {
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.
103       return;
104     }
105     _valid = init() >= 0;
106   }
107 
evenMixerContext108   static bool even(cubeb_channel_layout layout)
109   {
110     if (!layout) {
111       return true;
112     }
113     if (layout & (layout - 1)) {
114       return true;
115     }
116     return false;
117   }
118 
119   // Ensure that the layout is sane (that is have symmetrical left/right
120   // channels), if not, layout will be treated as mono.
clean_layoutMixerContext121   static cubeb_channel_layout clean_layout(cubeb_channel_layout layout)
122   {
123     if (layout && layout != CHANNEL_FRONT_LEFT && !(layout & (layout - 1))) {
124       LOG("Treating layout as mono");
125       return CHANNEL_FRONT_CENTER;
126     }
127 
128     return layout;
129   }
130 
sane_layoutMixerContext131   static bool sane_layout(cubeb_channel_layout layout)
132   {
133     if (!(layout & CUBEB_LAYOUT_3F)) { // at least 1 front speaker
134       return false;
135     }
136     if (!even(layout & (CHANNEL_FRONT_LEFT |
137                         CHANNEL_FRONT_RIGHT))) { // no asymetric front
138       return false;
139     }
140     if (!even(layout &
141               (CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT))) { // no asymetric side
142       return false;
143     }
144     if (!even(layout & (CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT))) {
145       return false;
146     }
147     if (!even(layout &
148               (CHANNEL_FRONT_LEFT_OF_CENTER | CHANNEL_FRONT_RIGHT_OF_CENTER))) {
149       return false;
150     }
151     if (cubeb_channel_layout_nb_channels(layout) >= CHANNELS_MAX) {
152       return false;
153     }
154     return true;
155   }
156 
157   int auto_matrix();
158   int init();
159 
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.
179 };
180 
181 int
auto_matrix()182 MixerContext::auto_matrix()
183 {
184   double matrix[NUM_NAMED_CHANNELS][NUM_NAMED_CHANNELS] = {{0}};
185   double maxcoef = 0;
186   float maxval;
187 
188   cubeb_channel_layout in_ch_layout = clean_layout(_in_ch_layout);
189   cubeb_channel_layout out_ch_layout = clean_layout(_out_ch_layout);
190 
191   if (!sane_layout(in_ch_layout)) {
192     // Channel Not Supported
193     LOG("Input Layout %x is not supported", _in_ch_layout);
194     return -1;
195   }
196 
197   if (!sane_layout(out_ch_layout)) {
198     LOG("Output Layout %x is not supported", _out_ch_layout);
199     return -1;
200   }
201 
202   for (uint32_t i = 0; i < FF_ARRAY_ELEMS(matrix); i++) {
203     if (in_ch_layout & out_ch_layout & (1U << i)) {
204       matrix[i][i] = 1.0;
205     }
206   }
207 
208   cubeb_channel_layout unaccounted = in_ch_layout & ~out_ch_layout;
209 
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.
215 
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;
221       } else {
222         matrix[FRONT_LEFT][FRONT_CENTER] += M_SQRT1_2;
223         matrix[FRONT_RIGHT][FRONT_CENTER] += M_SQRT1_2;
224       }
225     }
226   }
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;
233     }
234   }
235 
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;
248     }
249   }
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;
258       } else {
259         matrix[SIDE_LEFT][BACK_LEFT] += 1.0;
260         matrix[SIDE_RIGHT][BACK_RIGHT] += 1.0;
261       }
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;
268     }
269   }
270 
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;
278       } else {
279         matrix[BACK_LEFT][SIDE_LEFT] += 1.0;
280         matrix[BACK_RIGHT][SIDE_RIGHT] += 1.0;
281       }
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;
291     }
292   }
293 
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;
301     }
302   }
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;
310     }
311   }
312 
313   // Normalize the conversion matrix.
314   for (uint32_t out_i = 0, i = 0; i < CHANNELS_MAX; i++) {
315     double sum = 0;
316     int in_i = 0;
317     if ((out_ch_layout & (1U << i)) == 0) {
318       continue;
319     }
320     for (uint32_t j = 0; j < CHANNELS_MAX; j++) {
321       if ((in_ch_layout & (1U << j)) == 0) {
322         continue;
323       }
324       if (i < FF_ARRAY_ELEMS(matrix) && j < FF_ARRAY_ELEMS(matrix[0])) {
325         _matrix[out_i][in_i] = matrix[i][j];
326       } else {
327         _matrix[out_i][in_i] =
328             i == j && (in_ch_layout & out_ch_layout & (1U << i));
329       }
330       sum += fabs(_matrix[out_i][in_i]);
331       in_i++;
332     }
333     maxcoef = std::max(maxcoef, sum);
334     out_i++;
335   }
336 
337   if (_format == CUBEB_SAMPLE_S16NE) {
338     maxval = 1.0;
339   } else {
340     maxval = INT_MAX;
341   }
342 
343   // Normalize matrix if needed.
344   if (maxcoef > maxval) {
345     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;
349       }
350   }
351 
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];
356       }
357     }
358   }
359 
360   return 0;
361 }
362 
363 int
init()364 MixerContext::init()
365 {
366   int r = auto_matrix();
367   if (r) {
368     return r;
369   }
370 
371   // Determine if matrix operation would overflow
372   if (_format == CUBEB_SAMPLE_S16NE) {
373     int maxsum = 0;
374     for (uint32_t i = 0; i < _out_ch_count; i++) {
375       double rem = 0;
376       int sum = 0;
377 
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);
383       }
384       maxsum = std::max(maxsum, sum);
385     }
386     if (maxsum > 32768) {
387       _clipping = true;
388     }
389   }
390 
391   // FIXME quantize for integers
392   for (uint32_t i = 0; i < CHANNELS_MAX; i++) {
393     int ch_in = 0;
394     for (uint32_t j = 0; j < CHANNELS_MAX; j++) {
395       _matrix32[i][j] = lrintf(_matrix[i][j] * 32768);
396       if (_matrix[i][j]) {
397         _matrix_ch[i][++ch_in] = j;
398       }
399     }
400     _matrix_ch[i][0] = ch_in;
401   }
402 
403   return 0;
404 }
405 
406 template <typename TYPE_SAMPLE, typename TYPE_COEFF, typename F>
407 void
sum2(TYPE_SAMPLE * out,uint32_t stride_out,const TYPE_SAMPLE * in1,const TYPE_SAMPLE * in2,uint32_t stride_in,TYPE_COEFF coeff1,TYPE_COEFF coeff2,F && operand,uint32_t frames)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)
411 {
412   static_assert(
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);
417     out += stride_out;
418     in1 += stride_in;
419     in2 += stride_in;
420   }
421 }
422 
423 template <typename TYPE_SAMPLE, typename TYPE_COEFF, typename F>
424 void
copy(TYPE_SAMPLE * out,uint32_t stride_out,const TYPE_SAMPLE * in,uint32_t stride_in,TYPE_COEFF coeff,F && operand,uint32_t frames)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)
427 {
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);
432     out += stride_out;
433     in += stride_in;
434   }
435 }
436 
437 template <typename TYPE, typename TYPE_COEFF, size_t COLS, typename F>
438 static int
rematrix(const MixerContext * s,TYPE * aOut,const TYPE * aIn,const TYPE_COEFF (& matrix_coeff)[COLS][COLS],F && aF,uint32_t frames)439 rematrix(const MixerContext * s, TYPE * aOut, const TYPE * aIn,
440          const TYPE_COEFF (&matrix_coeff)[COLS][COLS], F && aF, uint32_t frames)
441 {
442   static_assert(
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");
445 
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]) {
449     case 0:
450       for (uint32_t i = 0; i < frames; i++) {
451         out[i * s->_out_ch_count] = 0;
452       }
453       break;
454     case 1: {
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);
458     } break;
459     case 2:
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);
464       break;
465     default:
466       for (uint32_t i = 0; i < frames; i++) {
467         TYPE_COEFF v = 0;
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];
471         }
472         out[i * s->_out_ch_count] = aF(v);
473       }
474       break;
475     }
476   }
477   return 0;
478 }
479 
480 struct cubeb_mixer {
cubeb_mixercubeb_mixer481   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)
485   {
486   }
487 
488   template <typename T>
copy_and_trunccubeb_mixer489   void copy_and_trunc(size_t frames, const T * input_buffer,
490                       T * output_buffer) const
491   {
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;
503           input_buffer++;
504         }
505         return;
506       }
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;
513       }
514     } else {
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;
519       }
520     }
521   }
522 
mixcubeb_mixer523   int mix(size_t frames, const void * input_buffer, size_t input_buffer_size,
524           void * output_buffer, size_t output_buffer_size) const
525   {
526     if (frames <= 0 || _context._out_ch_count == 0) {
527       return 0;
528     }
529 
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!
535       return -1;
536     }
537     if (output_buffer_size * _context._in_ch_count <
538         size_read_needed * _context._out_ch_count) {
539       return -1;
540     }
541 
542     if (!valid()) {
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));
548       } else {
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));
552       }
553       return 0;
554     }
555 
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);
562     }
563     case CUBEB_SAMPLE_S16NE:
564       if (_context._clipping) {
565         auto f = [](int x) {
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;
570           }
571           return y;
572         };
573         return rematrix(&_context, static_cast<int16_t *>(output_buffer),
574                         static_cast<const int16_t *>(input_buffer),
575                         _context._matrix32, f, frames);
576       } else {
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);
581       }
582       break;
583     default:
584       assert(false);
585       break;
586     }
587 
588     return -1;
589   }
590 
591   // Return false if any of the input or ouput layout were invalid.
validcubeb_mixer592   bool valid() const { return _context._valid; }
593 
~cubeb_mixercubeb_mixer594   virtual ~cubeb_mixer(){};
595 
596   MixerContext _context;
597 };
598 
599 cubeb_mixer *
cubeb_mixer_create(cubeb_sample_format format,uint32_t in_channels,cubeb_channel_layout in_layout,uint32_t out_channels,cubeb_channel_layout out_layout)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)
603 {
604   return new cubeb_mixer(format, in_channels, in_layout, out_channels,
605                          out_layout);
606 }
607 
608 void
cubeb_mixer_destroy(cubeb_mixer * mixer)609 cubeb_mixer_destroy(cubeb_mixer * mixer)
610 {
611   delete mixer;
612 }
613 
614 int
cubeb_mixer_mix(cubeb_mixer * mixer,size_t frames,const void * input_buffer,size_t input_buffer_size,void * output_buffer,size_t output_buffer_size)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)
618 {
619   return mixer->mix(frames, input_buffer, input_buffer_size, output_buffer,
620                     output_buffer_size);
621 }
622