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