annotate src/opus-1.3/tests/test_opus_projection.c @ 169:223a55898ab9 tip default

Add null config files
author Chris Cannam <cannam@all-day-breakfast.com>
date Mon, 02 Mar 2020 14:03:47 +0000
parents 4664ac0c1032
children
rev   line source
cannam@154 1 /* Copyright (c) 2017 Google Inc.
cannam@154 2 Written by Andrew Allen */
cannam@154 3 /*
cannam@154 4 Redistribution and use in source and binary forms, with or without
cannam@154 5 modification, are permitted provided that the following conditions
cannam@154 6 are met:
cannam@154 7
cannam@154 8 - Redistributions of source code must retain the above copyright
cannam@154 9 notice, this list of conditions and the following disclaimer.
cannam@154 10
cannam@154 11 - Redistributions in binary form must reproduce the above copyright
cannam@154 12 notice, this list of conditions and the following disclaimer in the
cannam@154 13 documentation and/or other materials provided with the distribution.
cannam@154 14
cannam@154 15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
cannam@154 16 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
cannam@154 17 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
cannam@154 18 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
cannam@154 19 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
cannam@154 20 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
cannam@154 21 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
cannam@154 22 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
cannam@154 23 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
cannam@154 24 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
cannam@154 25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
cannam@154 26 */
cannam@154 27
cannam@154 28 #ifdef HAVE_CONFIG_H
cannam@154 29 #include "config.h"
cannam@154 30 #endif
cannam@154 31
cannam@154 32 #include <assert.h>
cannam@154 33 #include <stdio.h>
cannam@154 34 #include <stdlib.h>
cannam@154 35 #include <stdint.h>
cannam@154 36 #include <string.h>
cannam@154 37 #include "float_cast.h"
cannam@154 38 #include "opus.h"
cannam@154 39 #include "test_opus_common.h"
cannam@154 40 #include "opus_projection.h"
cannam@154 41 #include "mathops.h"
cannam@154 42 #include "../src/mapping_matrix.h"
cannam@154 43 #include "mathops.h"
cannam@154 44
cannam@154 45 #define BUFFER_SIZE 960
cannam@154 46 #define MAX_DATA_BYTES 32768
cannam@154 47 #define MAX_FRAME_SAMPLES 5760
cannam@154 48 #define ERROR_TOLERANCE 1
cannam@154 49
cannam@154 50 #define SIMPLE_MATRIX_SIZE 12
cannam@154 51 #define SIMPLE_MATRIX_FRAME_SIZE 10
cannam@154 52 #define SIMPLE_MATRIX_INPUT_SIZE 30
cannam@154 53 #define SIMPLE_MATRIX_OUTPUT_SIZE 40
cannam@154 54
cannam@154 55 int assert_is_equal(
cannam@154 56 const opus_val16 *a, const opus_int16 *b, int size, opus_int16 tolerance)
cannam@154 57 {
cannam@154 58 int i;
cannam@154 59 for (i = 0; i < size; i++)
cannam@154 60 {
cannam@154 61 #ifdef FIXED_POINT
cannam@154 62 opus_int16 val = a[i];
cannam@154 63 #else
cannam@154 64 opus_int16 val = FLOAT2INT16(a[i]);
cannam@154 65 #endif
cannam@154 66 if (abs(val - b[i]) > tolerance)
cannam@154 67 return 1;
cannam@154 68 }
cannam@154 69 return 0;
cannam@154 70 }
cannam@154 71
cannam@154 72 int assert_is_equal_short(
cannam@154 73 const opus_int16 *a, const opus_int16 *b, int size, opus_int16 tolerance)
cannam@154 74 {
cannam@154 75 int i;
cannam@154 76 for (i = 0; i < size; i++)
cannam@154 77 if (abs(a[i] - b[i]) > tolerance)
cannam@154 78 return 1;
cannam@154 79 return 0;
cannam@154 80 }
cannam@154 81
cannam@154 82 void test_simple_matrix(void)
cannam@154 83 {
cannam@154 84 const MappingMatrix simple_matrix_params = {4, 3, 0};
cannam@154 85 const opus_int16 simple_matrix_data[SIMPLE_MATRIX_SIZE] = {0, 32767, 0, 0, 32767, 0, 0, 0, 0, 0, 0, 32767};
cannam@154 86 const opus_int16 input_int16[SIMPLE_MATRIX_INPUT_SIZE] = {
cannam@154 87 32767, 0, -32768, 29491, -3277, -29491, 26214, -6554, -26214, 22938, -9830,
cannam@154 88 -22938, 19661, -13107, -19661, 16384, -16384, -16384, 13107, -19661, -13107,
cannam@154 89 9830, -22938, -9830, 6554, -26214, -6554, 3277, -29491, -3277};
cannam@154 90 const opus_int16 expected_output_int16[SIMPLE_MATRIX_OUTPUT_SIZE] = {
cannam@154 91 0, 32767, 0, -32768, -3277, 29491, 0, -29491, -6554, 26214, 0, -26214,
cannam@154 92 -9830, 22938, 0, -22938, -13107, 19661, 0, -19661, -16384, 16384, 0, -16384,
cannam@154 93 -19661, 13107, 0, -13107, -22938, 9830, 0, -9830, -26214, 6554, 0, -6554,
cannam@154 94 -29491, 3277, 0, -3277};
cannam@154 95
cannam@154 96 int i, ret;
cannam@154 97 opus_int32 simple_matrix_size;
cannam@154 98 opus_val16 *input_val16;
cannam@154 99 opus_val16 *output_val16;
cannam@154 100 opus_int16 *output_int16;
cannam@154 101 MappingMatrix *simple_matrix;
cannam@154 102
cannam@154 103 /* Allocate input/output buffers. */
cannam@154 104 input_val16 = (opus_val16 *)opus_alloc(sizeof(opus_val16) * SIMPLE_MATRIX_INPUT_SIZE);
cannam@154 105 output_int16 = (opus_int16 *)opus_alloc(sizeof(opus_int16) * SIMPLE_MATRIX_OUTPUT_SIZE);
cannam@154 106 output_val16 = (opus_val16 *)opus_alloc(sizeof(opus_val16) * SIMPLE_MATRIX_OUTPUT_SIZE);
cannam@154 107
cannam@154 108 /* Initialize matrix */
cannam@154 109 simple_matrix_size = mapping_matrix_get_size(simple_matrix_params.rows,
cannam@154 110 simple_matrix_params.cols);
cannam@154 111 if (!simple_matrix_size)
cannam@154 112 test_failed();
cannam@154 113
cannam@154 114 simple_matrix = (MappingMatrix *)opus_alloc(simple_matrix_size);
cannam@154 115 mapping_matrix_init(simple_matrix, simple_matrix_params.rows,
cannam@154 116 simple_matrix_params.cols, simple_matrix_params.gain, simple_matrix_data,
cannam@154 117 sizeof(simple_matrix_data));
cannam@154 118
cannam@154 119 /* Copy inputs. */
cannam@154 120 for (i = 0; i < SIMPLE_MATRIX_INPUT_SIZE; i++)
cannam@154 121 {
cannam@154 122 #ifdef FIXED_POINT
cannam@154 123 input_val16[i] = input_int16[i];
cannam@154 124 #else
cannam@154 125 input_val16[i] = (1/32768.f)*input_int16[i];
cannam@154 126 #endif
cannam@154 127 }
cannam@154 128
cannam@154 129 /* _in_short */
cannam@154 130 for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++)
cannam@154 131 output_val16[i] = 0;
cannam@154 132 for (i = 0; i < simple_matrix->rows; i++)
cannam@154 133 {
cannam@154 134 mapping_matrix_multiply_channel_in_short(simple_matrix,
cannam@154 135 input_int16, simple_matrix->cols, &output_val16[i], i,
cannam@154 136 simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE);
cannam@154 137 }
cannam@154 138 ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE);
cannam@154 139 if (ret)
cannam@154 140 test_failed();
cannam@154 141
cannam@154 142 /* _out_short */
cannam@154 143 for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++)
cannam@154 144 output_int16[i] = 0;
cannam@154 145 for (i = 0; i < simple_matrix->cols; i++)
cannam@154 146 {
cannam@154 147 mapping_matrix_multiply_channel_out_short(simple_matrix,
cannam@154 148 &input_val16[i], i, simple_matrix->cols, output_int16,
cannam@154 149 simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE);
cannam@154 150 }
cannam@154 151 ret = assert_is_equal_short(output_int16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE);
cannam@154 152 if (ret)
cannam@154 153 test_failed();
cannam@154 154
cannam@154 155 #if !defined(DISABLE_FLOAT_API) && !defined(FIXED_POINT)
cannam@154 156 /* _in_float */
cannam@154 157 for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++)
cannam@154 158 output_val16[i] = 0;
cannam@154 159 for (i = 0; i < simple_matrix->rows; i++)
cannam@154 160 {
cannam@154 161 mapping_matrix_multiply_channel_in_float(simple_matrix,
cannam@154 162 input_val16, simple_matrix->cols, &output_val16[i], i,
cannam@154 163 simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE);
cannam@154 164 }
cannam@154 165 ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE);
cannam@154 166 if (ret)
cannam@154 167 test_failed();
cannam@154 168
cannam@154 169 /* _out_float */
cannam@154 170 for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++)
cannam@154 171 output_val16[i] = 0;
cannam@154 172 for (i = 0; i < simple_matrix->cols; i++)
cannam@154 173 {
cannam@154 174 mapping_matrix_multiply_channel_out_float(simple_matrix,
cannam@154 175 &input_val16[i], i, simple_matrix->cols, output_val16,
cannam@154 176 simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE);
cannam@154 177 }
cannam@154 178 ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE);
cannam@154 179 if (ret)
cannam@154 180 test_failed();
cannam@154 181 #endif
cannam@154 182
cannam@154 183 opus_free(input_val16);
cannam@154 184 opus_free(output_int16);
cannam@154 185 opus_free(output_val16);
cannam@154 186 opus_free(simple_matrix);
cannam@154 187 }
cannam@154 188
cannam@154 189 void test_creation_arguments(const int channels, const int mapping_family)
cannam@154 190 {
cannam@154 191 int streams;
cannam@154 192 int coupled_streams;
cannam@154 193 int enc_error;
cannam@154 194 int dec_error;
cannam@154 195 int ret;
cannam@154 196 OpusProjectionEncoder *st_enc = NULL;
cannam@154 197 OpusProjectionDecoder *st_dec = NULL;
cannam@154 198
cannam@154 199 const opus_int32 Fs = 48000;
cannam@154 200 const int application = OPUS_APPLICATION_AUDIO;
cannam@154 201
cannam@154 202 int order_plus_one = (int)floor(sqrt((float)channels));
cannam@154 203 int nondiegetic_channels = channels - order_plus_one * order_plus_one;
cannam@154 204
cannam@154 205 int is_channels_valid = 0;
cannam@154 206 int is_projection_valid = 0;
cannam@154 207
cannam@154 208 st_enc = opus_projection_ambisonics_encoder_create(Fs, channels,
cannam@154 209 mapping_family, &streams, &coupled_streams, application, &enc_error);
cannam@154 210 if (st_enc != NULL)
cannam@154 211 {
cannam@154 212 opus_int32 matrix_size;
cannam@154 213 unsigned char *matrix;
cannam@154 214
cannam@154 215 ret = opus_projection_encoder_ctl(st_enc,
cannam@154 216 OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, &matrix_size);
cannam@154 217 if (ret != OPUS_OK || !matrix_size)
cannam@154 218 test_failed();
cannam@154 219
cannam@154 220 matrix = (unsigned char *)opus_alloc(matrix_size);
cannam@154 221 ret = opus_projection_encoder_ctl(st_enc,
cannam@154 222 OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, matrix, matrix_size);
cannam@154 223
cannam@154 224 opus_projection_encoder_destroy(st_enc);
cannam@154 225
cannam@154 226 st_dec = opus_projection_decoder_create(Fs, channels, streams,
cannam@154 227 coupled_streams, matrix, matrix_size, &dec_error);
cannam@154 228 if (st_dec != NULL)
cannam@154 229 {
cannam@154 230 opus_projection_decoder_destroy(st_dec);
cannam@154 231 }
cannam@154 232 opus_free(matrix);
cannam@154 233 }
cannam@154 234
cannam@154 235 is_channels_valid = (order_plus_one >= 2 && order_plus_one <= 4) &&
cannam@154 236 (nondiegetic_channels == 0 || nondiegetic_channels == 2);
cannam@154 237 is_projection_valid = (enc_error == OPUS_OK && dec_error == OPUS_OK);
cannam@154 238 if (is_channels_valid ^ is_projection_valid)
cannam@154 239 {
cannam@154 240 fprintf(stderr, "Channels: %d, Family: %d\n", channels, mapping_family);
cannam@154 241 fprintf(stderr, "Order+1: %d, Non-diegetic Channels: %d\n",
cannam@154 242 order_plus_one, nondiegetic_channels);
cannam@154 243 fprintf(stderr, "Streams: %d, Coupled Streams: %d\n",
cannam@154 244 streams, coupled_streams);
cannam@154 245 test_failed();
cannam@154 246 }
cannam@154 247 }
cannam@154 248
cannam@154 249 void generate_music(short *buf, opus_int32 len, opus_int32 channels)
cannam@154 250 {
cannam@154 251 opus_int32 i,j,k;
cannam@154 252 opus_int32 *a,*b,*c,*d;
cannam@154 253 a = (opus_int32 *)malloc(sizeof(opus_int32) * channels);
cannam@154 254 b = (opus_int32 *)malloc(sizeof(opus_int32) * channels);
cannam@154 255 c = (opus_int32 *)malloc(sizeof(opus_int32) * channels);
cannam@154 256 d = (opus_int32 *)malloc(sizeof(opus_int32) * channels);
cannam@154 257 memset(a, 0, sizeof(opus_int32) * channels);
cannam@154 258 memset(b, 0, sizeof(opus_int32) * channels);
cannam@154 259 memset(c, 0, sizeof(opus_int32) * channels);
cannam@154 260 memset(d, 0, sizeof(opus_int32) * channels);
cannam@154 261 j=0;
cannam@154 262
cannam@154 263 for(i=0;i<len;i++)
cannam@154 264 {
cannam@154 265 for(k=0;k<channels;k++)
cannam@154 266 {
cannam@154 267 opus_uint32 r;
cannam@154 268 opus_int32 v;
cannam@154 269 v=(((j*((j>>12)^((j>>10|j>>12)&26&j>>7)))&128)+128)<<15;
cannam@154 270 r=fast_rand();v+=r&65535;v-=r>>16;
cannam@154 271 b[k]=v-a[k]+((b[k]*61+32)>>6);a[k]=v;
cannam@154 272 c[k]=(30*(c[k]+b[k]+d[k])+32)>>6;d[k]=b[k];
cannam@154 273 v=(c[k]+128)>>8;
cannam@154 274 buf[i*channels+k]=v>32767?32767:(v<-32768?-32768:v);
cannam@154 275 if(i%6==0)j++;
cannam@154 276 }
cannam@154 277 }
cannam@154 278
cannam@154 279 free(a);
cannam@154 280 free(b);
cannam@154 281 free(c);
cannam@154 282 free(d);
cannam@154 283 }
cannam@154 284
cannam@154 285 void test_encode_decode(opus_int32 bitrate, opus_int32 channels,
cannam@154 286 const int mapping_family)
cannam@154 287 {
cannam@154 288 const opus_int32 Fs = 48000;
cannam@154 289 const int application = OPUS_APPLICATION_AUDIO;
cannam@154 290
cannam@154 291 OpusProjectionEncoder *st_enc;
cannam@154 292 OpusProjectionDecoder *st_dec;
cannam@154 293 int streams;
cannam@154 294 int coupled;
cannam@154 295 int error;
cannam@154 296 short *buffer_in;
cannam@154 297 short *buffer_out;
cannam@154 298 unsigned char data[MAX_DATA_BYTES] = { 0 };
cannam@154 299 int len;
cannam@154 300 int out_samples;
cannam@154 301 opus_int32 matrix_size = 0;
cannam@154 302 unsigned char *matrix = NULL;
cannam@154 303
cannam@154 304 buffer_in = (short *)malloc(sizeof(short) * BUFFER_SIZE * channels);
cannam@154 305 buffer_out = (short *)malloc(sizeof(short) * BUFFER_SIZE * channels);
cannam@154 306
cannam@154 307 st_enc = opus_projection_ambisonics_encoder_create(Fs, channels,
cannam@154 308 mapping_family, &streams, &coupled, application, &error);
cannam@154 309 if (error != OPUS_OK) {
cannam@154 310 fprintf(stderr,
cannam@154 311 "Couldn\'t create encoder with %d channels and mapping family %d.\n",
cannam@154 312 channels, mapping_family);
cannam@154 313 free(buffer_in);
cannam@154 314 free(buffer_out);
cannam@154 315 test_failed();
cannam@154 316 }
cannam@154 317
cannam@154 318 error = opus_projection_encoder_ctl(st_enc,
cannam@154 319 OPUS_SET_BITRATE(bitrate * 1000 * (streams + coupled)));
cannam@154 320 if (error != OPUS_OK)
cannam@154 321 {
cannam@154 322 goto bad_cleanup;
cannam@154 323 }
cannam@154 324
cannam@154 325 error = opus_projection_encoder_ctl(st_enc,
cannam@154 326 OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, &matrix_size);
cannam@154 327 if (error != OPUS_OK || !matrix_size)
cannam@154 328 {
cannam@154 329 goto bad_cleanup;
cannam@154 330 }
cannam@154 331
cannam@154 332 matrix = (unsigned char *)opus_alloc(matrix_size);
cannam@154 333 error = opus_projection_encoder_ctl(st_enc,
cannam@154 334 OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, matrix, matrix_size);
cannam@154 335
cannam@154 336 st_dec = opus_projection_decoder_create(Fs, channels, streams, coupled,
cannam@154 337 matrix, matrix_size, &error);
cannam@154 338 opus_free(matrix);
cannam@154 339
cannam@154 340 if (error != OPUS_OK) {
cannam@154 341 fprintf(stderr,
cannam@154 342 "Couldn\'t create decoder with %d channels, %d streams "
cannam@154 343 "and %d coupled streams.\n", channels, streams, coupled);
cannam@154 344 goto bad_cleanup;
cannam@154 345 }
cannam@154 346
cannam@154 347 generate_music(buffer_in, BUFFER_SIZE, channels);
cannam@154 348
cannam@154 349 len = opus_projection_encode(
cannam@154 350 st_enc, buffer_in, BUFFER_SIZE, data, MAX_DATA_BYTES);
cannam@154 351 if(len<0 || len>MAX_DATA_BYTES) {
cannam@154 352 fprintf(stderr,"opus_encode() returned %d\n", len);
cannam@154 353 goto bad_cleanup;
cannam@154 354 }
cannam@154 355
cannam@154 356 out_samples = opus_projection_decode(
cannam@154 357 st_dec, data, len, buffer_out, MAX_FRAME_SAMPLES, 0);
cannam@154 358 if(out_samples!=BUFFER_SIZE) {
cannam@154 359 fprintf(stderr,"opus_decode() returned %d\n", out_samples);
cannam@154 360 goto bad_cleanup;
cannam@154 361 }
cannam@154 362
cannam@154 363 free(buffer_in);
cannam@154 364 free(buffer_out);
cannam@154 365 return;
cannam@154 366 bad_cleanup:
cannam@154 367 free(buffer_in);
cannam@154 368 free(buffer_out);
cannam@154 369 test_failed();
cannam@154 370 }
cannam@154 371
cannam@154 372 int main(int _argc, char **_argv)
cannam@154 373 {
cannam@154 374 unsigned int i;
cannam@154 375
cannam@154 376 (void)_argc;
cannam@154 377 (void)_argv;
cannam@154 378
cannam@154 379 /* Test simple matrix multiplication routines. */
cannam@154 380 test_simple_matrix();
cannam@154 381
cannam@154 382 /* Test full range of channels in creation arguments. */
cannam@154 383 for (i = 0; i < 255; i++)
cannam@154 384 test_creation_arguments(i, 3);
cannam@154 385
cannam@154 386 /* Test encode/decode pipeline. */
cannam@154 387 test_encode_decode(64 * 18, 18, 3);
cannam@154 388
cannam@154 389 fprintf(stderr, "All projection tests passed.\n");
cannam@154 390 return 0;
cannam@154 391 }
cannam@154 392