| /* 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" |
| |
| #ifdef ENABLE_EXPERIMENTAL_AMBISONICS |
| |
| #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) |
| { |
| return (opus_int16*)((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 |
| }; |
| |
| #endif /* ENABLE_EXPERIMENTAL_AMBISONICS */ |