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 "mapping_matrix.h"
39*a58d3d2aSXin Li #include "stack_alloc.h"
40*a58d3d2aSXin Li
41*a58d3d2aSXin Li struct OpusProjectionDecoder
42*a58d3d2aSXin Li {
43*a58d3d2aSXin Li opus_int32 demixing_matrix_size_in_bytes;
44*a58d3d2aSXin Li /* Encoder states go here */
45*a58d3d2aSXin Li };
46*a58d3d2aSXin Li
47*a58d3d2aSXin Li #if !defined(DISABLE_FLOAT_API)
opus_projection_copy_channel_out_float(void * dst,int dst_stride,int dst_channel,const opus_val16 * src,int src_stride,int frame_size,void * user_data)48*a58d3d2aSXin Li static void opus_projection_copy_channel_out_float(
49*a58d3d2aSXin Li void *dst,
50*a58d3d2aSXin Li int dst_stride,
51*a58d3d2aSXin Li int dst_channel,
52*a58d3d2aSXin Li const opus_val16 *src,
53*a58d3d2aSXin Li int src_stride,
54*a58d3d2aSXin Li int frame_size,
55*a58d3d2aSXin Li void *user_data)
56*a58d3d2aSXin Li {
57*a58d3d2aSXin Li float *float_dst;
58*a58d3d2aSXin Li const MappingMatrix *matrix;
59*a58d3d2aSXin Li float_dst = (float *)dst;
60*a58d3d2aSXin Li matrix = (const MappingMatrix *)user_data;
61*a58d3d2aSXin Li
62*a58d3d2aSXin Li if (dst_channel == 0)
63*a58d3d2aSXin Li OPUS_CLEAR(float_dst, frame_size * dst_stride);
64*a58d3d2aSXin Li
65*a58d3d2aSXin Li if (src != NULL)
66*a58d3d2aSXin Li mapping_matrix_multiply_channel_out_float(matrix, src, dst_channel,
67*a58d3d2aSXin Li src_stride, float_dst, dst_stride, frame_size);
68*a58d3d2aSXin Li }
69*a58d3d2aSXin Li #endif
70*a58d3d2aSXin Li
opus_projection_copy_channel_out_short(void * dst,int dst_stride,int dst_channel,const opus_val16 * src,int src_stride,int frame_size,void * user_data)71*a58d3d2aSXin Li static void opus_projection_copy_channel_out_short(
72*a58d3d2aSXin Li void *dst,
73*a58d3d2aSXin Li int dst_stride,
74*a58d3d2aSXin Li int dst_channel,
75*a58d3d2aSXin Li const opus_val16 *src,
76*a58d3d2aSXin Li int src_stride,
77*a58d3d2aSXin Li int frame_size,
78*a58d3d2aSXin Li void *user_data)
79*a58d3d2aSXin Li {
80*a58d3d2aSXin Li opus_int16 *short_dst;
81*a58d3d2aSXin Li const MappingMatrix *matrix;
82*a58d3d2aSXin Li short_dst = (opus_int16 *)dst;
83*a58d3d2aSXin Li matrix = (const MappingMatrix *)user_data;
84*a58d3d2aSXin Li if (dst_channel == 0)
85*a58d3d2aSXin Li OPUS_CLEAR(short_dst, frame_size * dst_stride);
86*a58d3d2aSXin Li
87*a58d3d2aSXin Li if (src != NULL)
88*a58d3d2aSXin Li mapping_matrix_multiply_channel_out_short(matrix, src, dst_channel,
89*a58d3d2aSXin Li src_stride, short_dst, dst_stride, frame_size);
90*a58d3d2aSXin Li }
91*a58d3d2aSXin Li
get_dec_demixing_matrix(OpusProjectionDecoder * st)92*a58d3d2aSXin Li static MappingMatrix *get_dec_demixing_matrix(OpusProjectionDecoder *st)
93*a58d3d2aSXin Li {
94*a58d3d2aSXin Li /* void* cast avoids clang -Wcast-align warning */
95*a58d3d2aSXin Li return (MappingMatrix*)(void*)((char*)st +
96*a58d3d2aSXin Li align(sizeof(OpusProjectionDecoder)));
97*a58d3d2aSXin Li }
98*a58d3d2aSXin Li
get_multistream_decoder(OpusProjectionDecoder * st)99*a58d3d2aSXin Li static OpusMSDecoder *get_multistream_decoder(OpusProjectionDecoder *st)
100*a58d3d2aSXin Li {
101*a58d3d2aSXin Li /* void* cast avoids clang -Wcast-align warning */
102*a58d3d2aSXin Li return (OpusMSDecoder*)(void*)((char*)st +
103*a58d3d2aSXin Li align(sizeof(OpusProjectionDecoder) +
104*a58d3d2aSXin Li st->demixing_matrix_size_in_bytes));
105*a58d3d2aSXin Li }
106*a58d3d2aSXin Li
opus_projection_decoder_get_size(int channels,int streams,int coupled_streams)107*a58d3d2aSXin Li opus_int32 opus_projection_decoder_get_size(int channels, int streams,
108*a58d3d2aSXin Li int coupled_streams)
109*a58d3d2aSXin Li {
110*a58d3d2aSXin Li opus_int32 matrix_size;
111*a58d3d2aSXin Li opus_int32 decoder_size;
112*a58d3d2aSXin Li
113*a58d3d2aSXin Li matrix_size =
114*a58d3d2aSXin Li mapping_matrix_get_size(streams + coupled_streams, channels);
115*a58d3d2aSXin Li if (!matrix_size)
116*a58d3d2aSXin Li return 0;
117*a58d3d2aSXin Li
118*a58d3d2aSXin Li decoder_size = opus_multistream_decoder_get_size(streams, coupled_streams);
119*a58d3d2aSXin Li if (!decoder_size)
120*a58d3d2aSXin Li return 0;
121*a58d3d2aSXin Li
122*a58d3d2aSXin Li return align(sizeof(OpusProjectionDecoder)) + matrix_size + decoder_size;
123*a58d3d2aSXin Li }
124*a58d3d2aSXin Li
opus_projection_decoder_init(OpusProjectionDecoder * st,opus_int32 Fs,int channels,int streams,int coupled_streams,unsigned char * demixing_matrix,opus_int32 demixing_matrix_size)125*a58d3d2aSXin Li int opus_projection_decoder_init(OpusProjectionDecoder *st, opus_int32 Fs,
126*a58d3d2aSXin Li int channels, int streams, int coupled_streams,
127*a58d3d2aSXin Li unsigned char *demixing_matrix, opus_int32 demixing_matrix_size)
128*a58d3d2aSXin Li {
129*a58d3d2aSXin Li int nb_input_streams;
130*a58d3d2aSXin Li opus_int32 expected_matrix_size;
131*a58d3d2aSXin Li int i, ret;
132*a58d3d2aSXin Li unsigned char mapping[255];
133*a58d3d2aSXin Li VARDECL(opus_int16, buf);
134*a58d3d2aSXin Li ALLOC_STACK;
135*a58d3d2aSXin Li
136*a58d3d2aSXin Li /* Verify supplied matrix size. */
137*a58d3d2aSXin Li nb_input_streams = streams + coupled_streams;
138*a58d3d2aSXin Li expected_matrix_size = nb_input_streams * channels * sizeof(opus_int16);
139*a58d3d2aSXin Li if (expected_matrix_size != demixing_matrix_size)
140*a58d3d2aSXin Li {
141*a58d3d2aSXin Li RESTORE_STACK;
142*a58d3d2aSXin Li return OPUS_BAD_ARG;
143*a58d3d2aSXin Li }
144*a58d3d2aSXin Li
145*a58d3d2aSXin Li /* Convert demixing matrix input into internal format. */
146*a58d3d2aSXin Li ALLOC(buf, nb_input_streams * channels, opus_int16);
147*a58d3d2aSXin Li for (i = 0; i < nb_input_streams * channels; i++)
148*a58d3d2aSXin Li {
149*a58d3d2aSXin Li int s = demixing_matrix[2*i + 1] << 8 | demixing_matrix[2*i];
150*a58d3d2aSXin Li s = ((s & 0xFFFF) ^ 0x8000) - 0x8000;
151*a58d3d2aSXin Li buf[i] = (opus_int16)s;
152*a58d3d2aSXin Li }
153*a58d3d2aSXin Li
154*a58d3d2aSXin Li /* Assign demixing matrix. */
155*a58d3d2aSXin Li st->demixing_matrix_size_in_bytes =
156*a58d3d2aSXin Li mapping_matrix_get_size(channels, nb_input_streams);
157*a58d3d2aSXin Li if (!st->demixing_matrix_size_in_bytes)
158*a58d3d2aSXin Li {
159*a58d3d2aSXin Li RESTORE_STACK;
160*a58d3d2aSXin Li return OPUS_BAD_ARG;
161*a58d3d2aSXin Li }
162*a58d3d2aSXin Li
163*a58d3d2aSXin Li mapping_matrix_init(get_dec_demixing_matrix(st), channels, nb_input_streams, 0,
164*a58d3d2aSXin Li buf, demixing_matrix_size);
165*a58d3d2aSXin Li
166*a58d3d2aSXin Li /* Set trivial mapping so each input channel pairs with a matrix column. */
167*a58d3d2aSXin Li for (i = 0; i < channels; i++)
168*a58d3d2aSXin Li mapping[i] = i;
169*a58d3d2aSXin Li
170*a58d3d2aSXin Li ret = opus_multistream_decoder_init(
171*a58d3d2aSXin Li get_multistream_decoder(st), Fs, channels, streams, coupled_streams, mapping);
172*a58d3d2aSXin Li RESTORE_STACK;
173*a58d3d2aSXin Li return ret;
174*a58d3d2aSXin Li }
175*a58d3d2aSXin Li
opus_projection_decoder_create(opus_int32 Fs,int channels,int streams,int coupled_streams,unsigned char * demixing_matrix,opus_int32 demixing_matrix_size,int * error)176*a58d3d2aSXin Li OpusProjectionDecoder *opus_projection_decoder_create(
177*a58d3d2aSXin Li opus_int32 Fs, int channels, int streams, int coupled_streams,
178*a58d3d2aSXin Li unsigned char *demixing_matrix, opus_int32 demixing_matrix_size, int *error)
179*a58d3d2aSXin Li {
180*a58d3d2aSXin Li int size;
181*a58d3d2aSXin Li int ret;
182*a58d3d2aSXin Li OpusProjectionDecoder *st;
183*a58d3d2aSXin Li
184*a58d3d2aSXin Li /* Allocate space for the projection decoder. */
185*a58d3d2aSXin Li size = opus_projection_decoder_get_size(channels, streams, coupled_streams);
186*a58d3d2aSXin Li if (!size) {
187*a58d3d2aSXin Li if (error)
188*a58d3d2aSXin Li *error = OPUS_ALLOC_FAIL;
189*a58d3d2aSXin Li return NULL;
190*a58d3d2aSXin Li }
191*a58d3d2aSXin Li st = (OpusProjectionDecoder *)opus_alloc(size);
192*a58d3d2aSXin Li if (!st)
193*a58d3d2aSXin Li {
194*a58d3d2aSXin Li if (error)
195*a58d3d2aSXin Li *error = OPUS_ALLOC_FAIL;
196*a58d3d2aSXin Li return NULL;
197*a58d3d2aSXin Li }
198*a58d3d2aSXin Li
199*a58d3d2aSXin Li /* Initialize projection decoder with provided settings. */
200*a58d3d2aSXin Li ret = opus_projection_decoder_init(st, Fs, channels, streams, coupled_streams,
201*a58d3d2aSXin Li demixing_matrix, demixing_matrix_size);
202*a58d3d2aSXin Li if (ret != OPUS_OK)
203*a58d3d2aSXin Li {
204*a58d3d2aSXin Li opus_free(st);
205*a58d3d2aSXin Li st = NULL;
206*a58d3d2aSXin Li }
207*a58d3d2aSXin Li if (error)
208*a58d3d2aSXin Li *error = ret;
209*a58d3d2aSXin Li return st;
210*a58d3d2aSXin Li }
211*a58d3d2aSXin Li
212*a58d3d2aSXin Li #ifdef FIXED_POINT
opus_projection_decode(OpusProjectionDecoder * st,const unsigned char * data,opus_int32 len,opus_int16 * pcm,int frame_size,int decode_fec)213*a58d3d2aSXin Li int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data,
214*a58d3d2aSXin Li opus_int32 len, opus_int16 *pcm, int frame_size,
215*a58d3d2aSXin Li int decode_fec)
216*a58d3d2aSXin Li {
217*a58d3d2aSXin Li return opus_multistream_decode_native(get_multistream_decoder(st), data, len,
218*a58d3d2aSXin Li pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, 0,
219*a58d3d2aSXin Li get_dec_demixing_matrix(st));
220*a58d3d2aSXin Li }
221*a58d3d2aSXin Li #else
opus_projection_decode(OpusProjectionDecoder * st,const unsigned char * data,opus_int32 len,opus_int16 * pcm,int frame_size,int decode_fec)222*a58d3d2aSXin Li int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data,
223*a58d3d2aSXin Li opus_int32 len, opus_int16 *pcm, int frame_size,
224*a58d3d2aSXin Li int decode_fec)
225*a58d3d2aSXin Li {
226*a58d3d2aSXin Li return opus_multistream_decode_native(get_multistream_decoder(st), data, len,
227*a58d3d2aSXin Li pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, 1,
228*a58d3d2aSXin Li get_dec_demixing_matrix(st));
229*a58d3d2aSXin Li }
230*a58d3d2aSXin Li #endif
231*a58d3d2aSXin Li
232*a58d3d2aSXin Li #ifndef DISABLE_FLOAT_API
opus_projection_decode_float(OpusProjectionDecoder * st,const unsigned char * data,opus_int32 len,float * pcm,int frame_size,int decode_fec)233*a58d3d2aSXin Li int opus_projection_decode_float(OpusProjectionDecoder *st, const unsigned char *data,
234*a58d3d2aSXin Li opus_int32 len, float *pcm, int frame_size, int decode_fec)
235*a58d3d2aSXin Li {
236*a58d3d2aSXin Li return opus_multistream_decode_native(get_multistream_decoder(st), data, len,
237*a58d3d2aSXin Li pcm, opus_projection_copy_channel_out_float, frame_size, decode_fec, 0,
238*a58d3d2aSXin Li get_dec_demixing_matrix(st));
239*a58d3d2aSXin Li }
240*a58d3d2aSXin Li #endif
241*a58d3d2aSXin Li
opus_projection_decoder_ctl(OpusProjectionDecoder * st,int request,...)242*a58d3d2aSXin Li int opus_projection_decoder_ctl(OpusProjectionDecoder *st, int request, ...)
243*a58d3d2aSXin Li {
244*a58d3d2aSXin Li va_list ap;
245*a58d3d2aSXin Li int ret = OPUS_OK;
246*a58d3d2aSXin Li
247*a58d3d2aSXin Li va_start(ap, request);
248*a58d3d2aSXin Li ret = opus_multistream_decoder_ctl_va_list(get_multistream_decoder(st),
249*a58d3d2aSXin Li request, ap);
250*a58d3d2aSXin Li va_end(ap);
251*a58d3d2aSXin Li return ret;
252*a58d3d2aSXin Li }
253*a58d3d2aSXin Li
opus_projection_decoder_destroy(OpusProjectionDecoder * st)254*a58d3d2aSXin Li void opus_projection_decoder_destroy(OpusProjectionDecoder *st)
255*a58d3d2aSXin Li {
256*a58d3d2aSXin Li opus_free(st);
257*a58d3d2aSXin Li }
258*a58d3d2aSXin Li
259