ref: ec11c82250118df2b4fcd3ce12deb781d205f198
parent: efcdeb9bb286882743aeeb8661c088187e315262
author: Jean-Marc Valin <jmvalin@jmvalin.ca>
date: Thu Jan 5 18:39:44 EST 2017
Avoids pre-echo in hybrid mode caused by noise being injected in the first band This could happen when we had more than 32 bits on the first hybrid band with a transient just in the middle of the frame. The band would be split and the first half of the frame could end up with non-zero energy, but not enough bits for a pulse. Because it's the first band, no folding would be possible. This would cause noise to be injected for the entire duration of the first half and that noise should then get folded to higher bands.
--- a/celt/bands.c
+++ b/celt/bands.c
@@ -684,6 +684,7 @@
int arch;
int theta_round;
int disable_inv;
+ int avoid_split_noise;
};
struct split_ctx {
@@ -745,6 +746,20 @@
if (!stereo || ctx->theta_round == 0)
{
itheta = (itheta*(opus_int32)qn+8192)>>14;
+ if (!stereo && ctx->avoid_split_noise && itheta > 0 && itheta < qn)
+ {
+ /* Check if the selected value of theta will cause the bit allocation
+ to inject noise on one side. If so, make sure the energy of that side
+ is zero. */
+ int unquantized = celt_udiv((opus_int32)itheta*16384, qn);
+ imid = bitexact_cos((opus_int16)unquantized);
+ iside = bitexact_cos((opus_int16)(16384-unquantized));
+ delta = FRAC_MUL16((N-1)<<7,bitexact_log2tan(iside,imid));
+ if (delta > *b)
+ itheta = qn;
+ else if (delta < -*b)
+ itheta = 0;
+ }
} else {
int down;
/* Bias quantization towards itheta=0 and itheta=16384. */
@@ -1452,6 +1467,8 @@
ctx.disable_inv = disable_inv;
ctx.resynth = resynth;
ctx.theta_round = 0;
+ /* Avoid injecting noise in the first band on transients. */
+ ctx.avoid_split_noise = B > 1;
for (i=start;i<end;i++)
{
opus_int32 tell;
@@ -1640,6 +1657,9 @@
/* Update the folding position only as long as we have 1 bit/sample depth. */
update_lowband = b>(N<<BITRES);
+ /* We only need to avoid noise on a split for the first band. After that, we
+ have folding. */
+ ctx.avoid_split_noise = 0;
}
*seed = ctx.seed;