shithub: opus

Download patch

ref: 0cc4d9659aaa35c8a21af0e7a8927bf9132315bf
parent: a1c2d71803b0a4a0ceac644270b9ff23ee81a3f3
author: Jean-Marc Valin <jmvalin@jmvalin.ca>
date: Wed May 31 23:14:13 EDT 2017

Adding leakage modelling to boost bands

We boost bands that either cause leakage or are filled with leakage

--- a/celt/celt.h
+++ b/celt/celt.h
@@ -50,6 +50,8 @@
 #define CELTDecoder OpusCustomDecoder
 #define CELTMode OpusCustomMode
 
+#define LEAK_BANDS 19
+
 typedef struct {
    int valid;
    float tonality;
@@ -60,6 +62,8 @@
    float vad_prob;
    int   bandwidth;
    float activity_probability;
+   /* Store as Q6 char to save space. */
+   unsigned char leak_boost[LEAK_BANDS];
 } AnalysisInfo;
 
 typedef struct {
--- a/celt/celt_encoder.c
+++ b/celt/celt_encoder.c
@@ -964,7 +964,7 @@
 static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16 *bandLogE2,
       int nbEBands, int start, int end, int C, int *offsets, int lsb_depth, const opus_int16 *logN,
       int isTransient, int vbr, int constrained_vbr, const opus_int16 *eBands, int LM,
-      int effectiveBytes, opus_int32 *tot_boost_, int lfe, opus_val16 *surround_dynalloc)
+      int effectiveBytes, opus_int32 *tot_boost_, int lfe, opus_val16 *surround_dynalloc, AnalysisInfo *analysis)
 {
    int i, c;
    opus_int32 tot_boost=0;
@@ -1054,14 +1054,26 @@
       }
       for (i=start;i<end;i++)
       {
-         int width;
-         int boost;
-         int boost_bits;
-
          if (i<8)
             follower[i] *= 2;
          if (i>=12)
             follower[i] = HALF16(follower[i]);
+      }
+#ifdef DISABLE_FLOAT_API
+      (void)analysis;
+#else
+      if (analysis->valid)
+      {
+         for (i=start;i<IMIN(LEAK_BANDS, end);i++)
+            follower[i] = follower[i] +  QCONST16(1.f/64.f, DB_SHIFT)*analysis->leak_boost[i];
+      }
+#endif
+      for (i=start;i<end;i++)
+      {
+         int width;
+         int boost;
+         int boost_bits;
+
          follower[i] = MIN16(follower[i], QCONST16(4, DB_SHIFT));
 
          width = C*(eBands[i+1]-eBands[i])<<LM;
@@ -1893,7 +1905,7 @@
 
    maxDepth = dynalloc_analysis(bandLogE, bandLogE2, nbEBands, start, end, C, offsets,
          st->lsb_depth, mode->logN, isTransient, st->vbr, st->constrained_vbr,
-         eBands, LM, effectiveBytes, &tot_boost, st->lfe, surround_dynalloc);
+         eBands, LM, effectiveBytes, &tot_boost, st->lfe, surround_dynalloc, &st->analysis);
    /* For LFE, everything interesting is in the first band */
    if (st->lfe)
       offsets[0] = IMIN(8, effectiveBytes/3);
--- a/src/analysis.c
+++ b/src/analysis.c
@@ -290,6 +290,9 @@
       2.163313f, 1.260756f, 1.116868f, 1.918795f
 };
 
+#define LEAKAGE_OFFSET 2.5f
+#define LEAKAGE_SLOPE 2.f
+
 #ifdef FIXED_POINT
 /* For fixed-point, the input is +/-2^15 shifted up by SIG_SHIFT, so we need to
    compensate for that in the energy. */
@@ -336,6 +339,9 @@
     float tonality2[240];
     float midE[8];
     float spec_variability=0;
+    float band_log2[NB_TBANDS+1];
+    float leakage_from[NB_TBANDS+1];
+    float leakage_to[NB_TBANDS+1];
     SAVE_STACK;
 
     alpha = 1.f/IMIN(10, 1+tonal->count);
@@ -461,6 +467,22 @@
     }
     relativeE = 0;
     frame_loudness = 0;
+    /* The energy of the very first band is special because of DC. */
+    {
+       float E = 0;
+       float X1r, X2r;
+       X1r = 2*(float)out[0].r;
+       X2r = 2*(float)out[0].i;
+       E = X1r*X1r + X2r*X2r;
+       for (i=1;i<4;i++)
+       {
+          float binE = out[i].r*(float)out[i].r + out[N-i].r*(float)out[N-i].r
+                     + out[i].i*(float)out[i].i + out[N-i].i*(float)out[N-i].i;
+          E += binE;
+       }
+       E = SCALE_ENER(E);
+       band_log2[0] = (float).5*log2(E+1e-10f);
+    }
     for (b=0;b<NB_TBANDS;b++)
     {
        float E=0, tE=0, nE=0;
@@ -490,6 +512,7 @@
 
        frame_loudness += (float)sqrt(E+1e-10f);
        logE[b] = (float)log(E+1e-10f);
+       band_log2[b+1] = (float).5*log2(E+1e-10f);
        tonal->logE[tonal->E_count][b] = logE[b];
        if (tonal->count==0)
           tonal->highE[b] = tonal->lowE[b] = logE[b];
@@ -540,6 +563,35 @@
        /*printf("%f %f ", band_tonality[b], stationarity);*/
        tonal->prev_band_tonality[b] = band_tonality[b];
     }
+
+    leakage_from[0] = band_log2[0];
+    leakage_to[0] = band_log2[0] - LEAKAGE_OFFSET;
+    for (b=1;b<NB_TBANDS+1;b++)
+    {
+       float leak_slope = LEAKAGE_SLOPE*(tbands[b]-tbands[b-1])/4;
+       leakage_from[b] = MIN16(leakage_from[b-1]+leak_slope, band_log2[b]);
+       leakage_to[b] = MAX16(leakage_to[b-1]-leak_slope, band_log2[b]-LEAKAGE_OFFSET);
+    }
+    for (b=NB_TBANDS-2;b>=0;b--)
+    {
+       float leak_slope = LEAKAGE_SLOPE*(tbands[b+1]-tbands[b])/4;
+       leakage_from[b] = MIN16(leakage_from[b+1]+leak_slope, leakage_from[b]);
+       leakage_to[b] = MAX16(leakage_to[b+1]-leak_slope, leakage_to[b]);
+    }
+    celt_assert(NB_TBANDS+1 <= LEAK_BANDS);
+    for (b=0;b<NB_TBANDS+1;b++)
+    {
+       /* leak_boost[] is made up of two terms. The first, based on leakage_high[],
+          represents the boost needed to overcome the amount of analysis leakage
+          cause in a weaker band b by louder neighroubing bands.
+          The second, based on leakage_low[], applies to a loud band b for
+          which the quantization noise causes synthesis leakage to the weaker
+          neighbouring bands. */
+       float boost = MAX16(0, leakage_to[b] - band_log2[b]) +
+             MAX16(0, band_log2[b] - (leakage_from[b]+LEAKAGE_OFFSET));
+       info->leak_boost[b] = IMIN(255, (int)floor(.5 + 64.f*boost));
+    }
+    for (;b<LEAK_BANDS;b++) info->leak_boost[b] = 0;
 
     for (i=0;i<NB_FRAMES;i++)
     {