Add coarse energy entropy model tuning.
authorTimothy B. Terriberry <tterribe@xiph.org>
Tue, 9 Nov 2010 09:43:18 +0000 (01:43 -0800)
committerJean-Marc Valin <jean-marc.valin@usherbrooke.ca>
Tue, 9 Nov 2010 09:54:41 +0000 (17:54 +0800)
This tunes the entropy model for coarse energy introduced in commit
 c1c40a76.
It uses a constant set of parameters, tuned from about an hour and a
 half of randomly selected test data encoded for each frame size,
 prediction type (inter/intra), and band number.
These will be slightly sub-optimal for different frame sizes, but
 should be better than what we were using.

For inter, this saves an average of 2.8, 5.2, 7.1, and 6.7 bits/frame
 for frame sizes of 120, 240, 480, and 960, respectively.
For intra, this saves an average of 1.5, 3.0, 4.5, and 5.3 bits/frame
 (for the same frame sizes, respectively).

libcelt/celt.c
libcelt/dump_modes.c
libcelt/laplace.c
libcelt/laplace.h
libcelt/modes.c
libcelt/modes.h
libcelt/quant_bands.c
libcelt/quant_bands.h
tests/laplace-test.c

index 450bde5..1bda1b3 100644 (file)
@@ -861,8 +861,8 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
 
    ALLOC(error, C*st->mode->nbEBands, celt_word16);
    quant_coarse_energy(st->mode, st->start, st->end, effEnd, bandLogE,
-         oldBandE, nbCompressedBytes*8, st->mode->prob,
-         error, enc, C, LM, nbAvailableBytes, st->force_intra,
+         oldBandE, nbCompressedBytes*8, error, enc,
+         C, LM, nbAvailableBytes, st->force_intra,
          &st->delayedIntra, st->complexity >= 4);
 
    if (LM > 0)
@@ -1663,7 +1663,7 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
    intra_ener = ec_dec_bit_prob(dec, 8192);
    /* Get band energies */
    unquant_coarse_energy(st->mode, st->start, st->end, bandE, oldBandE,
-         intra_ener, st->mode->prob, dec, C, LM);
+         intra_ener, dec, C, LM);
 
    if (LM > 0)
       isTransient = ec_dec_bit_prob(dec, 8192);
index be1afbc..84b0b71 100644 (file)
@@ -109,15 +109,6 @@ void dump_modes(FILE *file, CELTMode **modes, int nb_modes)
          fprintf(file, "\n");
       }
 
-      fprintf(file, "#ifndef DEF_PROB%d\n", mode->nbEBands);
-      fprintf(file, "#define DEF_PROB%d\n", mode->nbEBands);
-      fprintf (file, "static const celt_int16 prob%d[%d] = {\n", mode->nbEBands, 4*mode->nbEBands);
-      for (j=0;j<4*mode->nbEBands;j++)
-         fprintf (file, "%d, ", mode->prob[j]);
-      fprintf (file, "};\n");
-      fprintf(file, "#endif\n");
-      fprintf(file, "\n");
-
       fprintf(file, "#ifndef DEF_LOGN%d\n", framerate);
       fprintf(file, "#define DEF_LOGN%d\n", framerate);
       fprintf (file, "static const celt_int16 logN%d[%d] = {\n", framerate, mode->nbEBands);
@@ -234,7 +225,6 @@ void dump_modes(FILE *file, CELTMode **modes, int nb_modes)
       fprintf(file, "%d,\t/* maxLM */\n", mode->maxLM);
       fprintf(file, "%d,\t/* nbShortMdcts */\n", mode->nbShortMdcts);
       fprintf(file, "%d,\t/* shortMdctSize */\n", mode->shortMdctSize);
-      fprintf(file, "prob%d,\t/* prob */\n", mode->nbEBands);
       fprintf(file, "logN%d,\t/* logN */\n", framerate);
       fprintf(file, "{%d, cache_index%d, cache_bits%d},\t/* cache */\n",
             mode->cache.size, mode->Fs/mdctSize, mode->Fs/mdctSize);
index d1412c1..e43029f 100644 (file)
     direction). */
 #define LAPLACE_NMIN (16)
 
