aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--celt/arch.h1
-rw-r--r--celt/fixed_debug.h35
-rw-r--r--celt/fixed_generic.h3
-rw-r--r--include/opus_defines.h27
-rw-r--r--src/opus_decoder.c36
-rw-r--r--src/opus_multistream.c22
-rw-r--r--tests/test_opus_api.c72
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;