Make it possible to ignore inverted phase stereo for downmix purposes
diff --git a/celt/bands.c b/celt/bands.c
index bfbe263..fc80177 100644
--- a/celt/bands.c
+++ b/celt/bands.c
@@ -657,6 +657,7 @@
const celt_ener *bandE;
opus_uint32 seed;
int arch;
+ int disable_inv;
};
struct split_ctx {
@@ -793,7 +794,7 @@
} else if (stereo) {
if (encode)
{
- inv = itheta > 8192;
+ inv = itheta > 8192 && !ctx->disable_inv;
if (inv)
{
int j;
@@ -810,6 +811,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;
@@ -1365,7 +1369,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 arch)
+ opus_uint32 *seed, int arch, int disable_inv)
{
int i;
opus_int32 remaining_bits;
@@ -1408,6 +1412,7 @@
ctx.seed = *seed;
ctx.spread = spread;
ctx.arch = arch;
+ ctx.disable_inv = disable_inv;
for (i=start;i<end;i++)
{
opus_int32 tell;
diff --git a/celt/bands.h b/celt/bands.h
index e8bef4b..10d5abe 100644
--- 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 arch);
+ 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,
diff --git a/celt/celt_decoder.c b/celt/celt_decoder.c
index b978bb3..1cea482 100644
--- 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,7 @@
st->start = 0;
st->end = st->mode->effEBands;
st->signalling = 1;
+ st->disable_inv = channels == 1;
st->arch = opus_select_arch();
opus_custom_decoder_ctl(st, OPUS_RESET_STATE);
@@ -979,7 +981,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, st->arch);
+ len*(8<<BITRES)-anti_collapse_rsv, balance, dec, LM, codedBands, &st->rng,
+ st->arch, st->disable_inv);
if (anti_collapse_rsv > 0)
{
@@ -1234,6 +1237,26 @@
*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:
goto bad_request;
}
diff --git a/celt/celt_encoder.c b/celt/celt_encoder.c
index 1520a6c..d89de31 100644
--- 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 */
@@ -179,7 +180,7 @@
st->start = 0;
st->end = st->mode->effEBands;
st->signalling = 1;
-
+ st->disable_inv = channels == 1;
st->arch = arch;
st->constrained_vbr = 1;
@@ -2063,7 +2064,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->arch);
+ balance, enc, LM, codedBands, &st->rng, st->arch, st->disable_inv);
if (anti_collapse_rsv > 0)
{
@@ -2352,6 +2353,26 @@
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:
{
int i;
diff --git a/include/opus_defines.h b/include/opus_defines.h
index 315412d..b0796d1 100644
--- 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))
@@ -681,6 +682,26 @@
*/
#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.
+ * @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)
+
/**@}*/
/** @defgroup opus_decoderctls Decoder related CTLs
diff --git a/src/opus_decoder.c b/src/opus_decoder.c
index 080bec5..af46d82 100644
--- 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;
diff --git a/src/opus_encoder.c b/src/opus_encoder.c
index 227c715..6509c91 100644
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -2728,6 +2728,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;
diff --git a/tests/run_vectors.sh b/tests/run_vectors.sh
index 1d447c4..f0c52b3 100755
--- 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 logs_mono.txt logs_mono2.txt
+rm 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}s.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}s.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, "%"}'