-int ec_laplace_get_start_freq(int decay)
-{
-   celt_uint32 ft = 32768 - LAPLACE_MINP*(2*LAPLACE_NMIN+1);
-   int fs = (ft*(16384-decay))/(16384+decay);
-   return fs+LAPLACE_MINP;
-}
-
 static int ec_laplace_get_freq1(int fs0, int decay)
 {
    celt_int32 ft;
@@ -58,7 +51,7 @@ static int ec_laplace_get_freq1(int fs0, int decay)
    return ft*(16384-decay)>>15;
 }
 
-void ec_laplace_encode_start(ec_enc *enc, int *value, int decay, int fs)
+void ec_laplace_encode(ec_enc *enc, int *value, int fs, int decay)
 {
    unsigned fl;
    int val = *value;
@@ -102,14 +95,7 @@ void ec_laplace_encode_start(ec_enc *enc, int *value, int decay, int fs)
 }
 
 
-void ec_laplace_encode(ec_enc *enc, int *value, int decay)
-{
-   int fs = ec_laplace_get_start_freq(decay);
-   ec_laplace_encode_start(enc, value, decay, fs);
-}
-
-
-int ec_laplace_decode_start(ec_dec *dec, int decay, int fs)
+int ec_laplace_decode(ec_dec *dec, int fs, int decay)
 {
    int val=0;
    unsigned fl;
@@ -150,9 +136,3 @@ int ec_laplace_decode_start(ec_dec *dec, int decay, int fs)
    ec_dec_update(dec, fl, IMIN(fl+fs,32768), 32768);
    return val;
 }
-
-int ec_laplace_decode(ec_dec *dec, int decay)
-{
-   int fs = ec_laplace_get_start_freq(decay);
-   return ec_laplace_decode_start(dec, decay, fs);
-}
index 29e22c8..91c2df7 100644 (file)
 #include "entenc.h"
 #include "entdec.h"
 
-int ec_laplace_get_start_freq(int decay);
-
 /** Encode a value that is assumed to be the realisation of a
     Laplace-distributed random process
  @param enc Entropy encoder state
  @param value Value to encode
+ @param fs Probability of 0, multiplied by 32768
  @param decay Probability of the value +/- 1, multiplied by 16384
 */
-void ec_laplace_encode(ec_enc *enc, int *value, int decay);
-
-void ec_laplace_encode_start(ec_enc *enc, int *value, int decay, int fs);
+void ec_laplace_encode(ec_enc *enc, int *value, int fs, int decay);
 
 /** Decode a value that is assumed to be the realisation of a
     Laplace-distributed random process
  @param dec Entropy decoder state
+ @param fs Probability of 0, multiplied by 32768
  @param decay Probability of the value +/- 1, multiplied by 16384
  @return Value decoded
  */
-int ec_laplace_decode(ec_dec *dec, int decay);
-
-int ec_laplace_decode_start(ec_dec *dec, int decay, int fs);
+int ec_laplace_decode(ec_dec *dec, int fs, int decay);
index 1846284..0732e55 100644 (file)
@@ -454,10 +454,6 @@ CELTMode *celt_mode_create(celt_int32 Fs, int frame_size, int *error)
    )
       goto failure;
 
-   mode->prob = quant_prob_alloc(mode);
-   if (mode->prob==NULL)
-     goto failure;
-
    if (error)
       *error = CELT_OK;
 
@@ -486,7 +482,6 @@ void celt_mode_destroy(CELTMode *mode)
    celt_free((celt_int16*)mode->cache.index);
    celt_free((unsigned char*)mode->cache.bits);
    clt_mdct_clear(&mode->mdct);
-   quant_prob_free(mode->prob);
 
    celt_free((CELTMode *)mode);
 #endif
