Coverage Report

Created: 2026-01-17 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opus/src/opus_projection_encoder.c
Line
Count
Source
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
41
struct OpusProjectionEncoder
42
{
43
  opus_int32 mixing_matrix_size_in_bytes;
44
  opus_int32 demixing_matrix_size_in_bytes;
45
  /* Encoder states go here */
46
};
47
48
#if !defined(DISABLE_FLOAT_API)
49
static void opus_projection_copy_channel_in_float(
50
  opus_res *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
0
{
59
0
  mapping_matrix_multiply_channel_in_float((const MappingMatrix*)user_data,
60
0
    (const float*)src, src_stride, dst, src_channel, dst_stride, frame_size);
61
0
}
62
#endif
63
64
static void opus_projection_copy_channel_in_short(
65
  opus_res *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
274k
{
74
274k
  mapping_matrix_multiply_channel_in_short((const MappingMatrix*)user_data,
75
274k
    (const opus_int16*)src, src_stride, dst, src_channel, dst_stride, frame_size);
76
274k
}
77
78
static void opus_projection_copy_channel_in_int24(
79
  opus_res *dst,
80
  int dst_stride,
81
  const void *src,
82
  int src_stride,
83
  int src_channel,
84
  int frame_size,
85
  void *user_data
86
)
87
0
{
88
0
  mapping_matrix_multiply_channel_in_int24((const MappingMatrix*)user_data,
89
0
    (const opus_int32*)src, src_stride, dst, src_channel, dst_stride, frame_size);
90
0
}
91
92
static int get_order_plus_one_from_channels(int channels, int *order_plus_one)
93
62.5k
{
94
62.5k
  int order_plus_one_;
95
62.5k
  int acn_channels;
96
62.5k
  int nondiegetic_channels;
97
98
  /* Allowed numbers of channels:
99
   * (1 + n)^2 + 2j, for n = 0...14 and j = 0 or 1.
100
   */
101
62.5k
  if (channels < 1 || channels > 227)
102
15
    return OPUS_BAD_ARG;
103
104
62.5k
  order_plus_one_ = isqrt32(channels);
105
62.5k
  acn_channels = order_plus_one_ * order_plus_one_;
106
62.5k
  nondiegetic_channels = channels - acn_channels;
107
62.5k
  if (nondiegetic_channels != 0 && nondiegetic_channels != 2)
108
53
    return OPUS_BAD_ARG;
109
110
62.4k
  if (order_plus_one)
111
62.4k
    *order_plus_one = order_plus_one_;
112
62.4k
  return OPUS_OK;
113
62.5k
}
114
115
static int get_streams_from_channels(int channels, int mapping_family,
116
                                     int *streams, int *coupled_streams,
117
                                     int *order_plus_one)
118
62.6k
{
119
62.6k
  if (mapping_family == 3)
120
62.5k
  {
121
62.5k
    if (get_order_plus_one_from_channels(channels, order_plus_one) != OPUS_OK)
122
68
      return OPUS_BAD_ARG;
123
62.4k
    if (streams)
124
62.4k
      *streams = (channels + 1) / 2;
125
62.4k
    if (coupled_streams)
126
62.4k
      *coupled_streams = channels / 2;
127
62.4k
    return OPUS_OK;
128
62.5k
  }
129
77
  return OPUS_BAD_ARG;
130
62.6k
}
131
132
static MappingMatrix *get_mixing_matrix(OpusProjectionEncoder *st)
133
61.7k
{
134
  /* void* cast avoids clang -Wcast-align warning */
135
61.7k
  return (MappingMatrix *)(void*)((char*)st +
136
61.7k
    align(sizeof(OpusProjectionEncoder)));
137
61.7k
}
138
139
static MappingMatrix *get_enc_demixing_matrix(OpusProjectionEncoder *st)
140
405k
{
141
  /* void* cast avoids clang -Wcast-align warning */
142
405k
  return (MappingMatrix *)(void*)((char*)st +
143
405k
    align(sizeof(OpusProjectionEncoder) +
144
405k
    st->mixing_matrix_size_in_bytes));
145
405k
}
146
147
static OpusMSEncoder *get_multistream_encoder(OpusProjectionEncoder *st)
148
436k
{
149
  /* void* cast avoids clang -Wcast-align warning */
150
436k
  return (OpusMSEncoder *)(void*)((char*)st +
151
436k
    align(sizeof(OpusProjectionEncoder) +
152
436k
    st->mixing_matrix_size_in_bytes +
153
436k
    st->demixing_matrix_size_in_bytes));
154
436k
}
155
156
opus_int32 opus_projection_ambisonics_encoder_get_size(int channels,
157
                                                       int mapping_family)
158
31.3k
{
159
31.3k
  int nb_streams;
160
31.3k
  int nb_coupled_streams;
161
31.3k
  int order_plus_one;
162
31.3k
  int mixing_matrix_rows, mixing_matrix_cols;
163
31.3k
  int demixing_matrix_rows, demixing_matrix_cols;
164
31.3k
  opus_int32 mixing_matrix_size, demixing_matrix_size;
165
31.3k
  opus_int32 encoder_size;
166
31.3k
  int ret;
167
168
31.3k
  ret = get_streams_from_channels(channels, mapping_family, &nb_streams,
169
31.3k
                                  &nb_coupled_streams, &order_plus_one);
170
31.3k
  if (ret != OPUS_OK)
171
145
    return 0;
172
173
31.2k
  if (order_plus_one == 2)
174
21.2k
  {
175
21.2k
    mixing_matrix_rows = mapping_matrix_foa_mixing.rows;
176
21.2k
    mixing_matrix_cols = mapping_matrix_foa_mixing.cols;
177
21.2k
    demixing_matrix_rows = mapping_matrix_foa_demixing.rows;
178
21.2k
    demixing_matrix_cols = mapping_matrix_foa_demixing.cols;
179
21.2k
  }
180
9.98k
  else if (order_plus_one == 3)
181
4.17k
  {
182
4.17k
    mixing_matrix_rows = mapping_matrix_soa_mixing.rows;
183
4.17k
    mixing_matrix_cols = mapping_matrix_soa_mixing.cols;
184
4.17k
    demixing_matrix_rows = mapping_matrix_soa_demixing.rows;
185
4.17k
    demixing_matrix_cols = mapping_matrix_soa_demixing.cols;
186
4.17k
  }
187
5.81k
  else if (order_plus_one == 4)
188
2.36k
  {
189
2.36k
    mixing_matrix_rows = mapping_matrix_toa_mixing.rows;
190
2.36k
    mixing_matrix_cols = mapping_matrix_toa_mixing.cols;
191
2.36k
    demixing_matrix_rows = mapping_matrix_toa_demixing.rows;
192
2.36k
    demixing_matrix_cols = mapping_matrix_toa_demixing.cols;
193
2.36k
  }
194
3.44k
  else if (order_plus_one == 5)
195
1.02k
  {
196
1.02k
    mixing_matrix_rows = mapping_matrix_fourthoa_mixing.rows;
197
1.02k
    mixing_matrix_cols = mapping_matrix_fourthoa_mixing.cols;
198
1.02k
    demixing_matrix_rows = mapping_matrix_fourthoa_demixing.rows;
199
1.02k
    demixing_matrix_cols = mapping_matrix_fourthoa_demixing.cols;
200
1.02k
  }
201
2.42k
  else if (order_plus_one == 6)
202
2.38k
  {
203
2.38k
    mixing_matrix_rows = mapping_matrix_fifthoa_mixing.rows;
204
2.38k
    mixing_matrix_cols = mapping_matrix_fifthoa_mixing.cols;
205
2.38k
    demixing_matrix_rows = mapping_matrix_fifthoa_demixing.rows;
206
2.38k
    demixing_matrix_cols = mapping_matrix_fifthoa_demixing.cols;
207
2.38k
  }
208
36
  else
209
36
    return 0;
210
211
31.2k
  mixing_matrix_size =
212
31.2k
    mapping_matrix_get_size(mixing_matrix_rows, mixing_matrix_cols);
213
31.2k
  if (!mixing_matrix_size)
214
0
    return 0;
215
216
31.2k
  demixing_matrix_size =
217
31.2k
    mapping_matrix_get_size(demixing_matrix_rows, demixing_matrix_cols);
218
31.2k
  if (!demixing_matrix_size)
219
0
    return 0;
220
221
31.2k
  encoder_size =
222
31.2k
      opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams);
223
31.2k
  if (!encoder_size)
224
0
    return 0;
225
226
31.2k
  return align(sizeof(OpusProjectionEncoder)) +
227
31.2k
    mixing_matrix_size + demixing_matrix_size + encoder_size;
228
31.2k
}
229
230
int opus_projection_ambisonics_encoder_init(OpusProjectionEncoder *st, opus_int32 Fs,
231
                                            int channels, int mapping_family,
232
                                            int *streams, int *coupled_streams,
233
                                            int application)
234
31.2k
{
235
31.2k
  MappingMatrix *mixing_matrix;
236
31.2k
  MappingMatrix *demixing_matrix;
237
31.2k
  OpusMSEncoder *ms_encoder;
238
31.2k
  int i;
239
31.2k
  int ret;
240
31.2k
  int order_plus_one;
241
31.2k
  unsigned char mapping[255];
242
243
31.2k
  if (streams == NULL || coupled_streams == NULL) {
244
0
    return OPUS_BAD_ARG;
245
0
  }
246
247
31.2k
  if (get_streams_from_channels(channels, mapping_family, streams,
248
31.2k
    coupled_streams, &order_plus_one) != OPUS_OK)
249
0
    return OPUS_BAD_ARG;
250
251
31.2k
  if (mapping_family == 3)
252
31.2k
  {
253
    /* Assign mixing matrix based on available pre-computed matrices. */
254
31.2k
    mixing_matrix = get_mixing_matrix(st);
255
31.2k
    if (order_plus_one == 2)
256
21.2k
    {
257
21.2k
      mapping_matrix_init(mixing_matrix, mapping_matrix_foa_mixing.rows,
258
21.2k
        mapping_matrix_foa_mixing.cols, mapping_matrix_foa_mixing.gain,
259
21.2k
        mapping_matrix_foa_mixing_data,
260
21.2k
        sizeof(mapping_matrix_foa_mixing_data));
261
21.2k
    }
262
9.94k
    else if (order_plus_one == 3)
263
4.17k
    {
264
4.17k
      mapping_matrix_init(mixing_matrix, mapping_matrix_soa_mixing.rows,
265
4.17k
        mapping_matrix_soa_mixing.cols, mapping_matrix_soa_mixing.gain,
266
4.17k
        mapping_matrix_soa_mixing_data,
267
4.17k
        sizeof(mapping_matrix_soa_mixing_data));
268
4.17k
    }
269
5.77k
    else if (order_plus_one == 4)
270
2.36k
    {
271
2.36k
      mapping_matrix_init(mixing_matrix, mapping_matrix_toa_mixing.rows,
272
2.36k
        mapping_matrix_toa_mixing.cols, mapping_matrix_toa_mixing.gain,
273
2.36k
        mapping_matrix_toa_mixing_data,
274
2.36k
        sizeof(mapping_matrix_toa_mixing_data));
275
2.36k
    }
276
3.41k
    else if (order_plus_one == 5)
277
1.02k
    {
278
1.02k
      mapping_matrix_init(mixing_matrix, mapping_matrix_fourthoa_mixing.rows,
279
1.02k
        mapping_matrix_fourthoa_mixing.cols, mapping_matrix_fourthoa_mixing.gain,
280
1.02k
        mapping_matrix_fourthoa_mixing_data,
281
1.02k
        sizeof(mapping_matrix_fourthoa_mixing_data));
282
1.02k
    }
283
2.38k
    else if (order_plus_one == 6)
284
2.38k
    {
285
2.38k
      mapping_matrix_init(mixing_matrix, mapping_matrix_fifthoa_mixing.rows,
286
2.38k
        mapping_matrix_fifthoa_mixing.cols, mapping_matrix_fifthoa_mixing.gain,
287
2.38k
        mapping_matrix_fifthoa_mixing_data,
288
2.38k
        sizeof(mapping_matrix_fifthoa_mixing_data));
289
2.38k
    }
290
0
    else
291
0
      return OPUS_BAD_ARG;
292
293
31.2k
    st->mixing_matrix_size_in_bytes = mapping_matrix_get_size(
294
31.2k
      mixing_matrix->rows, mixing_matrix->cols);
295
31.2k
    if (!st->mixing_matrix_size_in_bytes)
296
0
      return OPUS_BAD_ARG;
297
298
    /* Assign demixing matrix based on available pre-computed matrices. */
299
31.2k
    demixing_matrix = get_enc_demixing_matrix(st);
300
31.2k
    if (order_plus_one == 2)
301
21.2k
    {
302
21.2k
      mapping_matrix_init(demixing_matrix, mapping_matrix_foa_demixing.rows,
303
21.2k
        mapping_matrix_foa_demixing.cols, mapping_matrix_foa_demixing.gain,
304
21.2k
        mapping_matrix_foa_demixing_data,
305
21.2k
        sizeof(mapping_matrix_foa_demixing_data));
306
21.2k
    }
307
9.94k
    else if (order_plus_one == 3)
308
4.17k
    {
309
4.17k
      mapping_matrix_init(demixing_matrix, mapping_matrix_soa_demixing.rows,
310
4.17k
        mapping_matrix_soa_demixing.cols, mapping_matrix_soa_demixing.gain,
311
4.17k
        mapping_matrix_soa_demixing_data,
312
4.17k
        sizeof(mapping_matrix_soa_demixing_data));
313
4.17k
    }
314
5.77k
    else if (order_plus_one == 4)
315
2.36k
    {
316
2.36k
      mapping_matrix_init(demixing_matrix, mapping_matrix_toa_demixing.rows,
317
2.36k
        mapping_matrix_toa_demixing.cols, mapping_matrix_toa_demixing.gain,
318
2.36k
        mapping_matrix_toa_demixing_data,
319
2.36k
        sizeof(mapping_matrix_toa_demixing_data));
320
2.36k
    }
321
3.41k
      else if (order_plus_one == 5)
322
1.02k
    {
323
1.02k
      mapping_matrix_init(demixing_matrix, mapping_matrix_fourthoa_demixing.rows,
324
1.02k
        mapping_matrix_fourthoa_demixing.cols, mapping_matrix_fourthoa_demixing.gain,
325
1.02k
        mapping_matrix_fourthoa_demixing_data,
326
1.02k
        sizeof(mapping_matrix_fourthoa_demixing_data));
327
1.02k
    }
328
2.38k
    else if (order_plus_one == 6)
329
2.38k
    {
330
2.38k
      mapping_matrix_init(demixing_matrix, mapping_matrix_fifthoa_demixing.rows,
331
2.38k
        mapping_matrix_fifthoa_demixing.cols, mapping_matrix_fifthoa_demixing.gain,
332
2.38k
        mapping_matrix_fifthoa_demixing_data,
333
2.38k
        sizeof(mapping_matrix_fifthoa_demixing_data));
334
2.38k
    }
335
0
    else
336
0
      return OPUS_BAD_ARG;
337
338
31.2k
    st->demixing_matrix_size_in_bytes = mapping_matrix_get_size(
339
31.2k
      demixing_matrix->rows, demixing_matrix->cols);
340
31.2k
    if (!st->demixing_matrix_size_in_bytes)
341
0
      return OPUS_BAD_ARG;
342
31.2k
  }
343
0
  else
344
0
    return OPUS_UNIMPLEMENTED;
345
346
  /* Ensure matrices are large enough for desired coding scheme. */
347
31.2k
  if (*streams + *coupled_streams > mixing_matrix->rows ||
348
31.2k
      channels > mixing_matrix->cols ||
349
31.2k
      channels > demixing_matrix->rows ||
350
31.2k
      *streams + *coupled_streams > demixing_matrix->cols)
351
0
    return OPUS_BAD_ARG;
352
353
  /* Set trivial mapping so each input channel pairs with a matrix column. */
354
314k
  for (i = 0; i < channels; i++)
355
283k
    mapping[i] = i;
356
357
  /* Initialize multistream encoder with provided settings. */
358
31.2k
  ms_encoder = get_multistream_encoder(st);
359
31.2k
  ret = opus_multistream_encoder_init(ms_encoder, Fs, channels, *streams,
360
31.2k
                                      *coupled_streams, mapping, application);
361
31.2k
  return ret;
362
31.2k
}
363
364
OpusProjectionEncoder *opus_projection_ambisonics_encoder_create(
365
    opus_int32 Fs, int channels, int mapping_family, int *streams,
366
    int *coupled_streams, int application, int *error)
367
31.3k
{
368
31.3k
  int size;
369
31.3k
  int ret;
370
31.3k
  OpusProjectionEncoder *st;
371
372
  /* Allocate space for the projection encoder. */
373
31.3k
  size = opus_projection_ambisonics_encoder_get_size(channels, mapping_family);
374
31.3k
  if (!size) {
375
181
    if (error)
376
181
      *error = OPUS_ALLOC_FAIL;
377
181
    return NULL;
378
181
  }
379
31.2k
  st = (OpusProjectionEncoder *)opus_alloc(size);
380
31.2k
  if (!st)
381
0
  {
382
0
    if (error)
383
0
      *error = OPUS_ALLOC_FAIL;
384
0
    return NULL;
385
0
  }
386
387
  /* Initialize projection encoder with provided settings. */
388
31.2k
  ret = opus_projection_ambisonics_encoder_init(st, Fs, channels,
389
31.2k
     mapping_family, streams, coupled_streams, application);
390
31.2k
  if (ret != OPUS_OK)
391
0
  {
392
0
    opus_free(st);
393
0
    st = NULL;
394
0
  }
395
31.2k
  if (error)
396
31.2k
    *error = ret;
397
31.2k
  return st;
398
31.2k
}
399
400
int opus_projection_encode(OpusProjectionEncoder *st, const opus_int16 *pcm,
401
                           int frame_size, unsigned char *data,
402
                           opus_int32 max_data_bytes)
403
30.4k
{
404
30.4k
  return opus_multistream_encode_native(get_multistream_encoder(st),
405
30.4k
    opus_projection_copy_channel_in_short, pcm, frame_size, data,
406
30.4k
    max_data_bytes, 16, downmix_int, 0, get_mixing_matrix(st));
407
30.4k
}
408
409
int opus_projection_encode24(OpusProjectionEncoder *st, const opus_int32 *pcm,
410
                           int frame_size, unsigned char *data,
411
                           opus_int32 max_data_bytes)
412
0
{
413
0
  return opus_multistream_encode_native(get_multistream_encoder(st),
414
0
    opus_projection_copy_channel_in_int24, pcm, frame_size, data,
415
0
    max_data_bytes, MAX_ENCODING_DEPTH, downmix_int, 0, get_mixing_matrix(st));
416
0
}
417
418
#ifndef DISABLE_FLOAT_API
419
int opus_projection_encode_float(OpusProjectionEncoder *st, const float *pcm,
420
                                 int frame_size, unsigned char *data,
421
                                 opus_int32 max_data_bytes)
422
0
{
423
0
  return opus_multistream_encode_native(get_multistream_encoder(st),
424
0
    opus_projection_copy_channel_in_float, pcm, frame_size, data,
425
0
    max_data_bytes, MAX_ENCODING_DEPTH, downmix_float, 1, get_mixing_matrix(st));
426
0
}
427
#endif
428
429
void opus_projection_encoder_destroy(OpusProjectionEncoder *st)
430
31.3k
{
431
31.3k
  opus_free(st);
432
31.3k
}
433
434
int opus_projection_encoder_ctl(OpusProjectionEncoder *st, int request, ...)
435
374k
{
436
374k
  va_list ap;
437
374k
  MappingMatrix *demixing_matrix;
438
374k
  OpusMSEncoder *ms_encoder;
439
374k
  int ret = OPUS_OK;
440
441
374k
  ms_encoder = get_multistream_encoder(st);
442
374k
  demixing_matrix = get_enc_demixing_matrix(st);
443
444
374k
  va_start(ap, request);
445
374k
  switch(request)
446
374k
  {
447
0
  case OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST:
448
0
  {
449
0
    opus_int32 *value = va_arg(ap, opus_int32*);
450
0
    if (!value)
451
0
    {
452
0
      goto bad_arg;
453
0
    }
454
0
    *value =
455
0
      ms_encoder->layout.nb_channels * (ms_encoder->layout.nb_streams
456
0
      + ms_encoder->layout.nb_coupled_streams) * sizeof(opus_int16);
457
0
  }
458
0
  break;
459
0
  case OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST:
460
0
  {
461
0
    opus_int32 *value = va_arg(ap, opus_int32*);
462
0
    if (!value)
463
0
    {
464
0
      goto bad_arg;
465
0
    }
466
0
    *value = demixing_matrix->gain;
467
0
  }
468
0
  break;
469
0
  case OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST:
470
0
  {
471
0
    int i, j, k, l;
472
0
    int nb_input_streams;
473
0
    int nb_output_streams;
474
0
    unsigned char *external_char;
475
0
    opus_int16 *internal_short;
476
0
    opus_int32 external_size;
477
0
    opus_int32 internal_size;
478
479
    /* (I/O is in relation to the decoder's perspective). */
480
0
    nb_input_streams = ms_encoder->layout.nb_streams +
481
0
      ms_encoder->layout.nb_coupled_streams;
482
0
    nb_output_streams = ms_encoder->layout.nb_channels;
483
484
0
    external_char = va_arg(ap, unsigned char *);
485
0
    external_size = va_arg(ap, opus_int32);
486
0
    if (!external_char)
487
0
    {
488
0
      goto bad_arg;
489
0
    }
490
0
    internal_short = mapping_matrix_get_data(demixing_matrix);
491
0
    internal_size = nb_input_streams * nb_output_streams * sizeof(opus_int16);
492
0
    if (external_size != internal_size)
493
0
    {
494
0
      goto bad_arg;
495
0
    }
496
497
    /* Copy demixing matrix subset to output destination. */
498
0
    l = 0;
499
0
    for (i = 0; i < nb_input_streams; i++) {
500
0
      for (j = 0; j < nb_output_streams; j++) {
501
0
        k = demixing_matrix->rows * i + j;
502
0
        external_char[2*l] = (unsigned char)internal_short[k];
503
0
        external_char[2*l+1] = (unsigned char)(internal_short[k] >> 8);
504
0
        l++;
505
0
      }
506
0
    }
507
0
  }
508
0
  break;
509
374k
  default:
510
374k
  {
511
374k
    ret = opus_multistream_encoder_ctl_va_list(ms_encoder, request, ap);
512
374k
  }
513
374k
  break;
514
374k
  }
515
374k
  va_end(ap);
516
374k
  return ret;
517
518
0
bad_arg:
519
0
  va_end(ap);
520
0
  return OPUS_BAD_ARG;
521
374k
}