ref: 18a380a7c209b482f63adeb19f5d398dcb1c10bd
parent: 6db0908db3378c79c554a863bb4033465be7bc4a
author: Jean-Marc Valin <jmvalin@jmvalin.ca>
date: Wed Apr 20 09:27:06 EDT 2016
Make it possible to ignore inverted phase stereo for downmix purposes
--- a/celt/bands.c
+++ b/celt/bands.c
@@ -683,6 +683,7 @@
opus_uint32 seed;
int arch;
int theta_round;
+ int disable_inv;
};
struct split_ctx {
@@ -832,7 +833,7 @@
} else if (stereo) {
if (encode)
{
- inv = itheta > 8192;
+ inv = itheta > 8192 && !ctx->disable_inv;
if (inv)
{
int j;
@@ -849,6 +850,9 @@
inv = ec_dec_bit_logp(ec, 2);
} else
inv = 0;
+ /* inv flag override to avoid problems with downmixing. */
+ if (ctx->disable_inv)
+ inv = 0;
itheta = 0;
}
qalloc = ec_tell_frac(ec) - tell;
@@ -1379,7 +1383,7 @@
const celt_ener *bandE, int *pulses, int shortBlocks, int spread,
int dual_stereo, int intensity, int *tf_res, opus_int32 total_bits,
opus_int32 balance, ec_ctx *ec, int LM, int codedBands,
- opus_uint32 *seed, int complexity, int arch)
+ opus_uint32 *seed, int complexity, int arch, int disable_inv)
{
int i;
opus_int32 remaining_bits;
@@ -1445,6 +1449,7 @@
ctx.seed = *seed;
ctx.spread = spread;
ctx.arch = arch;
+ ctx.disable_inv = disable_inv;
ctx.resynth = resynth;
ctx.theta_round = 0;
for (i=start;i<end;i++)
--- a/celt/bands.h
+++ b/celt/bands.h
@@ -105,7 +105,7 @@
const celt_ener *bandE, int *pulses, int shortBlocks, int spread,
int dual_stereo, int intensity, int *tf_res, opus_int32 total_bits,
opus_int32 balance, ec_ctx *ec, int M, int codedBands, opus_uint32 *seed,
- int complexity, int arch);
+ int complexity, int arch, int disable_inv);
void anti_collapse(const CELTMode *m, celt_norm *X_,
unsigned char *collapse_masks, int LM, int C, int size, int start,
--- a/celt/celt_decoder.c
+++ b/celt/celt_decoder.c
@@ -73,6 +73,7 @@
int downsample;
int start, end;
int signalling;
+ int disable_inv;
int arch;
/* Everything beyond this point gets cleared on a reset */
@@ -163,6 +164,11 @@
st->start = 0;
st->end = st->mode->effEBands;
st->signalling = 1;
+#ifdef ENABLE_UPDATE_DRAFT
+ st->disable_inv = channels == 1;
+#else
+ st->disable_inv = 0;
+#endif
st->arch = opus_select_arch();
opus_custom_decoder_ctl(st, OPUS_RESET_STATE);
@@ -1043,7 +1049,8 @@
quant_all_bands(0, mode, start, end, X, C==2 ? X+N : NULL, collapse_masks,
NULL, pulses, shortBlocks, spread_decision, dual_stereo, intensity, tf_res,
- len*(8<<BITRES)-anti_collapse_rsv, balance, dec, LM, codedBands, &st->rng, 0, st->arch);
+ len*(8<<BITRES)-anti_collapse_rsv, balance, dec, LM, codedBands, &st->rng, 0,
+ st->arch, st->disable_inv);
if (anti_collapse_rsv > 0)
{
@@ -1296,6 +1303,26 @@
if (value==0)
goto bad_arg;
*value=st->rng;
+ }
+ break;
+ case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->disable_inv = value;
+ }
+ break;
+ case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->disable_inv;
}
break;
default:
--- a/celt/celt_encoder.c
+++ b/celt/celt_encoder.c
@@ -75,6 +75,7 @@
int lsb_depth;
int variable_duration;
int lfe;
+ int disable_inv;
int arch;
/* Everything beyond this point gets cleared on a reset */
@@ -181,7 +182,6 @@
st->start = 0;
st->end = st->mode->effEBands;
st->signalling = 1;
-
st->arch = arch;
st->constrained_vbr = 1;
@@ -2079,7 +2079,7 @@
quant_all_bands(1, mode, start, end, X, C==2 ? X+N : NULL, collapse_masks,
bandE, pulses, shortBlocks, st->spread_decision,
dual_stereo, st->intensity, tf_res, nbCompressedBytes*(8<<BITRES)-anti_collapse_rsv,
- balance, enc, LM, codedBands, &st->rng, st->complexity, st->arch);
+ balance, enc, LM, codedBands, &st->rng, st->complexity, st->arch, st->disable_inv);
if (anti_collapse_rsv > 0)
{
@@ -2374,6 +2374,26 @@
{
opus_int32 value = va_arg(ap, opus_int32);
st->variable_duration = value;
+ }
+ break;
+ case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->disable_inv = value;
+ }
+ break;
+ case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->disable_inv;
}
break;
case OPUS_RESET_STATE:
--- a/include/opus_defines.h
+++ b/include/opus_defines.h
@@ -165,8 +165,9 @@
#define OPUS_GET_EXPERT_FRAME_DURATION_REQUEST 4041
#define OPUS_SET_PREDICTION_DISABLED_REQUEST 4042
#define OPUS_GET_PREDICTION_DISABLED_REQUEST 4043
-
/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */
+#define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046
+#define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047
/* 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))
@@ -680,6 +681,29 @@
* @hideinitializer
*/
#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x)
+
+/** If set to 1, disables the use of phase inversion for intensity stereo, improving the
+ * quality of mono downmixes, but slightly reducing normal stereo quality. Disabling phase
+ * inversion does not comply with RFC6716, even though it does not cause any
+ * interoperability issue. It will become part of the Opus standard once RFC6716 gets
+ * updated with draft-ietf-codec-opus-update.
+ * @see OPUS_GET_PHASE_INVERSION_DISABLED
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>0</dt><dd>Enable phase inversion (default).</dd>
+ * <dt>1</dt><dd>Disable phase inversion.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_PHASE_INVERSION_DISABLED(x) OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured phase inversion status.
+ * @see OPUS_SET_PHASE_INVERSION_DISABLED
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>0</dt><dd>Stereo phase inversion enabled (default).</dd>
+ * <dt>1</dt><dd>Stereo phase inversion disabled.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_PHASE_INVERSION_DISABLED(x) OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int_ptr(x)
/**@}*/
--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -899,6 +899,26 @@
*value = st->last_packet_duration;
}
break;
+ case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ celt_decoder_ctl(celt_dec, OPUS_SET_PHASE_INVERSION_DISABLED(value));
+ }
+ break;
+ case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ celt_decoder_ctl(celt_dec, OPUS_GET_PHASE_INVERSION_DISABLED(value));
+ }
+ break;
default:
/*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/
ret = OPUS_UNIMPLEMENTED;
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -2781,6 +2781,26 @@
*value = st->silk_mode.reducedDependency;
}
break;
+ case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ celt_encoder_ctl(celt_enc, OPUS_SET_PHASE_INVERSION_DISABLED(value));
+ }
+ break;
+ case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ celt_encoder_ctl(celt_enc, OPUS_GET_PHASE_INVERSION_DISABLED(value));
+ }
+ break;
case OPUS_RESET_STATE:
{
void *silk_enc;
--- a/tests/run_vectors.sh
+++ b/tests/run_vectors.sh
@@ -33,8 +33,8 @@
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-rm logs_mono.txt
-rm logs_stereo.txt
+rm -f logs_mono.txt logs_mono2.txt
+rm -f logs_stereo.txt logs_stereo2.txt
if [ "$#" -ne "3" ]; then
echo "usage: run_vectors.sh <exec path> <vector path> <rate>"
@@ -87,9 +87,11 @@
echo ERROR: decoding failed
exit 1
fi
- $OPUS_COMPARE -r $RATE $VECTOR_PATH/testvector$file.dec tmp.out >> logs_mono.txt 2>&1
+ $OPUS_COMPARE -r $RATE $VECTOR_PATH/testvector${file}.dec tmp.out >> logs_mono.txt 2>&1
float_ret=$?
- if [ "$float_ret" -eq "0" ]; then
+ $OPUS_COMPARE -r $RATE $VECTOR_PATH/testvector${file}m.dec tmp.out >> logs_mono2.txt 2>&1
+ float_ret2=$?
+ if [ "$float_ret" -eq "0" ] || [ "$float_ret2" -eq "0" ]; then
echo output matches reference
else
echo ERROR: output does not match reference
@@ -116,9 +118,11 @@
echo ERROR: decoding failed
exit 1
fi
- $OPUS_COMPARE -s -r $RATE $VECTOR_PATH/testvector$file.dec tmp.out >> logs_stereo.txt 2>&1
+ $OPUS_COMPARE -s -r $RATE $VECTOR_PATH/testvector${file}.dec tmp.out >> logs_stereo.txt 2>&1
float_ret=$?
- if [ "$float_ret" -eq "0" ]; then
+ $OPUS_COMPARE -s -r $RATE $VECTOR_PATH/testvector${file}m.dec tmp.out >> logs_stereo2.txt 2>&1
+ float_ret2=$?
+ if [ "$float_ret" -eq "0" ] || [ "$float_ret2" -eq "0" ]; then
echo output matches reference
else
echo ERROR: output does not match reference
@@ -130,5 +134,10 @@
echo All tests have passed successfully
-grep quality logs_mono.txt | awk '{sum+=$4}END{print "Average mono quality is", sum/NR, "%"}'
-grep quality logs_stereo.txt | awk '{sum+=$4}END{print "Average stereo quality is", sum/NR, "%"}'
+mono1=`grep quality logs_mono.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'`
+mono2=`grep quality logs_mono2.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'`
+echo $mono1 $mono2 | awk '{if ($2 > $1) $1 = $2; print "Average mono quality is", $1, "%"}'
+
+stereo1=`grep quality logs_stereo.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'`
+stereo2=`grep quality logs_stereo2.txt | awk '{sum+=$4}END{if (NR == 12) sum /= 12; else sum = 0; print sum}'`
+echo $stereo1 $stereo2 | awk '{if ($2 > $1) $1 = $2; print "Average stereo quality is", $1, "%"}'