summaryrefslogtreecommitdiff
path: root/media/libcubeb/src/cubeb_mixer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libcubeb/src/cubeb_mixer.cpp')
-rw-r--r--media/libcubeb/src/cubeb_mixer.cpp625
1 files changed, 0 insertions, 625 deletions
diff --git a/media/libcubeb/src/cubeb_mixer.cpp b/media/libcubeb/src/cubeb_mixer.cpp
deleted file mode 100644
index 343e0e2d39..0000000000
--- a/media/libcubeb/src/cubeb_mixer.cpp
+++ /dev/null
@@ -1,625 +0,0 @@
-/*
- * Copyright © 2016 Mozilla Foundation
- *
- * This program is made available under an ISC-style license. See the
- * accompanying file LICENSE for details.
- *
- * Adapted from code based on libswresample's rematrix.c
- */
-
-#define NOMINMAX
-
-#include "cubeb_mixer.h"
-#include "cubeb-internal.h"
-#include "cubeb_utils.h"
-#include <algorithm>
-#include <cassert>
-#include <climits>
-#include <cmath>
-#include <cstdlib>
-#include <memory>
-#include <type_traits>
-
-#ifndef FF_ARRAY_ELEMS
-#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
-#endif
-
-#define CHANNELS_MAX 32
-#define FRONT_LEFT 0
-#define FRONT_RIGHT 1
-#define FRONT_CENTER 2
-#define LOW_FREQUENCY 3
-#define BACK_LEFT 4
-#define BACK_RIGHT 5
-#define FRONT_LEFT_OF_CENTER 6
-#define FRONT_RIGHT_OF_CENTER 7
-#define BACK_CENTER 8
-#define SIDE_LEFT 9
-#define SIDE_RIGHT 10
-#define TOP_CENTER 11
-#define TOP_FRONT_LEFT 12
-#define TOP_FRONT_CENTER 13
-#define TOP_FRONT_RIGHT 14
-#define TOP_BACK_LEFT 15
-#define TOP_BACK_CENTER 16
-#define TOP_BACK_RIGHT 17
-#define NUM_NAMED_CHANNELS 18
-
-#ifndef M_SQRT1_2
-#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */
-#endif
-#ifndef M_SQRT2
-#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
-#endif
-#define SQRT3_2 1.22474487139158904909 /* sqrt(3/2) */
-
-#define C30DB M_SQRT2
-#define C15DB 1.189207115
-#define C__0DB 1.0
-#define C_15DB 0.840896415
-#define C_30DB M_SQRT1_2
-#define C_45DB 0.594603558
-#define C_60DB 0.5
-
-static cubeb_channel_layout
-cubeb_channel_layout_check(cubeb_channel_layout l, uint32_t c)
-{
- if (l == CUBEB_LAYOUT_UNDEFINED) {
- switch (c) {
- case 1:
- return CUBEB_LAYOUT_MONO;
- case 2:
- return CUBEB_LAYOUT_STEREO;
- }
- }
- return l;
-}
-
-unsigned int
-cubeb_channel_layout_nb_channels(cubeb_channel_layout x)
-{
-#if __GNUC__ || __clang__
- return __builtin_popcount(x);
-#else
- x -= (x >> 1) & 0x55555555;
- x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
- x = (x + (x >> 4)) & 0x0F0F0F0F;
- x += x >> 8;
- return (x + (x >> 16)) & 0x3F;
-#endif
-}
-
-struct MixerContext {
- MixerContext(cubeb_sample_format f, uint32_t in_channels,
- cubeb_channel_layout in, uint32_t out_channels,
- cubeb_channel_layout out)
- : _format(f), _in_ch_layout(cubeb_channel_layout_check(in, in_channels)),
- _out_ch_layout(cubeb_channel_layout_check(out, out_channels)),
- _in_ch_count(in_channels), _out_ch_count(out_channels)
- {
- if (in_channels != cubeb_channel_layout_nb_channels(in) ||
- out_channels != cubeb_channel_layout_nb_channels(out)) {
- // Mismatch between channels and layout, aborting.
- return;
- }
- _valid = init() >= 0;
- }
-
- static bool even(cubeb_channel_layout layout)
- {
- if (!layout) {
- return true;
- }
- if (layout & (layout - 1)) {
- return true;
- }
- return false;
- }
-
- // Ensure that the layout is sane (that is have symmetrical left/right
- // channels), if not, layout will be treated as mono.
- static cubeb_channel_layout clean_layout(cubeb_channel_layout layout)
- {
- if (layout && layout != CHANNEL_FRONT_LEFT && !(layout & (layout - 1))) {
- LOG("Treating layout as mono");
- return CHANNEL_FRONT_CENTER;
- }
-
- return layout;
- }
-
- static bool sane_layout(cubeb_channel_layout layout)
- {
- if (!(layout & CUBEB_LAYOUT_3F)) { // at least 1 front speaker
- return false;
- }
- if (!even(layout & (CHANNEL_FRONT_LEFT |
- CHANNEL_FRONT_RIGHT))) { // no asymetric front
- return false;
- }
- if (!even(layout &
- (CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT))) { // no asymetric side
- return false;
- }
- if (!even(layout & (CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT))) {
- return false;
- }
- if (!even(layout &
- (CHANNEL_FRONT_LEFT_OF_CENTER | CHANNEL_FRONT_RIGHT_OF_CENTER))) {
- return false;
- }
- if (cubeb_channel_layout_nb_channels(layout) >= CHANNELS_MAX) {
- return false;
- }
- return true;
- }
-
- int auto_matrix();
- int init();
-
- const cubeb_sample_format _format;
- const cubeb_channel_layout _in_ch_layout; ///< input channel layout
- const cubeb_channel_layout _out_ch_layout; ///< output channel layout
- const uint32_t _in_ch_count; ///< input channel count
- const uint32_t _out_ch_count; ///< output channel count
- const float _surround_mix_level = C_30DB; ///< surround mixing level
- const float _center_mix_level = C_30DB; ///< center mixing level
- const float _lfe_mix_level = 1; ///< LFE mixing level
- double _matrix[CHANNELS_MAX][CHANNELS_MAX] = {
- {0}}; ///< floating point rematrixing coefficients
- float _matrix_flt[CHANNELS_MAX][CHANNELS_MAX] = {
- {0}}; ///< single precision floating point rematrixing coefficients
- int32_t _matrix32[CHANNELS_MAX][CHANNELS_MAX] = {
- {0}}; ///< 17.15 fixed point rematrixing coefficients
- uint8_t _matrix_ch[CHANNELS_MAX][CHANNELS_MAX + 1] = {
- {0}}; ///< Lists of input channels per output channel that have non zero
- ///< rematrixing coefficients
- bool _clipping = false; ///< Set to true if clipping detection is required
- bool _valid = false; ///< Set to true if context is valid.
-};
-
-int
-MixerContext::auto_matrix()
-{
- double matrix[NUM_NAMED_CHANNELS][NUM_NAMED_CHANNELS] = {{0}};
- double maxcoef = 0;
- float maxval;
-
- cubeb_channel_layout in_ch_layout = clean_layout(_in_ch_layout);
- cubeb_channel_layout out_ch_layout = clean_layout(_out_ch_layout);
-
- if (!sane_layout(in_ch_layout)) {
- // Channel Not Supported
- LOG("Input Layout %x is not supported", _in_ch_layout);
- return -1;
- }
-
- if (!sane_layout(out_ch_layout)) {
- LOG("Output Layout %x is not supported", _out_ch_layout);
- return -1;
- }
-
- for (uint32_t i = 0; i < FF_ARRAY_ELEMS(matrix); i++) {
- if (in_ch_layout & out_ch_layout & (1U << i)) {
- matrix[i][i] = 1.0;
- }
- }
-
- cubeb_channel_layout unaccounted = in_ch_layout & ~out_ch_layout;
-
- // Rematrixing is done via a matrix of coefficient that should be applied to
- // all channels. Channels are treated as pair and must be symmetrical (if a
- // left channel exists, the corresponding right should exist too) unless the
- // output layout has similar layout. Channels are then mixed toward the front
- // center or back center if they exist with a slight bias toward the front.
-
- if (unaccounted & CHANNEL_FRONT_CENTER) {
- if ((out_ch_layout & CUBEB_LAYOUT_STEREO) == CUBEB_LAYOUT_STEREO) {
- if (in_ch_layout & CUBEB_LAYOUT_STEREO) {
- matrix[FRONT_LEFT][FRONT_CENTER] += _center_mix_level;
- matrix[FRONT_RIGHT][FRONT_CENTER] += _center_mix_level;
- } else {
- matrix[FRONT_LEFT][FRONT_CENTER] += M_SQRT1_2;
- matrix[FRONT_RIGHT][FRONT_CENTER] += M_SQRT1_2;
- }
- }
- }
- if (unaccounted & CUBEB_LAYOUT_STEREO) {
- if (out_ch_layout & CHANNEL_FRONT_CENTER) {
- matrix[FRONT_CENTER][FRONT_LEFT] += M_SQRT1_2;
- matrix[FRONT_CENTER][FRONT_RIGHT] += M_SQRT1_2;
- if (in_ch_layout & CHANNEL_FRONT_CENTER)
- matrix[FRONT_CENTER][FRONT_CENTER] = _center_mix_level * M_SQRT2;
- }
- }
-
- if (unaccounted & CHANNEL_BACK_CENTER) {
- if (out_ch_layout & CHANNEL_BACK_LEFT) {
- matrix[BACK_LEFT][BACK_CENTER] += M_SQRT1_2;
- matrix[BACK_RIGHT][BACK_CENTER] += M_SQRT1_2;
- } else if (out_ch_layout & CHANNEL_SIDE_LEFT) {
- matrix[SIDE_LEFT][BACK_CENTER] += M_SQRT1_2;
- matrix[SIDE_RIGHT][BACK_CENTER] += M_SQRT1_2;
- } else if (out_ch_layout & CHANNEL_FRONT_LEFT) {
- matrix[FRONT_LEFT][BACK_CENTER] += _surround_mix_level * M_SQRT1_2;
- matrix[FRONT_RIGHT][BACK_CENTER] += _surround_mix_level * M_SQRT1_2;
- } else if (out_ch_layout & CHANNEL_FRONT_CENTER) {
- matrix[FRONT_CENTER][BACK_CENTER] += _surround_mix_level * M_SQRT1_2;
- }
- }
- if (unaccounted & CHANNEL_BACK_LEFT) {
- if (out_ch_layout & CHANNEL_BACK_CENTER) {
- matrix[BACK_CENTER][BACK_LEFT] += M_SQRT1_2;
- matrix[BACK_CENTER][BACK_RIGHT] += M_SQRT1_2;
- } else if (out_ch_layout & CHANNEL_SIDE_LEFT) {
- if (in_ch_layout & CHANNEL_SIDE_LEFT) {
- matrix[SIDE_LEFT][BACK_LEFT] += M_SQRT1_2;
- matrix[SIDE_RIGHT][BACK_RIGHT] += M_SQRT1_2;
- } else {
- matrix[SIDE_LEFT][BACK_LEFT] += 1.0;
- matrix[SIDE_RIGHT][BACK_RIGHT] += 1.0;
- }
- } else if (out_ch_layout & CHANNEL_FRONT_LEFT) {
- matrix[FRONT_LEFT][BACK_LEFT] += _surround_mix_level;
- matrix[FRONT_RIGHT][BACK_RIGHT] += _surround_mix_level;
- } else if (out_ch_layout & CHANNEL_FRONT_CENTER) {
- matrix[FRONT_CENTER][BACK_LEFT] += _surround_mix_level * M_SQRT1_2;
- matrix[FRONT_CENTER][BACK_RIGHT] += _surround_mix_level * M_SQRT1_2;
- }
- }
-
- if (unaccounted & CHANNEL_SIDE_LEFT) {
- if (out_ch_layout & CHANNEL_BACK_LEFT) {
- /* if back channels do not exist in the input, just copy side
- channels to back channels, otherwise mix side into back */
- if (in_ch_layout & CHANNEL_BACK_LEFT) {
- matrix[BACK_LEFT][SIDE_LEFT] += M_SQRT1_2;
- matrix[BACK_RIGHT][SIDE_RIGHT] += M_SQRT1_2;
- } else {
- matrix[BACK_LEFT][SIDE_LEFT] += 1.0;
- matrix[BACK_RIGHT][SIDE_RIGHT] += 1.0;
- }
- } else if (out_ch_layout & CHANNEL_BACK_CENTER) {
- matrix[BACK_CENTER][SIDE_LEFT] += M_SQRT1_2;
- matrix[BACK_CENTER][SIDE_RIGHT] += M_SQRT1_2;
- } else if (out_ch_layout & CHANNEL_FRONT_LEFT) {
- matrix[FRONT_LEFT][SIDE_LEFT] += _surround_mix_level;
- matrix[FRONT_RIGHT][SIDE_RIGHT] += _surround_mix_level;
- } else if (out_ch_layout & CHANNEL_FRONT_CENTER) {
- matrix[FRONT_CENTER][SIDE_LEFT] += _surround_mix_level * M_SQRT1_2;
- matrix[FRONT_CENTER][SIDE_RIGHT] += _surround_mix_level * M_SQRT1_2;
- }
- }
-
- if (unaccounted & CHANNEL_FRONT_LEFT_OF_CENTER) {
- if (out_ch_layout & CHANNEL_FRONT_LEFT) {
- matrix[FRONT_LEFT][FRONT_LEFT_OF_CENTER] += 1.0;
- matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER] += 1.0;
- } else if (out_ch_layout & CHANNEL_FRONT_CENTER) {
- matrix[FRONT_CENTER][FRONT_LEFT_OF_CENTER] += M_SQRT1_2;
- matrix[FRONT_CENTER][FRONT_RIGHT_OF_CENTER] += M_SQRT1_2;
- }
- }
- /* mix LFE into front left/right or center */
- if (unaccounted & CHANNEL_LOW_FREQUENCY) {
- if (out_ch_layout & CHANNEL_FRONT_CENTER) {
- matrix[FRONT_CENTER][LOW_FREQUENCY] += _lfe_mix_level;
- } else if (out_ch_layout & CHANNEL_FRONT_LEFT) {
- matrix[FRONT_LEFT][LOW_FREQUENCY] += _lfe_mix_level * M_SQRT1_2;
- matrix[FRONT_RIGHT][LOW_FREQUENCY] += _lfe_mix_level * M_SQRT1_2;
- }
- }
-
- // Normalize the conversion matrix.
- for (uint32_t out_i = 0, i = 0; i < CHANNELS_MAX; i++) {
- double sum = 0;
- int in_i = 0;
- if ((out_ch_layout & (1U << i)) == 0) {
- continue;
- }
- for (uint32_t j = 0; j < CHANNELS_MAX; j++) {
- if ((in_ch_layout & (1U << j)) == 0) {
- continue;
- }
- if (i < FF_ARRAY_ELEMS(matrix) && j < FF_ARRAY_ELEMS(matrix[0])) {
- _matrix[out_i][in_i] = matrix[i][j];
- } else {
- _matrix[out_i][in_i] =
- i == j && (in_ch_layout & out_ch_layout & (1U << i));
- }
- sum += fabs(_matrix[out_i][in_i]);
- in_i++;
- }
- maxcoef = std::max(maxcoef, sum);
- out_i++;
- }
-
- if (_format == CUBEB_SAMPLE_S16NE) {
- maxval = 1.0;
- } else {
- maxval = INT_MAX;
- }
-
- // Normalize matrix if needed.
- if (maxcoef > maxval) {
- maxcoef /= maxval;
- for (uint32_t i = 0; i < CHANNELS_MAX; i++)
- for (uint32_t j = 0; j < CHANNELS_MAX; j++) {
- _matrix[i][j] /= maxcoef;
- }
- }
-
- if (_format == CUBEB_SAMPLE_FLOAT32NE) {
- for (uint32_t i = 0; i < FF_ARRAY_ELEMS(_matrix); i++) {
- for (uint32_t j = 0; j < FF_ARRAY_ELEMS(_matrix[0]); j++) {
- _matrix_flt[i][j] = _matrix[i][j];
- }
- }
- }
-
- return 0;
-}
-
-int
-MixerContext::init()
-{
- int r = auto_matrix();
- if (r) {
- return r;
- }
-
- // Determine if matrix operation would overflow
- if (_format == CUBEB_SAMPLE_S16NE) {
- int maxsum = 0;
- for (uint32_t i = 0; i < _out_ch_count; i++) {
- double rem = 0;
- int sum = 0;
-
- for (uint32_t j = 0; j < _in_ch_count; j++) {
- double target = _matrix[i][j] * 32768 + rem;
- int value = lrintf(target);
- rem += target - value;
- sum += std::abs(value);
- }
- maxsum = std::max(maxsum, sum);
- }
- if (maxsum > 32768) {
- _clipping = true;
- }
- }
-
- // FIXME quantize for integers
- for (uint32_t i = 0; i < CHANNELS_MAX; i++) {
- int ch_in = 0;
- for (uint32_t j = 0; j < CHANNELS_MAX; j++) {
- _matrix32[i][j] = lrintf(_matrix[i][j] * 32768);
- if (_matrix[i][j]) {
- _matrix_ch[i][++ch_in] = j;
- }
- }
- _matrix_ch[i][0] = ch_in;
- }
-
- return 0;
-}
-
-template <typename TYPE_SAMPLE, typename TYPE_COEFF, typename F>
-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)
-{
- static_assert(
- std::is_same<TYPE_COEFF,
- typename std::result_of<F(TYPE_COEFF)>::type>::value,
- "function must return the same type as used by matrix_coeff");
- for (uint32_t i = 0; i < frames; i++) {
- *out = operand(coeff1 * *in1 + coeff2 * *in2);
- out += stride_out;
- in1 += stride_in;
- in2 += stride_in;
- }
-}
-
-template <typename TYPE_SAMPLE, typename TYPE_COEFF, typename F>
-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)
-{
- static_assert(
- std::is_same<TYPE_COEFF,
- typename std::result_of<F(TYPE_COEFF)>::type>::value,
- "function must return the same type as used by matrix_coeff");
- for (uint32_t i = 0; i < frames; i++) {
- *out = operand(coeff * *in);
- out += stride_out;
- in += stride_in;
- }
-}
-
-template <typename TYPE, typename TYPE_COEFF, size_t COLS, typename F>
-static int
-rematrix(const MixerContext * s, TYPE * aOut, const TYPE * aIn,
- const TYPE_COEFF (&matrix_coeff)[COLS][COLS], F && aF, uint32_t frames)
-{
- static_assert(
- std::is_same<TYPE_COEFF,
- typename std::result_of<F(TYPE_COEFF)>::type>::value,
- "function must return the same type as used by matrix_coeff");
-
- for (uint32_t out_i = 0; out_i < s->_out_ch_count; out_i++) {
- TYPE * out = aOut + out_i;
- switch (s->_matrix_ch[out_i][0]) {
- case 0:
- for (uint32_t i = 0; i < frames; i++) {
- out[i * s->_out_ch_count] = 0;
- }
- break;
- case 1: {
- int in_i = s->_matrix_ch[out_i][1];
- copy(out, s->_out_ch_count, aIn + in_i, s->_in_ch_count,
- matrix_coeff[out_i][in_i], aF, frames);
- } break;
- case 2:
- sum2(out, s->_out_ch_count, aIn + s->_matrix_ch[out_i][1],
- aIn + s->_matrix_ch[out_i][2], s->_in_ch_count,
- matrix_coeff[out_i][s->_matrix_ch[out_i][1]],
- matrix_coeff[out_i][s->_matrix_ch[out_i][2]], aF, frames);
- break;
- default:
- for (uint32_t i = 0; i < frames; i++) {
- TYPE_COEFF v = 0;
- for (uint32_t j = 0; j < s->_matrix_ch[out_i][0]; j++) {
- uint32_t in_i = s->_matrix_ch[out_i][1 + j];
- v += *(aIn + in_i + i * s->_in_ch_count) * matrix_coeff[out_i][in_i];
- }
- out[i * s->_out_ch_count] = aF(v);
- }
- break;
- }
- }
- return 0;
-}
-
-struct cubeb_mixer {
- cubeb_mixer(cubeb_sample_format format, uint32_t in_channels,
- cubeb_channel_layout in_layout, uint32_t out_channels,
- cubeb_channel_layout out_layout)
- : _context(format, in_channels, in_layout, out_channels, out_layout)
- {
- }
-
- template <typename T>
- void copy_and_trunc(size_t frames, const T * input_buffer,
- T * output_buffer) const
- {
- if (_context._in_ch_count <= _context._out_ch_count) {
- // Not enough channels to copy, fill the gaps with silence.
- if (_context._in_ch_count == 1 && _context._out_ch_count >= 2) {
- // Special case for upmixing mono input to stereo and more. We will
- // duplicate the mono channel to the first two channels. On most system,
- // the first two channels are for left and right. It is commonly
- // expected that mono will on both left+right channels
- for (uint32_t i = 0; i < frames; i++) {
- output_buffer[0] = output_buffer[1] = *input_buffer;
- PodZero(output_buffer + 2, _context._out_ch_count - 2);
- output_buffer += _context._out_ch_count;
- input_buffer++;
- }
- return;
- }
- for (uint32_t i = 0; i < frames; i++) {
- PodCopy(output_buffer, input_buffer, _context._in_ch_count);
- output_buffer += _context._in_ch_count;
- input_buffer += _context._in_ch_count;
- PodZero(output_buffer, _context._out_ch_count - _context._in_ch_count);
- output_buffer += _context._out_ch_count - _context._in_ch_count;
- }
- } else {
- for (uint32_t i = 0; i < frames; i++) {
- PodCopy(output_buffer, input_buffer, _context._out_ch_count);
- output_buffer += _context._out_ch_count;
- input_buffer += _context._in_ch_count;
- }
- }
- }
-
- int mix(size_t frames, const void * input_buffer, size_t input_buffer_size,
- void * output_buffer, size_t output_buffer_size) const
- {
- if (frames <= 0 || _context._out_ch_count == 0) {
- return 0;
- }
-
- // Check if output buffer is of sufficient size.
- size_t size_read_needed =
- frames * _context._in_ch_count * cubeb_sample_size(_context._format);
- if (input_buffer_size < size_read_needed) {
- // We don't have enough data to read!
- return -1;
- }
- if (output_buffer_size * _context._in_ch_count <
- size_read_needed * _context._out_ch_count) {
- return -1;
- }
-
- if (!valid()) {
- // The channel layouts were invalid or unsupported, instead we will simply
- // either drop the extra channels, or fill with silence the missing ones
- if (_context._format == CUBEB_SAMPLE_FLOAT32NE) {
- copy_and_trunc(frames, static_cast<const float *>(input_buffer),
- static_cast<float *>(output_buffer));
- } else {
- assert(_context._format == CUBEB_SAMPLE_S16NE);
- copy_and_trunc(frames, static_cast<const int16_t *>(input_buffer),
- reinterpret_cast<int16_t *>(output_buffer));
- }
- return 0;
- }
-
- switch (_context._format) {
- case CUBEB_SAMPLE_FLOAT32NE: {
- auto f = [](float x) { return x; };
- return rematrix(&_context, static_cast<float *>(output_buffer),
- static_cast<const float *>(input_buffer),
- _context._matrix_flt, f, frames);
- }
- case CUBEB_SAMPLE_S16NE:
- if (_context._clipping) {
- auto f = [](int x) {
- int y = (x + 16384) >> 15;
- // clip the signed integer value into the -32768,32767 range.
- if ((y + 0x8000U) & ~0xFFFF) {
- return (y >> 31) ^ 0x7FFF;
- }
- return y;
- };
- return rematrix(&_context, static_cast<int16_t *>(output_buffer),
- static_cast<const int16_t *>(input_buffer),
- _context._matrix32, f, frames);
- } else {
- auto f = [](int x) { return (x + 16384) >> 15; };
- return rematrix(&_context, static_cast<int16_t *>(output_buffer),
- static_cast<const int16_t *>(input_buffer),
- _context._matrix32, f, frames);
- }
- break;
- default:
- assert(false);
- break;
- }
-
- return -1;
- }
-
- // Return false if any of the input or ouput layout were invalid.
- bool valid() const { return _context._valid; }
-
- virtual ~cubeb_mixer(){};
-
- MixerContext _context;
-};
-
-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)
-{
- return new cubeb_mixer(format, in_channels, in_layout, out_channels,
- out_layout);
-}
-
-void
-cubeb_mixer_destroy(cubeb_mixer * mixer)
-{
- delete mixer;
-}
-
-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)
-{
- return mixer->mix(frames, input_buffer, input_buffer_size, output_buffer,
- output_buffer_size);
-}