• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <stdio.h>
33 #include <stdlib.h>
34 #include <stdint.h>
35 #include <string.h>
36 #include "float_cast.h"
37 #include "opus.h"
38 #include "test_opus_common.h"
39 #include "opus_projection.h"
40 #include "mathops.h"
41 #include "../src/mapping_matrix.h"
42 #include "mathops.h"
43 
44 #define BUFFER_SIZE 960
45 #define MAX_DATA_BYTES 32768
46 #define MAX_FRAME_SAMPLES 5760
47 #define ERROR_TOLERANCE 1
48 
49 #define SIMPLE_MATRIX_SIZE 12
50 #define SIMPLE_MATRIX_FRAME_SIZE 10
51 #define SIMPLE_MATRIX_INPUT_SIZE 30
52 #define SIMPLE_MATRIX_OUTPUT_SIZE 40
53 
assert_is_equal(const opus_val16 * a,const opus_int16 * b,int size,opus_int16 tolerance)54 int assert_is_equal(
55   const opus_val16 *a, const opus_int16 *b, int size, opus_int16 tolerance)
56 {
57   int i;
58   for (i = 0; i < size; i++)
59   {
60 #ifdef FIXED_POINT
61     opus_int16 val = a[i];
62 #else
63     opus_int16 val = FLOAT2INT16(a[i]);
64 #endif
65     if (abs(val - b[i]) > tolerance)
66       return 1;
67   }
68   return 0;
69 }
70 
assert_is_equal_short(const opus_int16 * a,const opus_int16 * b,int size,opus_int16 tolerance)71 int assert_is_equal_short(
72   const opus_int16 *a, const opus_int16 *b, int size, opus_int16 tolerance)
73 {
74   int i;
75   for (i = 0; i < size; i++)
76     if (abs(a[i] - b[i]) > tolerance)
77       return 1;
78   return 0;
79 }
80 
test_simple_matrix(void)81 void test_simple_matrix(void)
82 {
83   const MappingMatrix simple_matrix_params = {4, 3, 0};
84   const opus_int16 simple_matrix_data[SIMPLE_MATRIX_SIZE] = {0, 32767, 0, 0, 32767, 0, 0, 0, 0, 0, 0, 32767};
85   const opus_int16 input_int16[SIMPLE_MATRIX_INPUT_SIZE] = {
86     32767, 0, -32768, 29491, -3277, -29491, 26214, -6554, -26214, 22938, -9830,
87     -22938, 19661, -13107, -19661, 16384, -16384, -16384, 13107, -19661, -13107,
88     9830, -22938, -9830, 6554, -26214, -6554, 3277, -29491, -3277};
89   const opus_int16 expected_output_int16[SIMPLE_MATRIX_OUTPUT_SIZE] = {
90     0, 32767, 0, -32768, -3277, 29491, 0, -29491, -6554, 26214, 0, -26214,
91     -9830, 22938, 0, -22938, -13107, 19661, 0, -19661, -16384, 16384, 0, -16384,
92     -19661, 13107, 0, -13107, -22938, 9830, 0, -9830, -26214, 6554, 0, -6554,
93     -29491, 3277, 0, -3277};
94 
95   int i, ret;
96   opus_int32 simple_matrix_size;
97   opus_val16 *input_val16;
98   opus_val16 *output_val16;
99   opus_int16 *output_int16;
100   MappingMatrix *simple_matrix;
101 
102   /* Allocate input/output buffers. */
103   input_val16 = (opus_val16 *)opus_alloc(sizeof(opus_val16) * SIMPLE_MATRIX_INPUT_SIZE);
104   output_int16 = (opus_int16 *)opus_alloc(sizeof(opus_int16) * SIMPLE_MATRIX_OUTPUT_SIZE);
105   output_val16 = (opus_val16 *)opus_alloc(sizeof(opus_val16) * SIMPLE_MATRIX_OUTPUT_SIZE);
106 
107   /* Initialize matrix */
108   simple_matrix_size = mapping_matrix_get_size(simple_matrix_params.rows,
109     simple_matrix_params.cols);
110   if (!simple_matrix_size)
111     test_failed();
112 
113   simple_matrix = (MappingMatrix *)opus_alloc(simple_matrix_size);
114   mapping_matrix_init(simple_matrix, simple_matrix_params.rows,
115     simple_matrix_params.cols, simple_matrix_params.gain, simple_matrix_data,
116     sizeof(simple_matrix_data));
117 
118   /* Copy inputs. */
119   for (i = 0; i < SIMPLE_MATRIX_INPUT_SIZE; i++)
120   {
121 #ifdef FIXED_POINT
122     input_val16[i] = input_int16[i];
123 #else
124     input_val16[i] = (1/32768.f)*input_int16[i];
125 #endif
126   }
127 
128   /* _in_short */
129   for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++)
130     output_val16[i] = 0;
131   for (i = 0; i < simple_matrix->rows; i++)
132   {
133     mapping_matrix_multiply_channel_in_short(simple_matrix,
134       input_int16, simple_matrix->cols, &output_val16[i], i,
135       simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE);
136   }
137   ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE);
138   if (ret)
139     test_failed();
140 
141   /* _out_short */
142   for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++)
143     output_int16[i] = 0;
144   for (i = 0; i < simple_matrix->cols; i++)
145   {
146     mapping_matrix_multiply_channel_out_short(simple_matrix,
147       &input_val16[i], i, simple_matrix->cols, output_int16,
148       simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE);
149   }
150   ret = assert_is_equal_short(output_int16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE);
151   if (ret)
152     test_failed();
153 
154 #if !defined(DISABLE_FLOAT_API) && !defined(FIXED_POINT)
155   /* _in_float */
156   for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++)
157     output_val16[i] = 0;
158   for (i = 0; i < simple_matrix->rows; i++)
159   {
160     mapping_matrix_multiply_channel_in_float(simple_matrix,
161       input_val16, simple_matrix->cols, &output_val16[i], i,
162       simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE);
163   }
164   ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE);
165   if (ret)
166     test_failed();
167 
168   /* _out_float */
169   for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++)
170     output_val16[i] = 0;
171   for (i = 0; i < simple_matrix->cols; i++)
172   {
173     mapping_matrix_multiply_channel_out_float(simple_matrix,
174       &input_val16[i], i, simple_matrix->cols, output_val16,
175       simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE);
176   }
177   ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE);
178   if (ret)
179     test_failed();
180 #endif
181 
182   opus_free(input_val16);
183   opus_free(output_int16);
184   opus_free(output_val16);
185   opus_free(simple_matrix);
186 }
187 
test_creation_arguments(const int channels,const int mapping_family)188 void test_creation_arguments(const int channels, const int mapping_family)
189 {
190   int streams;
191   int coupled_streams;
192   int enc_error;
193   int dec_error;
194   int ret;
195   OpusProjectionEncoder *st_enc = NULL;
196   OpusProjectionDecoder *st_dec = NULL;
197 
198   const opus_int32 Fs = 48000;
199   const int application = OPUS_APPLICATION_AUDIO;
200 
201   int order_plus_one = (int)floor(sqrt((float)channels));
202   int nondiegetic_channels = channels - order_plus_one * order_plus_one;
203 
204   int is_channels_valid = 0;
205   int is_projection_valid = 0;
206 
207   st_enc = opus_projection_ambisonics_encoder_create(Fs, channels,
208     mapping_family, &streams, &coupled_streams, application, &enc_error);
209   if (st_enc != NULL)
210   {
211     opus_int32 matrix_size;
212     unsigned char *matrix;
213 
214     ret = opus_projection_encoder_ctl(st_enc,
215       OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, &matrix_size);
216     if (ret != OPUS_OK || !matrix_size)
217       test_failed();
218 
219     matrix = (unsigned char *)opus_alloc(matrix_size);
220     ret = opus_projection_encoder_ctl(st_enc,
221       OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, matrix, matrix_size);
222 
223     opus_projection_encoder_destroy(st_enc);
224 
225     st_dec = opus_projection_decoder_create(Fs, channels, streams,
226       coupled_streams, matrix, matrix_size, &dec_error);
227     if (st_dec != NULL)
228     {
229       opus_projection_decoder_destroy(st_dec);
230     }
231     opus_free(matrix);
232   }
233 
234   is_channels_valid = (order_plus_one >= 2 && order_plus_one <= 4) &&
235     (nondiegetic_channels == 0 || nondiegetic_channels == 2);
236   is_projection_valid = (enc_error == OPUS_OK && dec_error == OPUS_OK);
237   if (is_channels_valid ^ is_projection_valid)
238   {
239     fprintf(stderr, "Channels: %d, Family: %d\n", channels, mapping_family);
240     fprintf(stderr, "Order+1: %d, Non-diegetic Channels: %d\n",
241       order_plus_one, nondiegetic_channels);
242     fprintf(stderr, "Streams: %d, Coupled Streams: %d\n",
243       streams, coupled_streams);
244     test_failed();
245   }
246 }
247 
generate_music(short * buf,opus_int32 len,opus_int32 channels)248 void generate_music(short *buf, opus_int32 len, opus_int32 channels)
249 {
250    opus_int32 i,j,k;
251    opus_int32 *a,*b,*c,*d;
252    a = (opus_int32 *)malloc(sizeof(opus_int32) * channels);
253    b = (opus_int32 *)malloc(sizeof(opus_int32) * channels);
254    c = (opus_int32 *)malloc(sizeof(opus_int32) * channels);
255    d = (opus_int32 *)malloc(sizeof(opus_int32) * channels);
256    memset(a, 0, sizeof(opus_int32) * channels);
257    memset(b, 0, sizeof(opus_int32) * channels);
258    memset(c, 0, sizeof(opus_int32) * channels);
259    memset(d, 0, sizeof(opus_int32) * channels);
260    j=0;
261 
262    for(i=0;i<len;i++)
263    {
264      for(k=0;k<channels;k++)
265      {
266       opus_uint32 r;
267       opus_int32 v;
268       v=(((j*((j>>12)^((j>>10|j>>12)&26&j>>7)))&128)+128)<<15;
269       r=fast_rand();v+=r&65535;v-=r>>16;
270       b[k]=v-a[k]+((b[k]*61+32)>>6);a[k]=v;
271       c[k]=(30*(c[k]+b[k]+d[k])+32)>>6;d[k]=b[k];
272       v=(c[k]+128)>>8;
273       buf[i*channels+k]=v>32767?32767:(v<-32768?-32768:v);
274       if(i%6==0)j++;
275      }
276    }
277 
278    free(a);
279    free(b);
280    free(c);
281    free(d);
282 }
283 
test_encode_decode(opus_int32 bitrate,opus_int32 channels,const int mapping_family)284 void test_encode_decode(opus_int32 bitrate, opus_int32 channels,
285                         const int mapping_family)
286 {
287   const opus_int32 Fs = 48000;
288   const int application = OPUS_APPLICATION_AUDIO;
289 
290   OpusProjectionEncoder *st_enc;
291   OpusProjectionDecoder *st_dec;
292   int streams;
293   int coupled;
294   int error;
295   short *buffer_in;
296   short *buffer_out;
297   unsigned char data[MAX_DATA_BYTES] = { 0 };
298   int len;
299   int out_samples;
300   opus_int32 matrix_size = 0;
301   unsigned char *matrix = NULL;
302 
303   buffer_in = (short *)malloc(sizeof(short) * BUFFER_SIZE * channels);
304   buffer_out = (short *)malloc(sizeof(short) * BUFFER_SIZE * channels);
305 
306   st_enc = opus_projection_ambisonics_encoder_create(Fs, channels,
307     mapping_family, &streams, &coupled, application, &error);
308   if (error != OPUS_OK) {
309     fprintf(stderr,
310       "Couldn\'t create encoder with %d channels and mapping family %d.\n",
311       channels, mapping_family);
312     free(buffer_in);
313     free(buffer_out);
314     test_failed();
315   }
316 
317   error = opus_projection_encoder_ctl(st_enc,
318     OPUS_SET_BITRATE(bitrate * 1000 * (streams + coupled)));
319   if (error != OPUS_OK)
320   {
321     goto bad_cleanup;
322   }
323 
324   error = opus_projection_encoder_ctl(st_enc,
325     OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, &matrix_size);
326   if (error != OPUS_OK || !matrix_size)
327   {
328     goto bad_cleanup;
329   }
330 
331   matrix = (unsigned char *)opus_alloc(matrix_size);
332   error = opus_projection_encoder_ctl(st_enc,
333     OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, matrix, matrix_size);
334 
335   st_dec = opus_projection_decoder_create(Fs, channels, streams, coupled,
336     matrix, matrix_size, &error);
337   opus_free(matrix);
338 
339   if (error != OPUS_OK) {
340     fprintf(stderr,
341       "Couldn\'t create decoder with %d channels, %d streams "
342       "and %d coupled streams.\n", channels, streams, coupled);
343     goto bad_cleanup;
344   }
345 
346   generate_music(buffer_in, BUFFER_SIZE, channels);
347 
348   len = opus_projection_encode(
349     st_enc, buffer_in, BUFFER_SIZE, data, MAX_DATA_BYTES);
350   if(len<0 || len>MAX_DATA_BYTES) {
351     fprintf(stderr,"opus_encode() returned %d\n", len);
352     goto bad_cleanup;
353   }
354 
355   out_samples = opus_projection_decode(
356     st_dec, data, len, buffer_out, MAX_FRAME_SAMPLES, 0);
357   if(out_samples!=BUFFER_SIZE) {
358     fprintf(stderr,"opus_decode() returned %d\n", out_samples);
359     goto bad_cleanup;
360   }
361 
362   opus_projection_decoder_destroy(st_dec);
363   opus_projection_encoder_destroy(st_enc);
364   free(buffer_in);
365   free(buffer_out);
366   return;
367 bad_cleanup:
368   free(buffer_in);
369   free(buffer_out);
370   test_failed();
371 }
372 
main(int _argc,char ** _argv)373 int main(int _argc, char **_argv)
374 {
375   unsigned int i;
376 
377   (void)_argc;
378   (void)_argv;
379 
380   /* Test simple matrix multiplication routines. */
381   test_simple_matrix();
382 
383   /* Test full range of channels in creation arguments. */
384   for (i = 0; i < 255; i++)
385     test_creation_arguments(i, 3);
386 
387   /* Test encode/decode pipeline. */
388   test_encode_decode(64 * 18, 18, 3);
389 
390   fprintf(stderr, "All projection tests passed.\n");
391   return 0;
392 }
393 
394