diff options
-rw-r--r-- | celt/arch.h | 1 | ||||
-rw-r--r-- | celt/fixed_debug.h | 35 | ||||
-rw-r--r-- | celt/fixed_generic.h | 3 | ||||
-rw-r--r-- | include/opus_defines.h | 27 | ||||
-rw-r--r-- | src/opus_decoder.c | 36 | ||||
-rw-r--r-- | src/opus_multistream.c | 22 | ||||
-rw-r--r-- | tests/test_opus_api.c | 72 |
7 files changed, 189 insertions, 7 deletions
diff --git a/celt/arch.h b/celt/arch.h index a7cfbe89..03cda40f 100644 --- a/celt/arch.h +++ b/celt/arch.h @@ -188,6 +188,7 @@ typedef float celt_ener; #define MULT16_16_P15(a,b) ((a)*(b)) #define MULT16_16_P13(a,b) ((a)*(b)) #define MULT16_16_P14(a,b) ((a)*(b)) +#define MULT16_32_P16(a,b) ((a)*(b)) #define DIV32_16(a,b) (((opus_val32)(a))/(opus_val16)(b)) #define DIV32(a,b) (((opus_val32)(a))/(opus_val32)(b)) diff --git a/celt/fixed_debug.h b/celt/fixed_debug.h index 89b3cf72..ed95cba3 100644 --- a/celt/fixed_debug.h +++ b/celt/fixed_debug.h @@ -47,6 +47,8 @@ extern long long celt_mips; /** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ #define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR32((b),16)), SHR32(MULT16_16SU((a),((b)&0x0000ffff)),16)) +#define MULT16_32_P16(a,b) MULT16_32_PX(a,b,16) + #define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits)))) #define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits)))) @@ -459,6 +461,39 @@ static inline int MULT16_32_QX_(int a, long long b, int Q, char *file, int line) return res; } +#define MULT16_32_PX(a, b, Q) MULT16_32_PX_(a, b, Q, __FILE__, __LINE__) +static inline int MULT16_32_PX_(int a, long long b, int Q, char *file, int line) +{ + long long res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d in %s: line %d\n\n", Q, (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (ABS32(b)>=((opus_val32)(1)<<(15+Q))) + { + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n\n", Q, (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((((long long)a)*(long long)b) + (((opus_val32)(1)<<Q)>>1))>> Q; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d in %s: line %d\n\n", Q, (int)a, (int)b,(int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (Q==15) + celt_mips+=4; + else + celt_mips+=5; + return res; +} + #define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15) #define MAC16_32_Q15(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q15((a),(b)))) diff --git a/celt/fixed_generic.h b/celt/fixed_generic.h index d5ea1219..71e28d62 100644 --- a/celt/fixed_generic.h +++ b/celt/fixed_generic.h @@ -39,6 +39,9 @@ /** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ #define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16)) +/** 16x32 multiplication, followed by a 16-bit shift right (round-to-nearest). Results fits in 32 bits */ +#define MULT16_32_P16(a,b) ADD32(MULT16_16((a),SHR((b),16)), PSHR(MULT16_16((a),((b)&0x0000ffff)),16)) + /** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */ #define MULT16_32_Q15(a,b) ADD32(SHL(MULT16_16((a),SHR((b),16)),1), SHR(MULT16_16SU((a),((b)&0x0000ffff)),15)) diff --git a/include/opus_defines.h b/include/opus_defines.h index 54d198be..de04ec5c 100644 --- a/include/opus_defines.h +++ b/include/opus_defines.h @@ -128,6 +128,8 @@ extern "C" { /* #define OPUS_RESET_STATE 4028 */ #define OPUS_GET_FINAL_RANGE_REQUEST 4031 #define OPUS_GET_PITCH_REQUEST 4033 +#define OPUS_SET_GAIN_REQUEST 4034 +#define OPUS_GET_GAIN_REQUEST 4045 /* Macros to trigger compilation errors when the wrong types are provided to a CTL */ #define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x)) @@ -400,7 +402,7 @@ extern "C" { * } * @endcode * - * @see opus_encoder, opus_decoder_ctl, opus_encoder_ctl + * @see opus_encoder, opus_decoder_ctl, opus_encoder_ctl, opus_decoderctls, opus_encoderctls * @{ */ @@ -440,6 +442,29 @@ extern "C" { /**@}*/ +/** @defgroup opus_decoderctls Decoder related CTLs + * @see opus_genericctls, opus_encoderctls, opus_decoder + * @{ + */ + +/** Configures decoder gain adjustment. + * Scales the decoded output by a factor specified in Q8 dB units. + * This has a maximum range of -32768 to 32767 inclusive, and returns + * OPUS_BAD_ARG otherwise. + * + * gain = pow(10, x/(20.0*256)) + * + * @param[in] x <tt>opus_int32</tt>: Amount to scale PCM signal by in Q8 dB units. + * @hideinitializer */ +#define OPUS_SET_GAIN(x) OPUS_SET_GAIN_REQUEST, __opus_check_int(x) +/** Gets the decoder's configured gain adjustment. @see OPUS_SET_GAIN + * + * @param[out] x <tt>opus_int32*</tt>: Amount to scale PCM signal by in Q8 dB units. + * @hideinitializer */ +#define OPUS_GET_GAIN(x) OPUS_GET_GAIN_REQUEST, __opus_check_int_ptr(x) + +/**@}*/ + /** @defgroup opus_libinfo Opus library information functions * @{ */ diff --git a/src/opus_decoder.c b/src/opus_decoder.c index 24869e7f..2ce4c95a 100644 --- a/src/opus_decoder.c +++ b/src/opus_decoder.c @@ -45,6 +45,7 @@ #include "os_support.h" #include "structs.h" #include "define.h" +#include "mathops.h" struct OpusDecoder { int celt_dec_offset; @@ -62,6 +63,7 @@ struct OpusDecoder { int prev_mode; int frame_size; int prev_redundancy; + int decode_gain; opus_uint32 rangeFinal; }; @@ -503,6 +505,18 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, } } + if(st->decode_gain) + { + opus_val32 gain; + gain = celt_exp2(MULT16_16_P15(QCONST16(6.48814081e-4f, 25), st->decode_gain)); + for (i=0;i<frame_size*st->channels;i++) + { + opus_val32 x; + x = MULT16_32_P16(pcm[i],gain); + pcm[i] = SATURATE(x, 32767); + } + } + if (len <= 1) st->rangeFinal = 0; else @@ -856,6 +870,28 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...) *value = st->DecControl.prevPitchLag; } break; + case OPUS_GET_GAIN_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + { + ret = OPUS_BAD_ARG; + break; + } + *value = st->decode_gain; + } + break; + case OPUS_SET_GAIN_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<-32768 || value>32767) + { + ret = OPUS_BAD_ARG; + break; + } + st->decode_gain = value; + } + break; default: /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/ ret = OPUS_UNIMPLEMENTED; diff --git a/src/opus_multistream.c b/src/opus_multistream.c index b593bf32..1128c07e 100644 --- a/src/opus_multistream.c +++ b/src/opus_multistream.c @@ -845,7 +845,27 @@ int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) } *value = (OpusDecoder*)ptr; } - break; + break; + case OPUS_SET_GAIN_REQUEST: + { + int s; + /* This works for int32 params */ + opus_int32 value = va_arg(ap, opus_int32); + for (s=0;s<st->layout.nb_streams;s++) + { + OpusDecoder *dec; + + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, request, value); + if (ret != OPUS_OK) + break; + } + } + break; default: ret = OPUS_UNIMPLEMENTED; break; diff --git a/tests/test_opus_api.c b/tests/test_opus_api.c index 31ca5a5a..641f6eac 100644 --- a/tests/test_opus_api.c +++ b/tests/test_opus_api.c @@ -187,6 +187,31 @@ opus_int32 test_dec_api(void) cfgs++; fprintf(stdout," OPUS_GET_PITCH ............................... OK.\n"); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_GAIN(&i)); + VG_CHECK(&i,sizeof(i)); + if(err != OPUS_OK || i!=0)test_failed(); + cfgs++; + err=opus_decoder_ctl(dec, OPUS_GET_GAIN(nullvalue)); + if(err != OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_decoder_ctl(dec, OPUS_SET_GAIN(-32769)); + if(err != OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_decoder_ctl(dec, OPUS_SET_GAIN(32768)); + if(err != OPUS_BAD_ARG)test_failed(); + cfgs++; + err=opus_decoder_ctl(dec, OPUS_SET_GAIN(-15)); + if(err != OPUS_OK)test_failed(); + cfgs++; + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(dec, OPUS_GET_GAIN(&i)); + VG_CHECK(&i,sizeof(i)); + if(err != OPUS_OK || i!=-15)test_failed(); + cfgs++; + fprintf(stdout," OPUS_SET_GAIN ................................ OK.\n"); + fprintf(stdout," OPUS_GET_GAIN ................................ OK.\n"); + /*Reset the decoder*/ dec2=malloc(opus_decoder_get_size(2)); memcpy(dec2,dec,opus_decoder_get_size(2)); @@ -360,23 +385,23 @@ opus_int32 test_msdec_api(void) cfgs++; VG_UNDEF(&err,sizeof(err)); - mapping[0]=0; - mapping[1]=1; - dec = opus_multistream_decoder_create(48000, 2, 2, 0, mapping, &err); + dec = opus_multistream_decoder_create(48000, 1, 4, 1, mapping, &err); if(err!=OPUS_OK || dec==NULL)test_failed(); cfgs++; opus_multistream_decoder_destroy(dec); cfgs++; VG_UNDEF(&err,sizeof(err)); - dec = opus_multistream_decoder_create(48000, 1, 4, 1, mapping, &err); + dec = opus_multistream_decoder_create(48000, 2, 1, 1, mapping, &err); if(err!=OPUS_OK || dec==NULL)test_failed(); cfgs++; opus_multistream_decoder_destroy(dec); cfgs++; VG_UNDEF(&err,sizeof(err)); - dec = opus_multistream_decoder_create(48000, 2, 1, 1, mapping, &err); + mapping[0]=0; + mapping[1]=1; + dec = opus_multistream_decoder_create(48000, 2, 2, 0, mapping, &err); if(err!=OPUS_OK || dec==NULL)test_failed(); cfgs++; @@ -396,6 +421,9 @@ opus_int32 test_msdec_api(void) if(err!=OPUS_BAD_ARG)test_failed(); cfgs++; err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(1,&streamdec)); + if(err!=OPUS_OK||streamdec==NULL)test_failed(); + cfgs++; + err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(2,&streamdec)); if(err!=OPUS_BAD_ARG)test_failed(); cfgs++; err=opus_multistream_decoder_ctl(dec, OPUS_MULTISTREAM_GET_DECODER_STATE(0,&streamdec)); @@ -404,6 +432,33 @@ opus_int32 test_msdec_api(void) fprintf(stdout," OPUS_MULTISTREAM_GET_DECODER_STATE ........... OK.\n"); cfgs++; + for(j=0;j<2;j++) + { + OpusDecoder *od; + err=opus_multistream_decoder_ctl(dec,OPUS_MULTISTREAM_GET_DECODER_STATE(j,&od)); + if(err != OPUS_OK)test_failed(); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(od, OPUS_GET_GAIN(&i)); + VG_CHECK(&i,sizeof(i)); + if(err != OPUS_OK || i!=0)test_failed(); + cfgs++; + } + err=opus_multistream_decoder_ctl(dec,OPUS_SET_GAIN(15)); + if(err!=OPUS_OK)test_failed(); + fprintf(stdout," OPUS_SET_GAIN ................................ OK.\n"); + for(j=0;j<2;j++) + { + OpusDecoder *od; + err=opus_multistream_decoder_ctl(dec,OPUS_MULTISTREAM_GET_DECODER_STATE(j,&od)); + if(err != OPUS_OK)test_failed(); + VG_UNDEF(&i,sizeof(i)); + err=opus_decoder_ctl(od, OPUS_GET_GAIN(&i)); + VG_CHECK(&i,sizeof(i)); + if(err != OPUS_OK || i!=15)test_failed(); + cfgs++; + } + fprintf(stdout," OPUS_GET_GAIN ................................ OK.\n"); + err=opus_multistream_decoder_ctl(dec,OPUS_UNIMPLEMENTED); if(err!=OPUS_UNIMPLEMENTED)test_failed(); fprintf(stdout," OPUS_UNIMPLEMENTED ........................... OK.\n"); @@ -447,6 +502,13 @@ opus_int32 test_msdec_api(void) fprintf(stdout," OPUS_RESET_STATE ............................. OK.\n"); cfgs++; + opus_multistream_decoder_destroy(dec); + cfgs++; + VG_UNDEF(&err,sizeof(err)); + dec = opus_multistream_decoder_create(48000, 2, 1, 1, mapping, &err); + if(err!=OPUS_OK || dec==NULL)test_failed(); + cfgs++; + packet[0]=(63<<2)+3; packet[1]=49; for(j=2;j<51;j++)packet[j]=0; |