| /* Copyright (c) 2017 Google Inc. | |
| Written by Andrew Allen */ | |
| /* | |
| Redistribution and use in source and binary forms, with or without | |
| modification, are permitted provided that the following conditions | |
| are met: | |
| - Redistributions of source code must retain the above copyright | |
| notice, this list of conditions and the following disclaimer. | |
| - Redistributions in binary form must reproduce the above copyright | |
| notice, this list of conditions and the following disclaimer in the | |
| documentation and/or other materials provided with the distribution. | |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER | |
| OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
| LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
| NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| #ifdef HAVE_CONFIG_H | |
| #include "config.h" | |
| #endif | |
| #include "arch.h" | |
| #include "float_cast.h" | |
| #include "opus_private.h" | |
| #include "opus_defines.h" | |
| #include "mapping_matrix.h" | |
| #define MATRIX_INDEX(nb_rows, row, col) (nb_rows * col + row) | |
| opus_int32 mapping_matrix_get_size(int rows, int cols) | |
| { | |
| opus_int32 size; | |
| /* Mapping Matrix must only support up to 255 channels in or out. | |
| * Additionally, the total cell count must be <= 65004 octets in order | |
| * for the matrix to be stored in an OGG header. | |
| */ | |
| if (rows > 255 || cols > 255) | |
| return 0; | |
| size = rows * (opus_int32)cols * sizeof(opus_int16); | |
| if (size > 65004) | |
| return 0; | |
| return align(sizeof(MappingMatrix)) + align(size); | |
| } | |
| opus_int16 *mapping_matrix_get_data(const MappingMatrix *matrix) | |
| { | |
| /* void* cast avoids clang -Wcast-align warning */ | |
| return (opus_int16*)(void*)((char*)matrix + align(sizeof(MappingMatrix))); | |
| } | |
| void mapping_matrix_init(MappingMatrix * const matrix, | |
| int rows, int cols, int gain, const opus_int16 *data, opus_int32 data_size) | |
| { | |
| int i; | |
| opus_int16 *ptr; | |
| #if !defined(ENABLE_ASSERTIONS) | |
| (void)data_size; | |
| #endif | |
| celt_assert(align(data_size) == align(rows * cols * sizeof(opus_int16))); | |
| matrix->rows = rows; | |
| matrix->cols = cols; | |
| matrix->gain = gain; | |
| ptr = mapping_matrix_get_data(matrix); | |
| for (i = 0; i < rows * cols; i++) | |
| { | |
| ptr[i] = data[i]; | |
| } | |
| } | |
| #ifndef DISABLE_FLOAT_API | |
| void mapping_matrix_multiply_channel_in_float( | |
| const MappingMatrix *matrix, | |
| const float *input, | |
| int input_rows, | |
| opus_val16 *output, | |
| int output_row, | |
| int output_rows, | |
| int frame_size) | |
| { | |
| /* Matrix data is ordered col-wise. */ | |
| opus_int16* matrix_data; | |
| int i, col; | |
| celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); | |
| matrix_data = mapping_matrix_get_data(matrix); | |
| for (i = 0; i < frame_size; i++) | |
| { | |
| float tmp = 0; | |
| for (col = 0; col < input_rows; col++) | |
| { | |
| tmp += | |
| matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * | |
| input[MATRIX_INDEX(input_rows, col, i)]; | |
| } | |
| #if defined(FIXED_POINT) | |
| output[output_rows * i] = FLOAT2INT16((1/32768.f)*tmp); | |
| #else | |
| output[output_rows * i] = (1/32768.f)*tmp; | |
| #endif | |
| } | |
| } | |
| void mapping_matrix_multiply_channel_out_float( | |
| const MappingMatrix *matrix, | |
| const opus_val16 *input, | |
| int input_row, | |
| int input_rows, | |
| float *output, | |
| int output_rows, | |
| int frame_size | |
| ) | |
| { | |
| /* Matrix data is ordered col-wise. */ | |
| opus_int16* matrix_data; | |
| int i, row; | |
| float input_sample; | |
| celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); | |
| matrix_data = mapping_matrix_get_data(matrix); | |
| for (i = 0; i < frame_size; i++) | |
| { | |
| #if defined(FIXED_POINT) | |
| input_sample = (1/32768.f)*input[input_rows * i]; | |
| #else | |
| input_sample = input[input_rows * i]; | |
| #endif | |
| for (row = 0; row < output_rows; row++) | |
| { | |
| float tmp = | |
| (1/32768.f)*matrix_data[MATRIX_INDEX(matrix->rows, row, input_row)] * | |
| input_sample; | |
| output[MATRIX_INDEX(output_rows, row, i)] += tmp; | |
| } | |
| } | |
| } | |
| #endif /* DISABLE_FLOAT_API */ | |
| void mapping_matrix_multiply_channel_in_short( | |
| const MappingMatrix *matrix, | |
| const opus_int16 *input, | |
| int input_rows, | |
| opus_val16 *output, | |
| int output_row, | |
| int output_rows, | |
| int frame_size) | |
| { | |
| /* Matrix data is ordered col-wise. */ | |
| opus_int16* matrix_data; | |
| int i, col; | |
| celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); | |
| matrix_data = mapping_matrix_get_data(matrix); | |
| for (i = 0; i < frame_size; i++) | |
| { | |
| opus_val32 tmp = 0; | |
| for (col = 0; col < input_rows; col++) | |
| { | |
| #if defined(FIXED_POINT) | |
| tmp += | |
| ((opus_int32)matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * | |
| (opus_int32)input[MATRIX_INDEX(input_rows, col, i)]) >> 8; | |
| #else | |
| tmp += | |
| matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * | |
| input[MATRIX_INDEX(input_rows, col, i)]; | |
| #endif | |
| } | |
| #if defined(FIXED_POINT) | |
| output[output_rows * i] = (opus_int16)((tmp + 64) >> 7); | |
| #else | |
| output[output_rows * i] = (1/(32768.f*32768.f))*tmp; | |
| #endif | |
| } | |
| } | |
| void mapping_matrix_multiply_channel_out_short( | |
| const MappingMatrix *matrix, | |
| const opus_val16 *input, | |
| int input_row, | |
| int input_rows, | |
| opus_int16 *output, | |
| int output_rows, | |
| int frame_size) | |
| { | |
| /* Matrix data is ordered col-wise. */ | |
| opus_int16* matrix_data; | |
| int i, row; | |
| opus_int32 input_sample; | |
| celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); | |
| matrix_data = mapping_matrix_get_data(matrix); | |
| for (i = 0; i < frame_size; i++) | |
| { | |
| #if defined(FIXED_POINT) | |
| input_sample = (opus_int32)input[input_rows * i]; | |
| #else | |
| input_sample = (opus_int32)FLOAT2INT16(input[input_rows * i]); | |
| #endif | |
| for (row = 0; row < output_rows; row++) | |
| { | |
| opus_int32 tmp = | |
| (opus_int32)matrix_data[MATRIX_INDEX(matrix->rows, row, input_row)] * | |
| input_sample; | |
| output[MATRIX_INDEX(output_rows, row, i)] += (tmp + 16384) >> 15; | |
| } | |
| } | |
| } | |
| const MappingMatrix mapping_matrix_foa_mixing = { 6, 6, 0 }; | |
| const opus_int16 mapping_matrix_foa_mixing_data[36] = { | |
| 16384, 0, -16384, 23170, 0, 0, 16384, 23170, | |
| 16384, 0, 0, 0, 16384, 0, -16384, -23170, | |
| 0, 0, 16384, -23170, 16384, 0, 0, 0, | |
| 0, 0, 0, 0, 32767, 0, 0, 0, | |
| 0, 0, 0, 32767 | |
| }; | |
| const MappingMatrix mapping_matrix_soa_mixing = { 11, 11, 0 }; | |
| const opus_int16 mapping_matrix_soa_mixing_data[121] = { | |
| 10923, 7723, 13377, -13377, 11585, 9459, 7723, -16384, | |
| -6689, 0, 0, 10923, 7723, 13377, 13377, -11585, | |
| 9459, 7723, 16384, -6689, 0, 0, 10923, -15447, | |
| 13377, 0, 0, -18919, 7723, 0, 13377, 0, | |
| 0, 10923, 7723, -13377, -13377, 11585, -9459, 7723, | |
| 16384, -6689, 0, 0, 10923, -7723, 0, 13377, | |
| -16384, 0, -15447, 0, 9459, 0, 0, 10923, | |
| -7723, 0, -13377, 16384, 0, -15447, 0, 9459, | |
| 0, 0, 10923, 15447, 0, 0, 0, 0, | |
| -15447, 0, -18919, 0, 0, 10923, 7723, -13377, | |
| 13377, -11585, -9459, 7723, -16384, -6689, 0, 0, | |
| 10923, -15447, -13377, 0, 0, 18919, 7723, 0, | |
| 13377, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 32767, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, | |
| 32767 | |
| }; | |
| const MappingMatrix mapping_matrix_toa_mixing = { 18, 18, 0 }; | |
| const opus_int16 mapping_matrix_toa_mixing_data[324] = { | |
| 8208, 0, -881, 14369, 0, 0, -8192, -4163, | |
| 13218, 0, 0, 0, 11095, -8836, -6218, 14833, | |
| 0, 0, 8208, -10161, 881, 10161, -13218, -2944, | |
| -8192, 2944, 0, -10488, -6218, 6248, -11095, -6248, | |
| 0, -10488, 0, 0, 8208, 10161, 881, -10161, | |
| -13218, 2944, -8192, -2944, 0, 10488, -6218, -6248, | |
| -11095, 6248, 0, 10488, 0, 0, 8176, 5566, | |
| -11552, 5566, 9681, -11205, 8192, -11205, 0, 4920, | |
| -15158, 9756, -3334, 9756, 0, -4920, 0, 0, | |
| 8176, 7871, 11552, 0, 0, 15846, 8192, 0, | |
| -9681, -6958, 0, 13797, 3334, 0, -15158, 0, | |
| 0, 0, 8176, 0, 11552, 7871, 0, 0, | |
| 8192, 15846, 9681, 0, 0, 0, 3334, 13797, | |
| 15158, 6958, 0, 0, 8176, 5566, -11552, -5566, | |
| -9681, -11205, 8192, 11205, 0, 4920, 15158, 9756, | |
| -3334, -9756, 0, 4920, 0, 0, 8208, 14369, | |
| -881, 0, 0, -4163, -8192, 0, -13218, -14833, | |
| 0, -8836, 11095, 0, 6218, 0, 0, 0, | |
| 8208, 10161, 881, 10161, 13218, 2944, -8192, 2944, | |
| 0, 10488, 6218, -6248, -11095, -6248, 0, -10488, | |
| 0, 0, 8208, -14369, -881, 0, 0, 4163, | |
| -8192, 0, -13218, 14833, 0, 8836, 11095, 0, | |
| 6218, 0, 0, 0, 8208, 0, -881, -14369, | |
| 0, 0, -8192, 4163, 13218, 0, 0, 0, | |
| 11095, 8836, -6218, -14833, 0, 0, 8176, -5566, | |
| -11552, 5566, -9681, 11205, 8192, -11205, 0, -4920, | |
| 15158, -9756, -3334, 9756, 0, -4920, 0, 0, | |
| 8176, 0, 11552, -7871, 0, 0, 8192, -15846, | |
| 9681, 0, 0, 0, 3334, -13797, 15158, -6958, | |
| 0, 0, 8176, -7871, 11552, 0, 0, -15846, | |
| 8192, 0, -9681, 6958, 0, -13797, 3334, 0, | |
| -15158, 0, 0, 0, 8176, -5566, -11552, -5566, | |
| 9681, 11205, 8192, 11205, 0, -4920, -15158, -9756, | |
| -3334, -9756, 0, 4920, 0, 0, 8208, -10161, | |
| 881, -10161, 13218, -2944, -8192, -2944, 0, -10488, | |
| 6218, 6248, -11095, 6248, 0, 10488, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, | |
| 32767, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 32767 | |
| }; | |
| const MappingMatrix mapping_matrix_foa_demixing = { 6, 6, 0 }; | |
| const opus_int16 mapping_matrix_foa_demixing_data[36] = { | |
| 16384, 16384, 16384, 16384, 0, 0, 0, 23170, | |
| 0, -23170, 0, 0, -16384, 16384, -16384, 16384, | |
| 0, 0, 23170, 0, -23170, 0, 0, 0, | |
| 0, 0, 0, 0, 32767, 0, 0, 0, | |
| 0, 0, 0, 32767 | |
| }; | |
| const MappingMatrix mapping_matrix_soa_demixing = { 11, 11, 3050 }; | |
| const opus_int16 mapping_matrix_soa_demixing_data[121] = { | |
| 2771, 2771, 2771, 2771, 2771, 2771, 2771, 2771, | |
| 2771, 0, 0, 10033, 10033, -20066, 10033, 14189, | |
| 14189, -28378, 10033, -20066, 0, 0, 3393, 3393, | |
| 3393, -3393, 0, 0, 0, -3393, -3393, 0, | |
| 0, -17378, 17378, 0, -17378, -24576, 24576, 0, | |
| 17378, 0, 0, 0, -14189, 14189, 0, -14189, | |
| -28378, 28378, 0, 14189, 0, 0, 0, 2399, | |
| 2399, -4799, -2399, 0, 0, 0, -2399, 4799, | |
| 0, 0, 1959, 1959, 1959, 1959, -3918, -3918, | |
| -3918, 1959, 1959, 0, 0, -4156, 4156, 0, | |
| 4156, 0, 0, 0, -4156, 0, 0, 0, | |
| 8192, 8192, -16384, 8192, 16384, 16384, -32768, 8192, | |
| -16384, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 8312, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, | |
| 8312 | |
| }; | |
| const MappingMatrix mapping_matrix_toa_demixing = { 18, 18, 0 }; | |
| const opus_int16 mapping_matrix_toa_demixing_data[324] = { | |
| 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, | |
| 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, | |
| 0, 0, 0, -9779, 9779, 6263, 8857, 0, | |
| 6263, 13829, 9779, -13829, 0, -6263, 0, -8857, | |
| -6263, -9779, 0, 0, -3413, 3413, 3413, -11359, | |
| 11359, 11359, -11359, -3413, 3413, -3413, -3413, -11359, | |
| 11359, 11359, -11359, 3413, 0, 0, 13829, 9779, | |
| -9779, 6263, 0, 8857, -6263, 0, 9779, 0, | |
| -13829, 6263, -8857, 0, -6263, -9779, 0, 0, | |
| 0, -15617, -15617, 6406, 0, 0, -6406, 0, | |
| 15617, 0, 0, -6406, 0, 0, 6406, 15617, | |
| 0, 0, 0, -5003, 5003, -10664, 15081, 0, | |
| -10664, -7075, 5003, 7075, 0, 10664, 0, -15081, | |
| 10664, -5003, 0, 0, -8176, -8176, -8176, 8208, | |
| 8208, 8208, 8208, -8176, -8176, -8176, -8176, 8208, | |
| 8208, 8208, 8208, -8176, 0, 0, -7075, 5003, | |
| -5003, -10664, 0, 15081, 10664, 0, 5003, 0, | |
| 7075, -10664, -15081, 0, 10664, -5003, 0, 0, | |
| 15617, 0, 0, 0, -6406, 6406, 0, -15617, | |
| 0, -15617, 15617, 0, 6406, -6406, 0, 0, | |
| 0, 0, 0, -11393, 11393, 2993, -4233, 0, | |
| 2993, -16112, 11393, 16112, 0, -2993, 0, 4233, | |
| -2993, -11393, 0, 0, 0, -9974, -9974, -13617, | |
| 0, 0, 13617, 0, 9974, 0, 0, 13617, | |
| 0, 0, -13617, 9974, 0, 0, 0, 5579, | |
| -5579, 10185, 14403, 0, 10185, -7890, -5579, 7890, | |
| 0, -10185, 0, -14403, -10185, 5579, 0, 0, | |
| 11826, -11826, -11826, -901, 901, 901, -901, 11826, | |
| -11826, 11826, 11826, -901, 901, 901, -901, -11826, | |
| 0, 0, -7890, -5579, 5579, 10185, 0, 14403, | |
| -10185, 0, -5579, 0, 7890, 10185, -14403, 0, | |
| -10185, 5579, 0, 0, -9974, 0, 0, 0, | |
| -13617, 13617, 0, 9974, 0, 9974, -9974, 0, | |
| 13617, -13617, 0, 0, 0, 0, 16112, -11393, | |
| 11393, -2993, 0, 4233, 2993, 0, -11393, 0, | |
| -16112, -2993, -4233, 0, 2993, 11393, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, | |
| 32767, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 32767 | |
| }; | |