diff options
-rw-r--r-- | src/mapping_matrix.c | 155 | ||||
-rw-r--r-- | src/mapping_matrix.h | 30 | ||||
-rw-r--r-- | src/opus_multistream_decoder.c | 40 | ||||
-rw-r--r-- | src/opus_multistream_encoder.c | 38 | ||||
-rw-r--r-- | src/opus_private.h | 46 | ||||
-rw-r--r-- | src/opus_projection_decoder.c | 127 | ||||
-rw-r--r-- | src/opus_projection_encoder.c | 99 | ||||
-rw-r--r-- | tests/test_opus_projection.c | 235 |
8 files changed, 448 insertions, 322 deletions
diff --git a/src/mapping_matrix.c b/src/mapping_matrix.c index 5268bc6d..d3d59d61 100644 --- a/src/mapping_matrix.c +++ b/src/mapping_matrix.c @@ -41,12 +41,12 @@ int mapping_matrix_get_size(int rows, int cols) { - return align(sizeof(MappingMatrix)) + rows * cols * sizeof(opus_int16); + return align(sizeof(MappingMatrix)) + align(rows * cols * sizeof(opus_int16)); } opus_int16 *mapping_matrix_get_data(const MappingMatrix *matrix) { - return (opus_int16*)(void *)(matrix + align(sizeof(MappingMatrix))); + return (opus_int16*)((char*)matrix + align(sizeof(MappingMatrix))); } void mapping_matrix_init(MappingMatrix * const matrix, @@ -58,7 +58,7 @@ void mapping_matrix_init(MappingMatrix * const matrix, #if !defined(ENABLE_ASSERTIONS) (void)data_size; #endif - celt_assert((opus_uint32)data_size == rows * cols * sizeof(opus_int16)); + celt_assert(align(data_size) == align(rows * cols * sizeof(opus_int16))); matrix->rows = rows; matrix->cols = cols; @@ -71,18 +71,18 @@ void mapping_matrix_init(MappingMatrix * const matrix, } #ifndef DISABLE_FLOAT_API -void mapping_matrix_multiply_float(const MappingMatrix *matrix, - const float *input, int input_rows, - float *output, int output_rows, - int frame_size) +void mapping_matrix_multiply_channel_in_float( + const MappingMatrix *matrix, + const float *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size) { - /* Matrix data is ordered col-wise. - * Input (x) is [n x k], output (y) is [m x k], matrix (M) is [m x n]: - * y = M x - */ + /* Matrix data is ordered col-wise. */ opus_int16* matrix_data; - int i, row, col; - float matrix_cell, input_sample; + int i, col; celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); @@ -90,31 +90,70 @@ void mapping_matrix_multiply_float(const MappingMatrix *matrix, for (i = 0; i < frame_size; i++) { + float tmp = 0; + for (col = 0; col < input_rows; col++) + { + tmp += + matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * + input[MATRIX_INDEX(input_rows, col, i)]; + } +#if defined(FIXED_POINT) + output[output_rows * i] = FLOAT2INT16((1/32768.f)*tmp); +#else + output[output_rows * i] = (1/32768.f)*tmp; +#endif + } +} + +void mapping_matrix_multiply_channel_out_float( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + float *output, + int output_rows, + int frame_size +) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, row; + float input_sample; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { +#if defined(FIXED_POINT) + input_sample = (1/32768.f)*input[input_rows * i]; +#else + input_sample = input[input_rows * i]; +#endif for (row = 0; row < output_rows; row++) { - output[MATRIX_INDEX(output_rows, row, i)] = 0; - for (col = 0; col < input_rows; col++) - { - matrix_cell = (0.000030518f)*(float)matrix_data[MATRIX_INDEX(matrix->rows, row, col)]; - input_sample = input[MATRIX_INDEX(input_rows, col, i)]; - output[MATRIX_INDEX(output_rows, row, i)] += matrix_cell * input_sample; - } + float tmp = + (1/32768.f)*matrix_data[MATRIX_INDEX(matrix->rows, row, input_row)] * + input_sample; + output[MATRIX_INDEX(output_rows, row, i)] += tmp; } } } #endif /* DISABLE_FLOAT_API */ -void mapping_matrix_multiply_short(const MappingMatrix *matrix, - const opus_int16 *input, int input_rows, - opus_int16 *output, int output_rows, - int frame_size) +void mapping_matrix_multiply_channel_in_short( + const MappingMatrix *matrix, + const opus_int16 *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size) { - /* Matrix data is ordered col-wise. - * Input (x) is [n x k], output (y) is [m x k], matrix (M) is [m x n]: - * y = M x - */ + /* Matrix data is ordered col-wise. */ opus_int16* matrix_data; - int i, row, col; + int i, col; celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); @@ -122,16 +161,58 @@ void mapping_matrix_multiply_short(const MappingMatrix *matrix, for (i = 0; i < frame_size; i++) { + opus_val32 tmp = 0; + for (col = 0; col < input_rows; col++) + { +#if defined(FIXED_POINT) + tmp += + ((opus_int32)matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * + (opus_int32)input[MATRIX_INDEX(input_rows, col, i)]) >> 8; +#else + tmp += + matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * + input[MATRIX_INDEX(input_rows, col, i)]; +#endif + } +#if defined(FIXED_POINT) + output[output_rows * i] = (opus_int16)((tmp + 64) >> 7); +#else + output[output_rows * i] = (1/(32768.f*32768.f))*tmp; +#endif + } +} + +void mapping_matrix_multiply_channel_out_short( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + opus_int16 *output, + int output_rows, + int frame_size) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, row; + opus_int32 input_sample; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { +#if defined(FIXED_POINT) + input_sample = (opus_int32)input[input_rows * i]; +#else + input_sample = (opus_int32)FLOAT2INT16(input[input_rows * i]); +#endif for (row = 0; row < output_rows; row++) { - opus_int32 tmp = 0; - for (col = 0; col < input_rows; col++) - { - tmp += - (matrix_data[MATRIX_INDEX(matrix->rows, row, col)] * - input[MATRIX_INDEX(input_rows, col, i)]) >> 8; - } - output[MATRIX_INDEX(output_rows, row, i)] = (tmp + 64)>>7; + opus_int32 tmp = + (opus_int32)matrix_data[MATRIX_INDEX(matrix->rows, row, input_row)] * + input_sample; + output[MATRIX_INDEX(output_rows, row, i)] += (tmp + 16384) >> 15; } } } diff --git a/src/mapping_matrix.h b/src/mapping_matrix.h index 8fe82eab..381c8e1a 100644 --- a/src/mapping_matrix.h +++ b/src/mapping_matrix.h @@ -44,8 +44,8 @@ extern "C" { typedef struct MappingMatrix { - int rows; - int cols; + int rows; /* number of channels outputted from matrix. */ + int cols; /* number of channels inputted to matrix. */ int gain; /* in dB. S7.8-format. */ /* Matrix cell data goes here using col-wise ordering. */ } MappingMatrix; @@ -64,20 +64,42 @@ void mapping_matrix_init( ); #ifndef DISABLE_FLOAT_API -void mapping_matrix_multiply_float( +void mapping_matrix_multiply_channel_in_float( const MappingMatrix *matrix, const float *input, int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size +); + +void mapping_matrix_multiply_channel_out_float( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, float *output, int output_rows, int frame_size ); #endif /* DISABLE_FLOAT_API */ -void mapping_matrix_multiply_short( +void mapping_matrix_multiply_channel_in_short( const MappingMatrix *matrix, const opus_int16 *input, int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size +); + +void mapping_matrix_multiply_channel_out_short( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, opus_int16 *output, int output_rows, int frame_size diff --git a/src/opus_multistream_decoder.c b/src/opus_multistream_decoder.c index 6ab5d4c7..d5dbf4fe 100644 --- a/src/opus_multistream_decoder.c +++ b/src/opus_multistream_decoder.c @@ -135,15 +135,6 @@ OpusMSDecoder *opus_multistream_decoder_create( return st; } -typedef void (*opus_copy_channel_out_func)( - void *dst, - int dst_stride, - int dst_channel, - const opus_val16 *src, - int src_stride, - int frame_size -); - static int opus_multistream_packet_validate(const unsigned char *data, opus_int32 len, int nb_streams, opus_int32 Fs) { @@ -173,7 +164,7 @@ static int opus_multistream_packet_validate(const unsigned char *data, return samples; } -static int opus_multistream_decode_native( +int opus_multistream_decode_native( OpusMSDecoder *st, const unsigned char *data, opus_int32 len, @@ -181,7 +172,8 @@ static int opus_multistream_decode_native( opus_copy_channel_out_func copy_channel_out, int frame_size, int decode_fec, - int soft_clip + int soft_clip, + void *user_data ) { opus_int32 Fs; @@ -258,7 +250,7 @@ static int opus_multistream_decode_native( while ( (chan = get_left_channel(&st->layout, s, prev)) != -1) { (*copy_channel_out)(pcm, st->layout.nb_channels, chan, - buf, 2, frame_size); + buf, 2, frame_size, user_data); prev = chan; } prev = -1; @@ -266,7 +258,7 @@ static int opus_multistream_decode_native( while ( (chan = get_right_channel(&st->layout, s, prev)) != -1) { (*copy_channel_out)(pcm, st->layout.nb_channels, chan, - buf+1, 2, frame_size); + buf+1, 2, frame_size, user_data); prev = chan; } } else { @@ -276,7 +268,7 @@ static int opus_multistream_decode_native( while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1) { (*copy_channel_out)(pcm, st->layout.nb_channels, chan, - buf, 1, frame_size); + buf, 1, frame_size, user_data); prev = chan; } } @@ -287,7 +279,7 @@ static int opus_multistream_decode_native( if (st->layout.mapping[c] == 255) { (*copy_channel_out)(pcm, st->layout.nb_channels, c, - NULL, 0, frame_size); + NULL, 0, frame_size, user_data); } } RESTORE_STACK; @@ -301,11 +293,13 @@ static void opus_copy_channel_out_float( int dst_channel, const opus_val16 *src, int src_stride, - int frame_size + int frame_size, + void *user_data ) { float *float_dst; opus_int32 i; + (void)user_data; float_dst = (float*)dst; if (src != NULL) { @@ -330,11 +324,13 @@ static void opus_copy_channel_out_short( int dst_channel, const opus_val16 *src, int src_stride, - int frame_size + int frame_size, + void *user_data ) { opus_int16 *short_dst; opus_int32 i; + (void)user_data; short_dst = (opus_int16*)dst; if (src != NULL) { @@ -365,7 +361,7 @@ int opus_multistream_decode( ) { return opus_multistream_decode_native(st, data, len, - pcm, opus_copy_channel_out_short, frame_size, decode_fec, 0); + pcm, opus_copy_channel_out_short, frame_size, decode_fec, 0, NULL); } #ifndef DISABLE_FLOAT_API @@ -373,7 +369,7 @@ int opus_multistream_decode_float(OpusMSDecoder *st, const unsigned char *data, opus_int32 len, float *pcm, int frame_size, int decode_fec) { return opus_multistream_decode_native(st, data, len, - pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0); + pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0, NULL); } #endif @@ -383,20 +379,20 @@ int opus_multistream_decode(OpusMSDecoder *st, const unsigned char *data, opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec) { return opus_multistream_decode_native(st, data, len, - pcm, opus_copy_channel_out_short, frame_size, decode_fec, 1); + pcm, opus_copy_channel_out_short, frame_size, decode_fec, 1, NULL); } int opus_multistream_decode_float( OpusMSDecoder *st, const unsigned char *data, opus_int32 len, - float *pcm, + opus_val16 *pcm, int frame_size, int decode_fec ) { return opus_multistream_decode_native(st, data, len, - pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0); + pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0, NULL); } #endif diff --git a/src/opus_multistream_encoder.c b/src/opus_multistream_encoder.c index 07de6cce..1df9e7db 100644 --- a/src/opus_multistream_encoder.c +++ b/src/opus_multistream_encoder.c @@ -61,15 +61,6 @@ static const VorbisLayout vorbis_mappings[8] = { {5, 3, {0, 6, 1, 2, 3, 4, 5, 7}}, /* 8: 7.1 surround */ }; -typedef void (*opus_copy_channel_in_func)( - opus_val16 *dst, - int dst_stride, - const void *src, - int src_stride, - int src_channel, - int frame_size -); - static opus_val32 *ms_get_preemph_mem(OpusMSEncoder *st) { int s; @@ -274,7 +265,7 @@ void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *b int nb_frames = frame_size/freq_size; celt_assert(nb_frames*freq_size == frame_size); OPUS_COPY(in, mem+c*overlap, overlap); - (*copy_channel_in)(x, 1, pcm, channels, c, len); + (*copy_channel_in)(x, 1, pcm, channels, c, len, NULL); celt_preemphasis(x, in+overlap, frame_size, 1, upsample, celt_mode->preemph, preemph_mem+c, 0); #ifndef FIXED_POINT { @@ -862,7 +853,7 @@ static opus_int32 rate_allocation( /* Max size in case the encoder decides to return six frames (6 x 20 ms = 120 ms) */ #define MS_FRAME_TMP (6*1275+12) -static int opus_multistream_encode_native +int opus_multistream_encode_native ( OpusMSEncoder *st, opus_copy_channel_in_func copy_channel_in, @@ -872,7 +863,8 @@ static int opus_multistream_encode_native opus_int32 max_data_bytes, int lsb_depth, downmix_func downmix, - int float_api + int float_api, + void *user_data ) { opus_int32 Fs; @@ -1006,9 +998,9 @@ static int opus_multistream_encode_native left = get_left_channel(&st->layout, s, -1); right = get_right_channel(&st->layout, s, -1); (*copy_channel_in)(buf, 2, - pcm, st->layout.nb_channels, left, frame_size); + pcm, st->layout.nb_channels, left, frame_size, user_data); (*copy_channel_in)(buf+1, 2, - pcm, st->layout.nb_channels, right, frame_size); + pcm, st->layout.nb_channels, right, frame_size, user_data); ptr += align(coupled_size); if (st->mapping_type == MAPPING_TYPE_SURROUND) { @@ -1024,7 +1016,7 @@ static int opus_multistream_encode_native int i; int chan = get_mono_channel(&st->layout, s, -1); (*copy_channel_in)(buf, 1, - pcm, st->layout.nb_channels, chan, frame_size); + pcm, st->layout.nb_channels, chan, frame_size, user_data); ptr += align(mono_size); if (st->mapping_type == MAPPING_TYPE_SURROUND) { @@ -1083,11 +1075,13 @@ static void opus_copy_channel_in_float( const void *src, int src_stride, int src_channel, - int frame_size + int frame_size, + void *user_data ) { const float *float_src; opus_int32 i; + (void)user_data; float_src = (const float *)src; for (i=0;i<frame_size;i++) #if defined(FIXED_POINT) @@ -1104,11 +1098,13 @@ static void opus_copy_channel_in_short( const void *src, int src_stride, int src_channel, - int frame_size + int frame_size, + void *user_data ) { const opus_int16 *short_src; opus_int32 i; + (void)user_data; short_src = (const opus_int16 *)src; for (i=0;i<frame_size;i++) #if defined(FIXED_POINT) @@ -1129,7 +1125,7 @@ int opus_multistream_encode( ) { return opus_multistream_encode_native(st, opus_copy_channel_in_short, - pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0); + pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0, NULL); } #ifndef DISABLE_FLOAT_API @@ -1142,7 +1138,7 @@ int opus_multistream_encode_float( ) { return opus_multistream_encode_native(st, opus_copy_channel_in_float, - pcm, frame_size, data, max_data_bytes, 16, downmix_float, 1); + pcm, frame_size, data, max_data_bytes, 16, downmix_float, 1, NULL); } #endif @@ -1158,7 +1154,7 @@ int opus_multistream_encode_float ) { return opus_multistream_encode_native(st, opus_copy_channel_in_float, - pcm, frame_size, data, max_data_bytes, 24, downmix_float, 1); + pcm, frame_size, data, max_data_bytes, 24, downmix_float, 1, NULL); } int opus_multistream_encode( @@ -1170,7 +1166,7 @@ int opus_multistream_encode( ) { return opus_multistream_encode_native(st, opus_copy_channel_in_short, - pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0); + pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0, NULL); } #endif diff --git a/src/opus_private.h b/src/opus_private.h index acbb0ae8..193ff938 100644 --- a/src/opus_private.h +++ b/src/opus_private.h @@ -88,7 +88,25 @@ int get_left_channel(const ChannelLayout *layout, int stream_id, int prev); int get_right_channel(const ChannelLayout *layout, int stream_id, int prev); int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev); - +typedef void (*opus_copy_channel_in_func)( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size, + void *user_data +); + +typedef void (*opus_copy_channel_out_func)( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size, + void *user_data +); #define MODE_SILK_ONLY 1000 #define MODE_HYBRID 1001 @@ -156,4 +174,30 @@ opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int int pad_frame(unsigned char *data, opus_int32 len, opus_int32 new_len); +int opus_multistream_encode_native +( + struct OpusMSEncoder *st, + opus_copy_channel_in_func copy_channel_in, + const void *pcm, + int analysis_frame_size, + unsigned char *data, + opus_int32 max_data_bytes, + int lsb_depth, + downmix_func downmix, + int float_api, + void *user_data +); + +int opus_multistream_decode_native( + struct OpusMSDecoder *st, + const unsigned char *data, + opus_int32 len, + void *pcm, + opus_copy_channel_out_func copy_channel_out, + int frame_size, + int decode_fec, + int soft_clip, + void *user_data +); + #endif /* OPUS_PRIVATE_H */ diff --git a/src/opus_projection_decoder.c b/src/opus_projection_decoder.c index 0d1ee41f..6cdadbe9 100644 --- a/src/opus_projection_decoder.c +++ b/src/opus_projection_decoder.c @@ -42,18 +42,63 @@ struct OpusProjectionDecoder { - int demixing_matrix_size_in_bytes; + opus_int32 demixing_matrix_size_in_bytes; /* Encoder states go here */ }; +#if !defined(DISABLE_FLOAT_API) +static void 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) +{ + float *float_dst; + const MappingMatrix *matrix; + float_dst = (float *)dst; + matrix = (const MappingMatrix *)user_data; + + if (dst_channel == 0) + OPUS_CLEAR(float_dst, frame_size * dst_stride); + + if (src != NULL) + mapping_matrix_multiply_channel_out_float(matrix, src, dst_channel, + src_stride, float_dst, dst_stride, frame_size); +} +#endif + +static void 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) +{ + opus_int16 *short_dst; + const MappingMatrix *matrix; + short_dst = (opus_int16 *)dst; + matrix = (const MappingMatrix *)user_data; + if (dst_channel == 0) + OPUS_CLEAR(short_dst, frame_size * dst_stride); + + if (src != NULL) + mapping_matrix_multiply_channel_out_short(matrix, src, dst_channel, + src_stride, short_dst, dst_stride, frame_size); +} + static MappingMatrix *get_demixing_matrix(OpusProjectionDecoder *st) { - return (MappingMatrix *)((char*)st + align(sizeof(OpusProjectionDecoder))); + return (MappingMatrix*)((char*)st + align(sizeof(OpusProjectionDecoder))); } static OpusMSDecoder *get_multistream_decoder(OpusProjectionDecoder *st) { - return (OpusMSDecoder *)((char*)st + align(sizeof(OpusProjectionDecoder) + + return (OpusMSDecoder*)((char*)st + align(sizeof(OpusProjectionDecoder) + st->demixing_matrix_size_in_bytes)); } @@ -69,7 +114,7 @@ opus_int32 opus_projection_decoder_get_size(int channels, int streams, if (!decoder_size) return 0; - return align(sizeof(OpusProjectionDecoder) + matrix_size + decoder_size); + return align(sizeof(OpusProjectionDecoder)) + matrix_size + decoder_size; } int opus_projection_decoder_init(OpusProjectionDecoder *st, opus_int32 Fs, @@ -86,14 +131,14 @@ int opus_projection_decoder_init(OpusProjectionDecoder *st, opus_int32 Fs, /* Verify supplied matrix size. */ nb_input_streams = streams + coupled_streams; expected_matrix_size = nb_input_streams * channels * sizeof(opus_int16); - if (expected_matrix_size != demixing_matrix_size) + if (align(expected_matrix_size) != align(demixing_matrix_size)) { RESTORE_STACK; return OPUS_BAD_ARG; } /* Convert demixing matrix input into internal format. */ - ALLOC(buf, demixing_matrix_size, opus_int16); + ALLOC(buf, nb_input_streams * channels, opus_int16); for (i = 0; i < nb_input_streams * channels; i++) { int s = demixing_matrix[2*i + 1] << 8 | demixing_matrix[2*i]; @@ -102,15 +147,13 @@ int opus_projection_decoder_init(OpusProjectionDecoder *st, opus_int32 Fs, } /* Assign demixing matrix. */ - st->demixing_matrix_size_in_bytes = expected_matrix_size; + st->demixing_matrix_size_in_bytes = mapping_matrix_get_size(channels, nb_input_streams); mapping_matrix_init(get_demixing_matrix(st), channels, nb_input_streams, 0, buf, demixing_matrix_size); /* Set trivial mapping so each input channel pairs with a matrix column. */ for (i = 0; i < channels; i++) - { mapping[i] = i; - } ret = opus_multistream_decoder_init( get_multistream_decoder(st), Fs, channels, streams, coupled_streams, mapping); @@ -154,63 +197,33 @@ OpusProjectionDecoder *opus_projection_decoder_create( return st; } +#ifdef FIXED_POINT int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data, opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec) { -#ifdef NONTHREADSAFE_PSEUDOSTACK - celt_fatal("Unable to use opus_projection_decode() when NONTHREADSAFE_PSEUDOSTACK is defined."); -#endif - MappingMatrix *matrix; - OpusMSDecoder *ms_decoder; - int ret; - VARDECL(opus_int16, buf); - ALLOC_STACK; - - ms_decoder = get_multistream_decoder(st); - ALLOC(buf, (ms_decoder->layout.nb_streams + ms_decoder->layout.nb_coupled_streams) * - frame_size, opus_int16); - ret = opus_multistream_decode(ms_decoder, data, len, buf, frame_size, - decode_fec); - if (ret <= 0) - return ret; - frame_size = ret; - matrix = get_demixing_matrix(st); - mapping_matrix_multiply_short(matrix, buf, - ms_decoder->layout.nb_streams + ms_decoder->layout.nb_coupled_streams, - pcm, ms_decoder->layout.nb_channels, frame_size); - RESTORE_STACK; - return frame_size; + return opus_multistream_decode_native(get_multistream_decoder(st), data, len, + pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, 0, + get_demixing_matrix(st)); +} +#else +int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data, + opus_int32 len, opus_int16 *pcm, int frame_size, + int decode_fec) +{ + return opus_multistream_decode_native(get_multistream_decoder(st), data, len, + pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, 1, + get_demixing_matrix(st)); } +#endif #ifndef DISABLE_FLOAT_API int opus_projection_decode_float(OpusProjectionDecoder *st, const unsigned char *data, - opus_int32 len, float *pcm, - int frame_size, int decode_fec) + opus_int32 len, float *pcm, int frame_size, int decode_fec) { -#ifdef NONTHREADSAFE_PSEUDOSTACK - celt_fatal("Unable to use opus_projection_decode_float() when NONTHREADSAFE_PSEUDOSTACK is defined."); -#endif - MappingMatrix *matrix; - OpusMSDecoder *ms_decoder; - int ret; - VARDECL(float, buf); - ALLOC_STACK; - - ms_decoder = get_multistream_decoder(st); - ALLOC(buf, (ms_decoder->layout.nb_streams + ms_decoder->layout.nb_coupled_streams) * - frame_size, float); - ret = opus_multistream_decode_float(ms_decoder, data, len, buf, - frame_size, decode_fec); - if (ret <= 0) - return ret; - frame_size = ret; - matrix = get_demixing_matrix(st); - mapping_matrix_multiply_float(matrix, buf, - ms_decoder->layout.nb_streams + ms_decoder->layout.nb_coupled_streams, - pcm, ms_decoder->layout.nb_channels, frame_size); - RESTORE_STACK; - return frame_size; + return opus_multistream_decode_native(get_multistream_decoder(st), data, len, + pcm, opus_projection_copy_channel_out_float, frame_size, decode_fec, 0, + get_demixing_matrix(st)); } #endif diff --git a/src/opus_projection_encoder.c b/src/opus_projection_encoder.c index a2c2f353..3cf516ab 100644 --- a/src/opus_projection_encoder.c +++ b/src/opus_projection_encoder.c @@ -42,11 +42,41 @@ struct OpusProjectionEncoder { - int mixing_matrix_size_in_bytes; - int demixing_matrix_size_in_bytes; + opus_int32 mixing_matrix_size_in_bytes; + opus_int32 demixing_matrix_size_in_bytes; /* Encoder states go here */ }; +#if !defined(DISABLE_FLOAT_API) +static void 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 +) +{ + mapping_matrix_multiply_channel_in_float((const MappingMatrix*)user_data, + (const float*)src, src_stride, dst, src_channel, dst_stride, frame_size); +} +#endif + +static void 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 +) +{ + mapping_matrix_multiply_channel_in_short((const MappingMatrix*)user_data, + (const opus_int16*)src, src_stride, dst, src_channel, dst_stride, frame_size); +} + static int get_order_plus_one_from_channels(int channels, int *order_plus_one) { int order_plus_one_; @@ -115,10 +145,8 @@ opus_int32 opus_projection_ambisonics_encoder_get_size(int channels, ret = get_streams_from_channels(channels, mapping_family, &nb_streams, &nb_coupled_streams, &order_plus_one); - if (ret != OPUS_OK) - { + if (ret != OPUS_OK || order_plus_one < 2 || order_plus_one > 4) return 0; - } matrix_rows = order_plus_one * order_plus_one + 2; matrix_size = mapping_matrix_get_size(matrix_rows, matrix_rows); @@ -126,7 +154,7 @@ opus_int32 opus_projection_ambisonics_encoder_get_size(int channels, opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams); if (!encoder_size) return 0; - return align(sizeof(OpusProjectionEncoder) + matrix_size + matrix_size + encoder_size); + return align(sizeof(OpusProjectionEncoder)) + matrix_size + matrix_size + encoder_size; } int opus_projection_ambisonics_encoder_init(OpusProjectionEncoder *st, opus_int32 Fs, @@ -218,9 +246,7 @@ int opus_projection_ambisonics_encoder_init(OpusProjectionEncoder *st, opus_int3 /* Set trivial mapping so each input channel pairs with a matrix column. */ for (i = 0; i < channels; i++) - { mapping[i] = i; - } /* Initialize multistream encoder with provided settings. */ ms_encoder = get_multistream_encoder(st); @@ -269,54 +295,31 @@ int opus_projection_encode(OpusProjectionEncoder *st, const opus_int16 *pcm, int frame_size, unsigned char *data, opus_int32 max_data_bytes) { -#ifdef NONTHREADSAFE_PSEUDOSTACK - celt_fatal("Unable to use opus_projection_encode() when NONTHREADSAFE_PSEUDOSTACK is defined."); -#endif - MappingMatrix *matrix; - OpusMSEncoder *ms_encoder; - int ret; - VARDECL(opus_int16, buf); - ALLOC_STACK; - - matrix = get_mixing_matrix(st); - ms_encoder = get_multistream_encoder(st); - ALLOC(buf, (ms_encoder->layout.nb_streams + ms_encoder->layout.nb_coupled_streams) * - frame_size, opus_int16); - mapping_matrix_multiply_short(matrix, pcm, - ms_encoder->layout.nb_channels, buf, - ms_encoder->layout.nb_streams + ms_encoder->layout.nb_coupled_streams, - frame_size); - ret = opus_multistream_encode(ms_encoder, buf, frame_size, data, max_data_bytes); - RESTORE_STACK; - return ret; + return opus_multistream_encode_native(get_multistream_encoder(st), + opus_projection_copy_channel_in_short, pcm, frame_size, data, + max_data_bytes, 16, downmix_int, 0, get_mixing_matrix(st)); } #ifndef DISABLE_FLOAT_API +#ifdef FIXED_POINT int opus_projection_encode_float(OpusProjectionEncoder *st, const float *pcm, int frame_size, unsigned char *data, opus_int32 max_data_bytes) { -#ifdef NONTHREADSAFE_PSEUDOSTACK - celt_fatal("Unable to use opus_projection_encode_float() when NONTHREADSAFE_PSEUDOSTACK is defined."); -#endif - MappingMatrix *matrix; - OpusMSEncoder *ms_encoder; - int ret; - VARDECL(float, buf); - ALLOC_STACK; - - matrix = get_mixing_matrix(st); - ms_encoder = get_multistream_encoder(st); - ALLOC(buf, (ms_encoder->layout.nb_streams + ms_encoder->layout.nb_coupled_streams) * - frame_size, float); - mapping_matrix_multiply_float(matrix, pcm, - ms_encoder->layout.nb_channels, buf, - ms_encoder->layout.nb_streams + ms_encoder->layout.nb_coupled_streams, - frame_size); - ret = opus_multistream_encode_float(ms_encoder, buf, frame_size, data, max_data_bytes); - RESTORE_STACK; - return ret; + return opus_multistream_encode_native(get_multistream_encoder(st), + opus_projection_copy_channel_in_float, pcm, frame_size, data, + max_data_bytes, 16, downmix_float, 1, get_mixing_matrix(st)); } +#else +int opus_projection_encode_float(OpusProjectionEncoder *st, const float *pcm, + int frame_size, unsigned char *data, + opus_int32 max_data_bytes) +{ + return opus_multistream_encode_native(get_multistream_encoder(st), + opus_projection_copy_channel_in_float, pcm, frame_size, data, + max_data_bytes, 24, downmix_float, 1, get_mixing_matrix(st)); +} +#endif #endif void opus_projection_encoder_destroy(OpusProjectionEncoder *st) diff --git a/tests/test_opus_projection.c b/tests/test_opus_projection.c index 4b11c129..01dc42d6 100644 --- a/tests/test_opus_projection.c +++ b/tests/test_opus_projection.c @@ -47,170 +47,141 @@ #define BUFFER_SIZE 960 #define MAX_DATA_BYTES 32768 #define MAX_FRAME_SAMPLES 5760 +#define ERROR_TOLERANCE 1 -#define INT16_TO_FLOAT(x) ((1/32768.f)*(float)x) +#define SIMPLE_MATRIX_SIZE 12 +#define SIMPLE_MATRIX_FRAME_SIZE 10 +#define SIMPLE_MATRIX_INPUT_SIZE 30 +#define SIMPLE_MATRIX_OUTPUT_SIZE 40 -void print_matrix_short(const opus_int16 *data, int rows, int cols) -{ - int i, j; - for (i = 0; i < rows; i++) - { - for (j = 0; j < cols; j++) - { - fprintf(stderr, "%8.5f ", (float)INT16_TO_FLOAT(data[j * rows + i])); - } - fprintf(stderr, "\n"); - } - fprintf(stderr, "\n"); -} - -void print_matrix_float(const float *data, int rows, int cols) -{ - int i, j; - for (i = 0; i < rows; i++) - { - for (j = 0; j < cols; j++) - { - fprintf(stderr, "%8.5f ", data[j * rows + i]); - } - fprintf(stderr, "\n"); - } - fprintf(stderr, "\n"); -} - -void print_matrix(MappingMatrix *matrix) -{ - opus_int16 *data; - - fprintf(stderr, "%d x %d, gain: %d\n", matrix->rows, matrix->cols, - matrix->gain); - - data = mapping_matrix_get_data(matrix); - print_matrix_short(data, matrix->rows, matrix->cols); -} - -int assert_transform_short( - const opus_int16 *a, const opus_int16 *b, int size, opus_int16 tolerance) +int assert_is_equal( + const opus_val16 *a, const opus_int16 *b, int size, opus_int16 tolerance) { int i; for (i = 0; i < size; i++) { - if (abs(a[i] - b[i]) > tolerance) - { - return 0; - } +#ifdef FIXED_POINT + opus_int16 val = a[i]; +#else + opus_int16 val = FLOAT2INT16(a[i]); +#endif + if (abs(val - b[i]) > tolerance) + return 1; } - return 1; + return 0; } -int assert_transform_float( - const float *a, const float *b, int size, float tolerance) +int assert_is_equal_short( + const opus_int16 *a, const opus_int16 *b, int size, opus_int16 tolerance) { int i; for (i = 0; i < size; i++) - { - if (fabsf(a[i] - b[i]) > tolerance) - { - return 0; - } - } - return 1; + if (abs(a[i] - b[i]) > tolerance) + return 1; + return 0; } -void test_matrix_transform(void) +void test_simple_matrix(void) { - /* Create testing mixing matrix (4 x 3), gain 0dB: - * [ 0 1 0 ] - * [ 1 0 0 ] - * [ 0 0 0 ] - * [ 0 0 1 ] - */ - opus_int32 matrix_size; - MappingMatrix *testing_matrix; - const opus_int16 testing_matrix_data[12] = { - 0, 32767, 0, 0, 32767, 0, 0, 0, 0, 0, 0, 32767 }; - - const int frame_size = 10; - const opus_int16 input[30] = { + const MappingMatrix simple_matrix_params = {4, 3, 0}; + const opus_int16 simple_matrix_data[SIMPLE_MATRIX_SIZE] = {0, 32767, 0, 0, 32767, 0, 0, 0, 0, 0, 0, 32767}; + const opus_int16 input_int16[SIMPLE_MATRIX_INPUT_SIZE] = { 32767, 0, -32768, 29491, -3277, -29491, 26214, -6554, -26214, 22938, -9830, -22938, 19661, -13107, -19661, 16384, -16384, -16384, 13107, -19661, -13107, 9830, -22938, -9830, 6554, -26214, -6554, 3277, -29491, -3277}; - const opus_int16 expected_output[40] = { + const opus_int16 expected_output_int16[SIMPLE_MATRIX_OUTPUT_SIZE] = { 0, 32767, 0, -32768, -3277, 29491, 0, -29491, -6554, 26214, 0, -26214, -9830, 22938, 0, -22938, -13107, 19661, 0, -19661, -16384, 16384, 0, -16384, -19661, 13107, 0, -13107, -22938, 9830, 0, -9830, -26214, 6554, 0, -6554, -29491, 3277, 0, -3277}; - opus_int16 output[40] = {0}; -#ifndef DISABLE_FLOAT_API - int i; - /* Sample-accurate to -93.9794 dB */ - float flt_tolerance = 2e-5f; - float input32[30] = {0}; - float output32[40] = {0}; - float expected_output32[40] = {0}; - - /* Convert short to float representations. */ - for (i = 0; i < 30; i++) + int i, ret; + opus_val16 *input_val16; + opus_val16 *output_val16; + opus_int16 *output_int16; + MappingMatrix *simple_matrix; + + /* Allocate input/output buffers. */ + input_val16 = (opus_val16 *)opus_alloc(align(sizeof(opus_val16) * SIMPLE_MATRIX_INPUT_SIZE)); + output_int16 = (opus_int16 *)opus_alloc(align(sizeof(opus_int16) * SIMPLE_MATRIX_OUTPUT_SIZE)); + output_val16 = (opus_val16 *)opus_alloc(align(sizeof(opus_val16) * SIMPLE_MATRIX_OUTPUT_SIZE)); + + /* Initialize matrix */ + simple_matrix = (MappingMatrix *)opus_alloc( + mapping_matrix_get_size(simple_matrix_params.rows, + simple_matrix_params.cols)); + mapping_matrix_init(simple_matrix, simple_matrix_params.rows, + simple_matrix_params.cols, simple_matrix_params.gain, simple_matrix_data, + sizeof(simple_matrix_data)); + + /* Copy inputs. */ + for (i = 0; i < SIMPLE_MATRIX_INPUT_SIZE; i++) { - input32[i] = INT16_TO_FLOAT(input[i]); +#ifdef FIXED_POINT + input_val16[i] = input_int16[i]; +#else + input_val16[i] = (1/32768.f)*input_int16[i]; +#endif } - for (i = 0; i < 40; i++) + + /* _in_short */ + for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++) + output_val16[i] = 0; + for (i = 0; i < simple_matrix->rows; i++) { - expected_output32[i] = INT16_TO_FLOAT(expected_output[i]); + mapping_matrix_multiply_channel_in_short(simple_matrix, + input_int16, simple_matrix->cols, &output_val16[i], i, + simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE); } -#endif /* DISABLE_FLOAT_API */ - - /* Create the matrix. */ - matrix_size = mapping_matrix_get_size(4, 3); - testing_matrix = (MappingMatrix *)opus_alloc(matrix_size); - mapping_matrix_init(testing_matrix, 4, 3, 0, testing_matrix_data, - 12 * sizeof(opus_int16)); + ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE); + if (ret) + test_failed(); - mapping_matrix_multiply_short(testing_matrix, input, testing_matrix->cols, - output, testing_matrix->rows, frame_size); - if (!assert_transform_short(output, expected_output, 40, 1)) + /* _out_short */ + for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++) + output_int16[i] = 0; + for (i = 0; i < simple_matrix->cols; i++) { - fprintf(stderr, "Matrix:\n"); - print_matrix(testing_matrix); - - fprintf(stderr, "Input (short):\n"); - print_matrix_short(input, testing_matrix->cols, frame_size); - - fprintf(stderr, "Expected Output (short):\n"); - print_matrix_short(expected_output, testing_matrix->rows, frame_size); - - fprintf(stderr, "Output (short):\n"); - print_matrix_short(output, testing_matrix->rows, frame_size); - - goto bad_cleanup; + mapping_matrix_multiply_channel_out_short(simple_matrix, + &input_val16[i], i, simple_matrix->cols, output_int16, + simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE); } + ret = assert_is_equal_short(output_int16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE); + if (ret) + test_failed(); -#ifndef DISABLE_FLOAT_API - mapping_matrix_multiply_float(testing_matrix, input32, testing_matrix->cols, - output32, testing_matrix->rows, frame_size); - if (!assert_transform_float(output32, expected_output32, 40, flt_tolerance)) +#if !defined(DISABLE_FLOAT_API) && !defined(FIXED_POINT) + /* _in_float */ + for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++) + output_val16[i] = 0; + for (i = 0; i < simple_matrix->rows; i++) { - fprintf(stderr, "Matrix:\n"); - print_matrix(testing_matrix); - - fprintf(stderr, "Input (float):\n"); - print_matrix_float(input32, testing_matrix->cols, frame_size); - - fprintf(stderr, "Expected Output (float):\n"); - print_matrix_float(expected_output32, testing_matrix->rows, frame_size); - - fprintf(stderr, "Output (float):\n"); - print_matrix_float(output32, testing_matrix->rows, frame_size); + mapping_matrix_multiply_channel_in_float(simple_matrix, + input_val16, simple_matrix->cols, &output_val16[i], i, + simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE); + } + ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE); + if (ret) + test_failed(); - goto bad_cleanup; + /* _out_float */ + for (i = 0; i < SIMPLE_MATRIX_OUTPUT_SIZE; i++) + output_val16[i] = 0; + for (i = 0; i < simple_matrix->cols; i++) + { + mapping_matrix_multiply_channel_out_float(simple_matrix, + &input_val16[i], i, simple_matrix->cols, output_val16, + simple_matrix->rows, SIMPLE_MATRIX_FRAME_SIZE); } + ret = assert_is_equal(output_val16, expected_output_int16, SIMPLE_MATRIX_OUTPUT_SIZE, ERROR_TOLERANCE); + if (ret) + test_failed(); #endif - opus_free(testing_matrix); - return; -bad_cleanup: - opus_free(testing_matrix); - test_failed(); + + opus_free(input_val16); + opus_free(output_int16); + opus_free(output_val16); + opus_free(simple_matrix); } void test_creation_arguments(const int channels, const int mapping_family) @@ -403,15 +374,15 @@ int main(int _argc, char **_argv) (void)_argc; (void)_argv; - /* Test matrix creation/multiplication. */ - test_matrix_transform(); + /* Test simple matrix multiplication routines. */ + test_simple_matrix(); /* Test full range of channels in creation arguments. */ for (i = 0; i < 255; i++) test_creation_arguments(i, 253); /* Test encode/decode pipeline. */ - test_encode_decode(64 * 16, 16, 253); + test_encode_decode(64 * 18, 18, 253); fprintf(stderr, "All projection tests passed.\n"); return 0; |