Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 1 | /* Copyright (c) 2017 Google Inc. |
| 2 | Written by Andrew Allen */ |
| 3 | /* |
| 4 | Redistribution and use in source and binary forms, with or without |
| 5 | modification, are permitted provided that the following conditions |
| 6 | are met: |
| 7 | |
| 8 | - Redistributions of source code must retain the above copyright |
| 9 | notice, this list of conditions and the following disclaimer. |
| 10 | |
| 11 | - Redistributions in binary form must reproduce the above copyright |
| 12 | notice, this list of conditions and the following disclaimer in the |
| 13 | documentation and/or other materials provided with the distribution. |
| 14 | |
| 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 16 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER |
| 19 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| 24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 26 | */ |
| 27 | |
| 28 | #ifdef HAVE_CONFIG_H |
| 29 | #include "config.h" |
| 30 | #endif |
| 31 | |
| 32 | #include "mathops.h" |
| 33 | #include "os_support.h" |
| 34 | #include "opus_private.h" |
| 35 | #include "opus_defines.h" |
| 36 | #include "opus_projection.h" |
| 37 | #include "opus_multistream.h" |
| 38 | #include "stack_alloc.h" |
| 39 | #include "mapping_matrix.h" |
| 40 | |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 41 | struct OpusProjectionEncoder |
| 42 | { |
Andrew Allen | 65f11d3 | 2017-12-04 15:32:18 -0800 | [diff] [blame] | 43 | opus_int32 mixing_matrix_size_in_bytes; |
| 44 | opus_int32 demixing_matrix_size_in_bytes; |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 45 | /* Encoder states go here */ |
| 46 | }; |
| 47 | |
Andrew Allen | 65f11d3 | 2017-12-04 15:32:18 -0800 | [diff] [blame] | 48 | #if !defined(DISABLE_FLOAT_API) |
| 49 | static void opus_projection_copy_channel_in_float( |
| 50 | opus_val16 *dst, |
| 51 | int dst_stride, |
| 52 | const void *src, |
| 53 | int src_stride, |
| 54 | int src_channel, |
| 55 | int frame_size, |
| 56 | void *user_data |
| 57 | ) |
| 58 | { |
| 59 | mapping_matrix_multiply_channel_in_float((const MappingMatrix*)user_data, |
| 60 | (const float*)src, src_stride, dst, src_channel, dst_stride, frame_size); |
| 61 | } |
| 62 | #endif |
| 63 | |
| 64 | static void opus_projection_copy_channel_in_short( |
| 65 | opus_val16 *dst, |
| 66 | int dst_stride, |
| 67 | const void *src, |
| 68 | int src_stride, |
| 69 | int src_channel, |
| 70 | int frame_size, |
| 71 | void *user_data |
| 72 | ) |
| 73 | { |
| 74 | mapping_matrix_multiply_channel_in_short((const MappingMatrix*)user_data, |
| 75 | (const opus_int16*)src, src_stride, dst, src_channel, dst_stride, frame_size); |
| 76 | } |
| 77 | |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 78 | static int get_order_plus_one_from_channels(int channels, int *order_plus_one) |
| 79 | { |
| 80 | int order_plus_one_; |
| 81 | int acn_channels; |
| 82 | int nondiegetic_channels; |
| 83 | |
| 84 | /* Allowed numbers of channels: |
| 85 | * (1 + n)^2 + 2j, for n = 0...14 and j = 0 or 1. |
| 86 | */ |
Mark Harris | 697beca | 2018-05-27 17:47:28 -0700 | [diff] [blame] | 87 | if (channels < 1 || channels > 227) |
| 88 | return OPUS_BAD_ARG; |
| 89 | |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 90 | order_plus_one_ = isqrt32(channels); |
| 91 | acn_channels = order_plus_one_ * order_plus_one_; |
| 92 | nondiegetic_channels = channels - acn_channels; |
Mark Harris | 697beca | 2018-05-27 17:47:28 -0700 | [diff] [blame] | 93 | if (nondiegetic_channels != 0 && nondiegetic_channels != 2) |
| 94 | return OPUS_BAD_ARG; |
| 95 | |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 96 | if (order_plus_one) |
| 97 | *order_plus_one = order_plus_one_; |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 98 | return OPUS_OK; |
| 99 | } |
| 100 | |
| 101 | static int get_streams_from_channels(int channels, int mapping_family, |
| 102 | int *streams, int *coupled_streams, |
| 103 | int *order_plus_one) |
| 104 | { |
Jean-Marc Valin | 6a74b41 | 2018-06-15 16:52:14 -0400 | [diff] [blame] | 105 | if (mapping_family == 3) |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 106 | { |
| 107 | if (get_order_plus_one_from_channels(channels, order_plus_one) != OPUS_OK) |
| 108 | return OPUS_BAD_ARG; |
| 109 | if (streams) |
| 110 | *streams = (channels + 1) / 2; |
| 111 | if (coupled_streams) |
| 112 | *coupled_streams = channels / 2; |
| 113 | return OPUS_OK; |
| 114 | } |
| 115 | return OPUS_BAD_ARG; |
| 116 | } |
| 117 | |
| 118 | static MappingMatrix *get_mixing_matrix(OpusProjectionEncoder *st) |
| 119 | { |
Mark Harris | 01b035f | 2018-07-21 17:55:24 -0700 | [diff] [blame] | 120 | /* void* cast avoids clang -Wcast-align warning */ |
| 121 | return (MappingMatrix *)(void*)((char*)st + |
| 122 | align(sizeof(OpusProjectionEncoder))); |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 123 | } |
| 124 | |
| 125 | static MappingMatrix *get_demixing_matrix(OpusProjectionEncoder *st) |
| 126 | { |
Mark Harris | 01b035f | 2018-07-21 17:55:24 -0700 | [diff] [blame] | 127 | /* void* cast avoids clang -Wcast-align warning */ |
| 128 | return (MappingMatrix *)(void*)((char*)st + |
| 129 | align(sizeof(OpusProjectionEncoder) + |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 130 | st->mixing_matrix_size_in_bytes)); |
| 131 | } |
| 132 | |
| 133 | static OpusMSEncoder *get_multistream_encoder(OpusProjectionEncoder *st) |
| 134 | { |
Mark Harris | 01b035f | 2018-07-21 17:55:24 -0700 | [diff] [blame] | 135 | /* void* cast avoids clang -Wcast-align warning */ |
| 136 | return (OpusMSEncoder *)(void*)((char*)st + |
| 137 | align(sizeof(OpusProjectionEncoder) + |
| 138 | st->mixing_matrix_size_in_bytes + |
| 139 | st->demixing_matrix_size_in_bytes)); |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 140 | } |
| 141 | |
| 142 | opus_int32 opus_projection_ambisonics_encoder_get_size(int channels, |
| 143 | int mapping_family) |
| 144 | { |
| 145 | int nb_streams; |
| 146 | int nb_coupled_streams; |
| 147 | int order_plus_one; |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 148 | int mixing_matrix_rows, mixing_matrix_cols; |
| 149 | int demixing_matrix_rows, demixing_matrix_cols; |
| 150 | opus_int32 mixing_matrix_size, demixing_matrix_size; |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 151 | opus_int32 encoder_size; |
| 152 | int ret; |
| 153 | |
| 154 | ret = get_streams_from_channels(channels, mapping_family, &nb_streams, |
| 155 | &nb_coupled_streams, &order_plus_one); |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 156 | if (ret != OPUS_OK) |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 157 | return 0; |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 158 | |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 159 | if (order_plus_one == 2) |
| 160 | { |
| 161 | mixing_matrix_rows = mapping_matrix_foa_mixing.rows; |
| 162 | mixing_matrix_cols = mapping_matrix_foa_mixing.cols; |
| 163 | demixing_matrix_rows = mapping_matrix_foa_demixing.rows; |
| 164 | demixing_matrix_cols = mapping_matrix_foa_demixing.cols; |
| 165 | } |
| 166 | else if (order_plus_one == 3) |
| 167 | { |
| 168 | mixing_matrix_rows = mapping_matrix_soa_mixing.rows; |
| 169 | mixing_matrix_cols = mapping_matrix_soa_mixing.cols; |
| 170 | demixing_matrix_rows = mapping_matrix_soa_demixing.rows; |
| 171 | demixing_matrix_cols = mapping_matrix_soa_demixing.cols; |
| 172 | } |
| 173 | else if (order_plus_one == 4) |
| 174 | { |
| 175 | mixing_matrix_rows = mapping_matrix_toa_mixing.rows; |
| 176 | mixing_matrix_cols = mapping_matrix_toa_mixing.cols; |
| 177 | demixing_matrix_rows = mapping_matrix_toa_demixing.rows; |
| 178 | demixing_matrix_cols = mapping_matrix_toa_demixing.cols; |
| 179 | } |
| 180 | else |
| 181 | return 0; |
| 182 | |
| 183 | mixing_matrix_size = |
| 184 | mapping_matrix_get_size(mixing_matrix_rows, mixing_matrix_cols); |
| 185 | if (!mixing_matrix_size) |
| 186 | return 0; |
| 187 | |
| 188 | demixing_matrix_size = |
| 189 | mapping_matrix_get_size(demixing_matrix_rows, demixing_matrix_cols); |
| 190 | if (!demixing_matrix_size) |
Andrew Allen | cae4445 | 2017-12-04 16:05:57 -0800 | [diff] [blame] | 191 | return 0; |
| 192 | |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 193 | encoder_size = |
| 194 | opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams); |
| 195 | if (!encoder_size) |
| 196 | return 0; |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 197 | |
| 198 | return align(sizeof(OpusProjectionEncoder)) + |
| 199 | mixing_matrix_size + demixing_matrix_size + encoder_size; |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 200 | } |
| 201 | |
| 202 | int opus_projection_ambisonics_encoder_init(OpusProjectionEncoder *st, opus_int32 Fs, |
| 203 | int channels, int mapping_family, |
| 204 | int *streams, int *coupled_streams, |
| 205 | int application) |
| 206 | { |
| 207 | MappingMatrix *mixing_matrix; |
| 208 | MappingMatrix *demixing_matrix; |
| 209 | OpusMSEncoder *ms_encoder; |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 210 | int i; |
| 211 | int ret; |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 212 | int order_plus_one; |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 213 | unsigned char mapping[255]; |
| 214 | |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 215 | if (streams == NULL || coupled_streams == NULL) { |
| 216 | return OPUS_BAD_ARG; |
| 217 | } |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 218 | |
| 219 | if (get_streams_from_channels(channels, mapping_family, streams, |
| 220 | coupled_streams, &order_plus_one) != OPUS_OK) |
| 221 | return OPUS_BAD_ARG; |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 222 | |
Jean-Marc Valin | 6a74b41 | 2018-06-15 16:52:14 -0400 | [diff] [blame] | 223 | if (mapping_family == 3) |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 224 | { |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 225 | /* Assign mixing matrix based on available pre-computed matrices. */ |
| 226 | mixing_matrix = get_mixing_matrix(st); |
| 227 | if (order_plus_one == 2) |
| 228 | { |
| 229 | mapping_matrix_init(mixing_matrix, mapping_matrix_foa_mixing.rows, |
| 230 | mapping_matrix_foa_mixing.cols, mapping_matrix_foa_mixing.gain, |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 231 | mapping_matrix_foa_mixing_data, |
| 232 | sizeof(mapping_matrix_foa_mixing_data)); |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 233 | } |
| 234 | else if (order_plus_one == 3) |
| 235 | { |
| 236 | mapping_matrix_init(mixing_matrix, mapping_matrix_soa_mixing.rows, |
| 237 | mapping_matrix_soa_mixing.cols, mapping_matrix_soa_mixing.gain, |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 238 | mapping_matrix_soa_mixing_data, |
| 239 | sizeof(mapping_matrix_soa_mixing_data)); |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 240 | } |
| 241 | else if (order_plus_one == 4) |
| 242 | { |
| 243 | mapping_matrix_init(mixing_matrix, mapping_matrix_toa_mixing.rows, |
| 244 | mapping_matrix_toa_mixing.cols, mapping_matrix_toa_mixing.gain, |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 245 | mapping_matrix_toa_mixing_data, |
| 246 | sizeof(mapping_matrix_toa_mixing_data)); |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 247 | } |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 248 | else |
| 249 | return OPUS_BAD_ARG; |
| 250 | |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 251 | st->mixing_matrix_size_in_bytes = mapping_matrix_get_size( |
| 252 | mixing_matrix->rows, mixing_matrix->cols); |
Andrew Allen | cae4445 | 2017-12-04 16:05:57 -0800 | [diff] [blame] | 253 | if (!st->mixing_matrix_size_in_bytes) |
| 254 | return OPUS_BAD_ARG; |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 255 | |
| 256 | /* Assign demixing matrix based on available pre-computed matrices. */ |
| 257 | demixing_matrix = get_demixing_matrix(st); |
| 258 | if (order_plus_one == 2) |
| 259 | { |
| 260 | mapping_matrix_init(demixing_matrix, mapping_matrix_foa_demixing.rows, |
| 261 | mapping_matrix_foa_demixing.cols, mapping_matrix_foa_demixing.gain, |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 262 | mapping_matrix_foa_demixing_data, |
| 263 | sizeof(mapping_matrix_foa_demixing_data)); |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 264 | } |
| 265 | else if (order_plus_one == 3) |
| 266 | { |
| 267 | mapping_matrix_init(demixing_matrix, mapping_matrix_soa_demixing.rows, |
| 268 | mapping_matrix_soa_demixing.cols, mapping_matrix_soa_demixing.gain, |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 269 | mapping_matrix_soa_demixing_data, |
| 270 | sizeof(mapping_matrix_soa_demixing_data)); |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 271 | } |
| 272 | else if (order_plus_one == 4) |
| 273 | { |
| 274 | mapping_matrix_init(demixing_matrix, mapping_matrix_toa_demixing.rows, |
| 275 | mapping_matrix_toa_demixing.cols, mapping_matrix_toa_demixing.gain, |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 276 | mapping_matrix_toa_demixing_data, |
| 277 | sizeof(mapping_matrix_toa_demixing_data)); |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 278 | } |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 279 | else |
| 280 | return OPUS_BAD_ARG; |
| 281 | |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 282 | st->demixing_matrix_size_in_bytes = mapping_matrix_get_size( |
| 283 | demixing_matrix->rows, demixing_matrix->cols); |
Andrew Allen | cae4445 | 2017-12-04 16:05:57 -0800 | [diff] [blame] | 284 | if (!st->demixing_matrix_size_in_bytes) |
| 285 | return OPUS_BAD_ARG; |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 286 | } |
| 287 | else |
| 288 | return OPUS_UNIMPLEMENTED; |
| 289 | |
| 290 | /* Ensure matrices are large enough for desired coding scheme. */ |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 291 | if (*streams + *coupled_streams > mixing_matrix->rows || |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 292 | channels > mixing_matrix->cols || |
| 293 | channels > demixing_matrix->rows || |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 294 | *streams + *coupled_streams > demixing_matrix->cols) |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 295 | return OPUS_BAD_ARG; |
| 296 | |
| 297 | /* Set trivial mapping so each input channel pairs with a matrix column. */ |
| 298 | for (i = 0; i < channels; i++) |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 299 | mapping[i] = i; |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 300 | |
| 301 | /* Initialize multistream encoder with provided settings. */ |
| 302 | ms_encoder = get_multistream_encoder(st); |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 303 | ret = opus_multistream_encoder_init(ms_encoder, Fs, channels, *streams, |
| 304 | *coupled_streams, mapping, application); |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 305 | return ret; |
| 306 | } |
| 307 | |
| 308 | OpusProjectionEncoder *opus_projection_ambisonics_encoder_create( |
| 309 | opus_int32 Fs, int channels, int mapping_family, int *streams, |
| 310 | int *coupled_streams, int application, int *error) |
| 311 | { |
| 312 | int size; |
| 313 | int ret; |
| 314 | OpusProjectionEncoder *st; |
| 315 | |
| 316 | /* Allocate space for the projection encoder. */ |
| 317 | size = opus_projection_ambisonics_encoder_get_size(channels, mapping_family); |
| 318 | if (!size) { |
| 319 | if (error) |
| 320 | *error = OPUS_ALLOC_FAIL; |
| 321 | return NULL; |
| 322 | } |
| 323 | st = (OpusProjectionEncoder *)opus_alloc(size); |
| 324 | if (!st) |
| 325 | { |
| 326 | if (error) |
| 327 | *error = OPUS_ALLOC_FAIL; |
| 328 | return NULL; |
| 329 | } |
| 330 | |
| 331 | /* Initialize projection encoder with provided settings. */ |
| 332 | ret = opus_projection_ambisonics_encoder_init(st, Fs, channels, |
| 333 | mapping_family, streams, coupled_streams, application); |
| 334 | if (ret != OPUS_OK) |
| 335 | { |
| 336 | opus_free(st); |
| 337 | st = NULL; |
| 338 | } |
| 339 | if (error) |
| 340 | *error = ret; |
| 341 | return st; |
| 342 | } |
| 343 | |
| 344 | int opus_projection_encode(OpusProjectionEncoder *st, const opus_int16 *pcm, |
| 345 | int frame_size, unsigned char *data, |
| 346 | opus_int32 max_data_bytes) |
| 347 | { |
Andrew Allen | 65f11d3 | 2017-12-04 15:32:18 -0800 | [diff] [blame] | 348 | return opus_multistream_encode_native(get_multistream_encoder(st), |
| 349 | opus_projection_copy_channel_in_short, pcm, frame_size, data, |
| 350 | max_data_bytes, 16, downmix_int, 0, get_mixing_matrix(st)); |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 351 | } |
| 352 | |
| 353 | #ifndef DISABLE_FLOAT_API |
Andrew Allen | 65f11d3 | 2017-12-04 15:32:18 -0800 | [diff] [blame] | 354 | #ifdef FIXED_POINT |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 355 | int opus_projection_encode_float(OpusProjectionEncoder *st, const float *pcm, |
| 356 | int frame_size, unsigned char *data, |
| 357 | opus_int32 max_data_bytes) |
| 358 | { |
Andrew Allen | 65f11d3 | 2017-12-04 15:32:18 -0800 | [diff] [blame] | 359 | return opus_multistream_encode_native(get_multistream_encoder(st), |
| 360 | opus_projection_copy_channel_in_float, pcm, frame_size, data, |
| 361 | max_data_bytes, 16, downmix_float, 1, get_mixing_matrix(st)); |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 362 | } |
Andrew Allen | 65f11d3 | 2017-12-04 15:32:18 -0800 | [diff] [blame] | 363 | #else |
| 364 | int opus_projection_encode_float(OpusProjectionEncoder *st, const float *pcm, |
| 365 | int frame_size, unsigned char *data, |
| 366 | opus_int32 max_data_bytes) |
| 367 | { |
| 368 | return opus_multistream_encode_native(get_multistream_encoder(st), |
| 369 | opus_projection_copy_channel_in_float, pcm, frame_size, data, |
| 370 | max_data_bytes, 24, downmix_float, 1, get_mixing_matrix(st)); |
| 371 | } |
| 372 | #endif |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 373 | #endif |
| 374 | |
| 375 | void opus_projection_encoder_destroy(OpusProjectionEncoder *st) |
| 376 | { |
| 377 | opus_free(st); |
| 378 | } |
| 379 | |
| 380 | int opus_projection_encoder_ctl(OpusProjectionEncoder *st, int request, ...) |
| 381 | { |
Jean-Marc Valin | 1f0c1b1 | 2018-07-26 20:13:55 -0400 | [diff] [blame^] | 382 | va_list ap; |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 383 | MappingMatrix *demixing_matrix; |
| 384 | OpusMSEncoder *ms_encoder; |
| 385 | int ret = OPUS_OK; |
| 386 | |
| 387 | ms_encoder = get_multistream_encoder(st); |
| 388 | demixing_matrix = get_demixing_matrix(st); |
| 389 | |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 390 | va_start(ap, request); |
| 391 | switch(request) |
| 392 | { |
| 393 | case OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST: |
| 394 | { |
| 395 | opus_int32 *value = va_arg(ap, opus_int32*); |
| 396 | if (!value) |
| 397 | { |
| 398 | goto bad_arg; |
| 399 | } |
| 400 | *value = |
| 401 | ms_encoder->layout.nb_channels * (ms_encoder->layout.nb_streams |
| 402 | + ms_encoder->layout.nb_coupled_streams) * sizeof(opus_int16); |
| 403 | } |
| 404 | break; |
| 405 | case OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST: |
| 406 | { |
| 407 | opus_int32 *value = va_arg(ap, opus_int32*); |
| 408 | if (!value) |
| 409 | { |
| 410 | goto bad_arg; |
| 411 | } |
| 412 | *value = demixing_matrix->gain; |
| 413 | } |
| 414 | break; |
| 415 | case OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST: |
| 416 | { |
Andrew Allen | ff83843 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 417 | int i, j, k, l; |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 418 | int nb_input_streams; |
| 419 | int nb_output_streams; |
| 420 | unsigned char *external_char; |
| 421 | opus_int16 *internal_short; |
| 422 | opus_int32 external_size; |
| 423 | opus_int32 internal_size; |
| 424 | |
| 425 | /* (I/O is in relation to the decoder's perspective). */ |
| 426 | nb_input_streams = ms_encoder->layout.nb_streams + |
| 427 | ms_encoder->layout.nb_coupled_streams; |
| 428 | nb_output_streams = ms_encoder->layout.nb_channels; |
| 429 | |
| 430 | external_char = va_arg(ap, unsigned char *); |
Andrew Allen | 058e817 | 2017-12-05 15:34:43 -0800 | [diff] [blame] | 431 | external_size = va_arg(ap, opus_int32); |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 432 | if (!external_char) |
| 433 | { |
| 434 | goto bad_arg; |
| 435 | } |
| 436 | internal_short = mapping_matrix_get_data(demixing_matrix); |
| 437 | internal_size = nb_input_streams * nb_output_streams * sizeof(opus_int16); |
| 438 | if (external_size != internal_size) |
| 439 | { |
| 440 | goto bad_arg; |
| 441 | } |
| 442 | |
| 443 | /* Copy demixing matrix subset to output destination. */ |
Andrew Allen | ff83843 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 444 | l = 0; |
| 445 | for (i = 0; i < nb_input_streams; i++) { |
| 446 | for (j = 0; j < nb_output_streams; j++) { |
| 447 | k = demixing_matrix->rows * i + j; |
| 448 | external_char[2*l] = (unsigned char)internal_short[k]; |
| 449 | external_char[2*l+1] = (unsigned char)(internal_short[k] >> 8); |
| 450 | l++; |
| 451 | } |
Andrew Allen | f643c03 | 2017-11-07 13:26:23 -0800 | [diff] [blame] | 452 | } |
| 453 | } |
| 454 | break; |
| 455 | default: |
| 456 | { |
| 457 | ret = opus_multistream_encoder_ctl_va_list(ms_encoder, request, ap); |
| 458 | } |
| 459 | break; |
| 460 | } |
| 461 | va_end(ap); |
| 462 | return ret; |
| 463 | |
| 464 | bad_arg: |
| 465 | va_end(ap); |
| 466 | return OPUS_BAD_ARG; |
| 467 | } |
| 468 | |