index 8760436..3417c8d 100644 (file)
@@ -97,7 +97,6 @@ struct CELTMode {
    int         nbShortMdcts;
    int         shortMdctSize;
 
-   const celt_int16 *prob;
    const celt_int16 *logN;
 
    PulseCache cache;
index e3fbb61..d7eb953 100644 (file)
@@ -70,6 +70,74 @@ static const celt_word16 pred_coef[4] = {29440/32768., 26112/32768., 21248/32768
 static const celt_word16 beta_coef[4] = {30147/32768., 22282/32768., 12124/32768., 6554/32768.};
 #endif
 
+/*Parameters of the Laplace-like probability models used for the coarse energy.
+  There is one pair of parameters for each frame size, prediction type
+   (inter/intra), and band number.
+  The first number of each pair is the probability of 0, and the second is the
+   decay rate, both in Q8 precision.*/
+static const unsigned char e_prob_model[4][2][42] = {
+   /*120 sample frames.*/
+   {
+      /*Inter*/
+      {
+          72, 127,  65, 129,  66, 128,  65, 128,  64, 128,  62, 128,  64, 128,
+          64, 128,  92,  78,  92,  79,  92,  78,  90,  79, 116,  41, 115,  40,
+         114,  40, 132,  26, 132,  26, 145,  17, 161,  12, 176,  10, 177,  11
+      },
+      /*Intra*/
+      {
+          24, 179,  48, 138,  54, 135,  54, 132,  53, 134,  56, 133,  55, 132,
+          55, 132,  61, 114,  70,  96,  74,  88,  75,  88,  87,  74,  89,  66,
+          91,  67, 100,  59, 108,  50, 120,  40, 122,  37,  97,  43,  78,  50
+      }
+   },
+   /*240 sample frames.*/
+   {
+      /*Inter*/
+      {
+          83,  78,  84,  81,  88,  75,  86,  74,  87,  71,  90,  73,  93,  74,
+          93,  74, 109,  40, 114,  36, 117,  34, 117,  34, 143,  17, 145,  18,
+         146,  19, 162,  12, 165,  10, 178,   7, 189,   6, 190,   8, 177,   9
+      },
+      /*Intra*/
+      {
+          23, 178,  54, 115,  63, 102,  66,  98,  69,  99,  74,  89,  71,  91,
+          73,  91,  78,  89,  86,  80,  92,  66,  93,  64, 102,  59, 103,  60,
+         104,  60, 117,  52, 123,  44, 138,  35, 133,  31,  97,  38,  77,  45
+      }
+   },
+   /*480 sample frames.*/
+   {
+      /*Inter*/
+      {
+          61,  90,  93,  60, 105,  42, 107,  41, 110,  45, 116,  38, 113,  38,
+         112,  38, 124,  26, 132,  27, 136,  19, 140,  20, 155,  14, 159,  16,
+         158,  18, 170,  13, 177,  10, 187,   8, 192,   6, 175,   9, 159,  10
+      },
+      /*Intra*/
+      {
+          21, 178,  59, 110,  71,  86,  75,  85,  84,  83,  91,  66,  88,  73,
+          87,  72,  92,  75,  98,  72, 105,  58, 107,  54, 115,  52, 114,  55,
+         112,  56, 129,  51, 132,  40, 150,  33, 140,  29,  98,  35,  77,  42
+      }
+   },
+   /*960 sample frames.*/
+   {
+      /*Inter*/
+      {
+          42, 121,  96,  66, 108,  43, 111,  40, 117,  44, 123,  32, 120,  36,
+         119,  33, 127,  33, 134,  34, 139,  21, 147,  23, 152,  20, 158,  25,
+         154,  26, 166,  21, 173,  16, 184,  13, 184,  10, 150,  13, 139,  15
+      },
+      /*Intra*/
+      {
+          22, 178,  63, 114,  74,  82,  84,  83,  92,  82, 103,  62,  96,  72,
+          96,  67, 101,  73, 107,  72, 113,  55, 118,  52, 125,  52, 118,  52,
+         117,  55, 135,  49, 137,  39, 157,  32, 145,  29,  97,  33,  77,  40
+      }
+   }
+};
+
 static int intra_decision(const celt_word16 *eBands, celt_word16 *oldEBands, int start, int end, int len, int C)
 {
    int c, i;
@@ -84,38 +152,10 @@ static int intra_decision(const celt_word16 *eBands, celt_word16 *oldEBands, int
    return SHR32(dist,2*DB_SHIFT-4) > 2*C*(end-start);
 }
 
-#ifndef STATIC_MODES
-
-celt_int16 *quant_prob_alloc(const CELTMode *m)
-{
-   int i;
-   celt_int16 *prob;
-   prob = celt_alloc(4*m->nbEBands*sizeof(celt_int16));
-   if (prob==NULL)
-     return NULL;
-   for (i=0;i<m->nbEBands;i++)
-   {
-      prob[2*i] = 7000-i*200;
-      prob[2*i+1] = ec_laplace_get_start_freq(prob[2*i]);
-   }
-   for (i=0;i<m->nbEBands;i++)
-   {
-      prob[2*m->nbEBands+2*i] = 9000-i*220;
-      prob[2*m->nbEBands+2*i+1] = ec_laplace_get_start_freq(prob[2*m->nbEBands+2*i]);
-   }
-   return prob;
-}
-
-void quant_prob_free(const celt_int16 *freq)
-{
-   celt_free((celt_int16*)freq);
-}
-#endif
-
 static void quant_coarse_energy_impl(const CELTMode *m, int start, int end,
       const celt_word16 *eBands, celt_word16 *oldEBands, int budget,
-      const celt_int16 *prob, celt_word16 *error, ec_enc *enc, int _C, int LM,
-      int intra, celt_word16 max_decay)
+      const unsigned char *prob_model, celt_word16 *error, ec_enc *enc,
+      int _C, int LM, int intra, celt_word16 max_decay)
 {
    const int C = CHANNELS(_C);
    int i, c;
@@ -127,7 +167,6 @@ static void quant_coarse_energy_impl(const CELTMode *m, int start, int end,
    if (intra)
    {
       coef = 0;
-      prob += 2*m->nbEBands;
       beta = QCONST16(.15f,15);
    } else {
       beta = beta_coef[LM];
@@ -141,6 +180,7 @@ static void quant_coarse_energy_impl(const CELTMode *m, int start, int end,
       do {
          int bits_left;
          int qi;
+         int pi;
          celt_word16 q;
          celt_word16 x;
          celt_word32 f;
@@ -174,7 +214,9 @@ static void quant_coarse_energy_impl(const CELTMode *m, int start, int end,
             if (bits_left<8)
                qi = 0;
          }
-         ec_laplace_encode_start(enc, &qi, prob[2*i], prob[2*i+1]);
+         pi = 2*IMIN(i,20);
+         ec_laplace_encode(enc, &qi,
+               prob_model[pi]<<7, prob_model[pi+1]<<6);
          error[i+c*m->nbEBands] = PSHR32(f,15) - SHL16(qi,DB_SHIFT);
          q = SHL16(qi,DB_SHIFT);
          
@@ -186,8 +228,8 @@ static void quant_coarse_energy_impl(const CELTMode *m, int start, int end,
 
 void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd,
       const celt_word16 *eBands, celt_word16 *oldEBands, int budget,
-      const celt_int16 *prob, celt_word16 *error, ec_enc *enc, int _C, int LM,
-      int nbAvailableBytes, int force_intra, int *delayedIntra, int two_pass)
+      celt_word16 *error, ec_enc *enc, int _C, int LM, int nbAvailableBytes,
+      int force_intra, int *delayedIntra, int two_pass)
 {
    const int C = CHANNELS(_C);
    int intra;
@@ -223,7 +265,7 @@ void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd,
    if (two_pass || intra)
    {
       quant_coarse_energy_impl(m, start, end, eBands, oldEBands_intra, budget,
-            prob, error_intra, enc, C, LM, 1, max_decay);
+            e_prob_model[LM][1], error_intra, enc, C, LM, 1, max_decay);
    }
 
    if (!intra)
@@ -246,7 +288,7 @@ void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd,
       *(enc->buf) = buf_start_state;
 
       quant_coarse_energy_impl(m, start, end, eBands, oldEBands, budget,
-            prob, error, enc, C, LM, 0, max_decay);
+            e_prob_model[LM][intra], error, enc, C, LM, 0, max_decay);
 
       if (two_pass && ec_enc_tell(enc, 3) > tell_intra)
       {
@@ -332,8 +374,9 @@ void quant_energy_finalise(const CELTMode *m, int start, int end, celt_ener *eBa
    }
 }
 
-void unquant_coarse_energy(const CELTMode *m, int start, int end, celt_ener *eBands, celt_word16 *oldEBands, int intra, const celt_int16 *prob, ec_dec *dec, int _C, int LM)
+void unquant_coarse_energy(const CELTMode *m, int start, int end, celt_ener *eBands, celt_word16 *oldEBands, int intra, ec_dec *dec, int _C, int LM)
 {
+   const unsigned char *prob_model = e_prob_model[LM][intra];
    int i, c;
    celt_word32 prev[2] = {0, 0};
    celt_word16 coef;
@@ -345,7 +388,6 @@ void unquant_coarse_energy(const CELTMode *m, int start, int end, celt_ener *eBa
    {
       coef = 0;
       beta = QCONST16(.15f,15);
-      prob += 2*m->nbEBands;
    } else {
       beta = beta_coef[LM];
       coef = pred_coef[LM];
@@ -357,8 +399,11 @@ void unquant_coarse_energy(const CELTMode *m, int start, int end, celt_ener *eBa
       c=0;
       do {
          int qi;
+         int pi;
          celt_word16 q;
-         qi = ec_laplace_decode_start(dec, prob[2*i], prob[2*i+1]);
+         pi = 2*IMIN(i,20);
+         qi = ec_laplace_decode(dec,
+               prob_model[pi]<<7, prob_model[pi+1]<<6);
          q = SHL16(qi,DB_SHIFT);
 
          oldEBands[i+c*m->nbEBands] = PSHR32(MULT16_16(coef,oldEBands[i+c*m->nbEBands]) + prev[c] + SHL32(EXTEND32(q),15), 15);
index 416ee13..0e3a5e2 100644 (file)
@@ -45,19 +45,19 @@ void amp2Log2(const CELTMode *m, int effEnd, int end,
 void log2Amp(const CELTMode *m, int start, int end,
       celt_ener *eBands, celt_word16 *oldEBands, int _C);
 
-celt_int16 *quant_prob_alloc(const CELTMode *m);
+unsigned char *quant_prob_alloc(const CELTMode *m);
 void quant_prob_free(const celt_int16 *freq);
 
 void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd,
       const celt_word16 *eBands, celt_word16 *oldEBands, int budget,
-      const celt_int16 *prob, celt_word16 *error, ec_enc *enc, int _C, int LM,
+      celt_word16 *error, ec_enc *enc, int _C, int LM,
       int nbAvailableBytes, int force_intra, int *delayedIntra, int two_pass);
 
 void quant_fine_energy(const CELTMode *m, int start, int end, celt_ener *eBands, celt_word16 *oldEBands, celt_word16 *error, int *fine_quant, ec_enc *enc, int _C);
 
 void quant_energy_finalise(const CELTMode *m, int start, int end, celt_ener *eBands, celt_word16 *oldEBands, celt_word16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int _C);
 
-void unquant_coarse_energy(const CELTMode *m, int start, int end, celt_ener *eBands, celt_word16 *oldEBands, int intra, const celt_int16 *prob, ec_dec *dec, int _C, int LM);
+void unquant_coarse_energy(const CELTMode *m, int start, int end, celt_ener *eBands, celt_word16 *oldEBands, int intra, ec_dec *dec, int _C, int LM);
 
 void unquant_fine_energy(const CELTMode *m, int start, int end, celt_ener *eBands, celt_word16 *oldEBands, int *fine_quant, ec_dec *dec, int _C);
 
index 417f4e1..7778667 100644 (file)
 
 #define DATA_SIZE 40000
 
+int ec_laplace_get_start_freq(int decay)
+{
+   celt_uint32 ft = 32768 - LAPLACE_MINP*(2*LAPLACE_NMIN+1);
+   int fs = (ft*(16384-decay))/(16384+decay);
+   return fs+LAPLACE_MINP;
+}
+
 int main(void)
 {
    int i;
@@ -41,8 +48,9 @@ int main(void)
       decay[i] = rand()%11000+5000;
    }
    for (i=0;i<10000;i++)
-      ec_laplace_encode(&enc, &val[i], decay[i]);      
-      
+      ec_laplace_encode(&enc, &val[i],
+            ec_laplace_get_start_freq(decay[i]), decay[i]);
+
    ec_enc_done(&enc);
 
    ec_byte_readinit(&buf,ec_byte_get_buffer(&buf),ec_byte_bytes(&buf));
@@ -50,7 +58,8 @@ int main(void)
 
    for (i=0;i<10000;i++)
    {
-      int d = ec_laplace_decode(&dec, decay[i]);
+      int d = ec_laplace_decode(&dec,
+            ec_laplace_get_start_freq(decay[i]), decay[i]);
       if (d != val[i])
       {
          fprintf (stderr, "Got %d instead of %d\n", d, val[i]);