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