Implemented rate-dependant allocation for the fine energy quantisation.
authorJean-Marc Valin <Jean-Marc.Valin@csiro.au>
Wed, 7 May 2008 03:44:39 +0000 (13:44 +1000)
committerJean-Marc Valin <Jean-Marc.Valin@csiro.au>
Wed, 7 May 2008 03:44:39 +0000 (13:44 +1000)
libcelt/celt.c
libcelt/dump_modes.c
libcelt/modes.c
libcelt/modes.h
libcelt/quant_bands.c

index f28be89..fddd416 100644 (file)
@@ -321,7 +321,7 @@ int EXPORT celt_encode(CELTEncoder * restrict st, celt_int16_t * restrict pcm, u
       for (i=0;i<C*N;i++)
          P[i] = 0;
    }
-   quant_energy(st->mode, bandE, st->oldBandE, nbCompressedBytes*8/3, st->mode->prob, &st->enc);
+   quant_energy(st->mode, bandE, st->oldBandE, 20+nbCompressedBytes*8/5, st->mode->prob, &st->enc);
 
    if (C==2)
    {
@@ -589,7 +589,7 @@ int EXPORT celt_decode(CELTDecoder * restrict st, unsigned char *data, int len,
    }
 
    /* Get band energies */
-   unquant_energy(st->mode, bandE, st->oldBandE, len*8/3, st->mode->prob, &dec);
+   unquant_energy(st->mode, bandE, st->oldBandE, 20+len*8/5, st->mode->prob, &dec);
 
    /* Pitch MDCT */
    compute_mdcts(st->mode, st->mode->window, st->out_mem+pitch_index*C, freq);
index 6a19086..9f00dcc 100644 (file)
@@ -161,6 +161,7 @@ void dump_modes(FILE *file, CELTMode **modes, int nb_modes)
       fprintf(file, "window%d,\t/* window */\n", mode->overlap);
       fprintf(file, "{psy_decayR_%d},\t/* psy */\n", mode->Fs);
       fprintf(file, "0,\t/* prob */\n");
+      fprintf(file, "0,\t/* energy_alloc */\n");
       fprintf(file, "0x%x,\t/* marker */\n", 0xa110ca7e);
       fprintf(file, "};\n");
    }
index 29ea983..6b9af97 100644 (file)
@@ -232,6 +232,38 @@ static void compute_allocation_table(CELTMode *mode, int res)
 
 #endif /* STATIC_MODES */
 
+static void compute_energy_allocation_table(CELTMode *mode)
+{
+   int i, j;
+   celt_int16_t *alloc;
+   
+   alloc = celt_alloc(sizeof(celt_int16_t)*(mode->nbAllocVectors*(mode->nbEBands+1)));
+   for (i=0;i<mode->nbAllocVectors;i++)
+   {
+      int sum = 0;
+      int min_bits = 1;
+      if (mode->allocVectors[i*mode->nbEBands]>12)
+         min_bits = 2;
+      if (mode->allocVectors[i*mode->nbEBands]>24)
+         min_bits = 3;
+      for (j=0;j<mode->nbEBands;j++)
+      {
+         alloc[i*(mode->nbEBands+1)+j] = mode->allocVectors[i*mode->nbEBands+j]
+                                         / (mode->eBands[j+1]-mode->eBands[j]-1);
+         if (alloc[i*(mode->nbEBands+1)+j]<min_bits)
+            alloc[i*(mode->nbEBands+1)+j] = min_bits;
+         if (alloc[i*(mode->nbEBands+1)+j]>7)
+            alloc[i*(mode->nbEBands+1)+j] = 7;
+         sum += alloc[i*(mode->nbEBands+1)+j];
+         /*printf ("%d ", alloc[i*(mode->nbEBands+1)+j]);*/
+         /*printf ("%f ", mode->allocVectors[i*mode->nbEBands+j]*1.f/(mode->eBands[j+1]-mode->eBands[j]-1));*/
+      }
+      alloc[i*(mode->nbEBands+1)+mode->nbEBands] = sum;
+      /*printf ("\n");*/
+   }
+   mode->energy_alloc = alloc;
+}
+
 CELTMode EXPORT *celt_mode_create(celt_int32_t Fs, int channels, int frame_size, int lookahead, int *error)
 {
    int i;
@@ -342,6 +374,8 @@ CELTMode EXPORT *celt_mode_create(celt_int32_t Fs, int channels, int frame_size,
    mode->fft = pitch_state_alloc(MAX_PERIOD);
 
    mode->prob = quant_prob_alloc(mode);
+   compute_energy_allocation_table(mode);
+   
    if (error)
       *error = CELT_OK;
    return mode;
@@ -378,6 +412,7 @@ void EXPORT celt_mode_destroy(CELTMode *mode)
    mdct_clear(&mode->mdct);
    pitch_state_free(mode->fft);
    quant_prob_free(mode->prob);
+   celt_free((celt_int16_t *)mode->energy_alloc);
    celt_free((CELTMode *)mode);
 }
 
index d7b59f0..d47825e 100644 (file)
@@ -96,6 +96,7 @@ struct CELTMode {
    struct PsyDecay psy;
 
    int *prob;
+   const celt_int16_t *energy_alloc;
    
    celt_uint32_t marker_end;
 };
index 5e6ec9a..2c6fb63 100644 (file)
@@ -48,7 +48,47 @@ const celt_word16_t eMeans[24] = {45.f, -8.f, -12.f, -2.5f, 1.f, 0.f, 0.f, 0.f,
 #endif
 
 /*const int frac[24] = {4, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};*/
-const int frac[24] = {8, 6, 5, 4, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
+/*const int frac[24] = {8, 6, 5, 4, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};*/
+
+static void compute_fine_allocation(const CELTMode *m, celt_int16_t *bits, int budget)
+{
+   int i,j;
+   int len;
+   len = m->nbEBands;
+   for (i=0;i<m->nbAllocVectors;i++)
+   {
+      if (m->energy_alloc[i*(len+1)+len] > budget)
+         break;
+   }
+   if (i==0)
+   {
+      for (j=0;j<len;j++)
+         bits[j] = 0;
+   } else {
+      for (j=0;j<len;j++)
+         bits[j] = m->energy_alloc[(i-1)*(len+1)+j];
+      budget -= m->energy_alloc[(i-1)*(len+1)+len];
+   }
+   if (i<m->nbAllocVectors)
+   {
+      j=0;
+      while (budget>0)
+      {
+         if (m->energy_alloc[i*(len+1)+j]>bits[j])
+         {
+            bits[j]++;
+            budget--;
+         }
+         j++;
+         if (j>=len)
+            j=0;
+      }
+   }
+   
+   /*for (j=0;j<len;j++)
+      printf ("%d ", bits[j]);
+   printf ("\n");*/
+}
 
 #ifdef FIXED_POINT
 static inline celt_ener_t dB2Amp(celt_ener_t dB)
@@ -155,11 +195,13 @@ static void quant_energy_mono(const CELTMode *m, celt_ener_t *eBands, celt_word1
    celt_word16_t coef = m->ePredCoef;
    celt_word16_t beta;
    VARDECL(celt_word16_t, error);
+   VARDECL(celt_int16_t, fine_quant);
    SAVE_STACK;
    /* The .7 is a heuristic */
    beta = MULT16_16_Q15(QCONST16(.8f,15),coef);
    
    ALLOC(error, m->nbEBands, celt_word16_t);
+   ALLOC(fine_quant, m->nbEBands, celt_int16_t);
    bits = ec_enc_tell(enc, 0);
    /* Encode at a fixed coarse resolution */
    for (i=0;i<m->nbEBands;i++)
@@ -177,8 +219,9 @@ static void quant_energy_mono(const CELTMode *m, celt_ener_t *eBands, celt_word1
 #else
       qi = (int)floor(.5+f);
 #endif
-      /* If we don't have enough bits to encode all the energy, just assume something safe. */
-      if (ec_enc_tell(enc, 0) - bits > budget)
+      /* If we don't have enough bits to encode all the energy, just assume something safe.
+         We allow slightly busting the budget here */
+      if (ec_enc_tell(enc, 0) - bits > budget+16)
          qi = -1;
       else
          ec_laplace_encode_start(enc, qi, prob[2*i], prob[2*i+1]);
@@ -189,24 +232,25 @@ static void quant_energy_mono(const CELTMode *m, celt_ener_t *eBands, celt_word1
       
       prev = mean+prev+MULT16_16_Q15(Q15ONE-beta,q);
    }
+   
+   compute_fine_allocation(m, fine_quant, budget-(ec_enc_tell(enc, 0)-bits));
+
    /* Encode finer resolution */
    for (i=0;i<m->nbEBands;i++)
    {
       int q2;
-      celt_word16_t offset = (error[i]+QCONST16(.5f,8))*frac[i];
-      /* FIXME: Instead of giving up without warning, we should degrade everything gracefully */
-      if (ec_enc_tell(enc, 0) - bits + celt_ilog2(frac[i]) >= budget)
-         break;
+      celt_int16_t frac = 1<<fine_quant[i];
+      celt_word16_t offset = (error[i]+QCONST16(.5f,8))*frac;
 #ifdef FIXED_POINT
       /* Has to be without rounding */
       q2 = offset>>8;
 #else
       q2 = (int)floor(offset);
 #endif
-      if (q2 > frac[i]-1)
-         q2 = frac[i]-1;
-      enc_frac(enc, q2, frac[i]);
-      offset = EXTRACT16(celt_div(SHL16(q2,8)+QCONST16(.5,8),frac[i])-QCONST16(.5f,8));
+      if (q2 > frac-1)
+         q2 = frac-1;
+      enc_frac(enc, q2, frac);
+      offset = EXTRACT16(celt_div(SHL16(q2,8)+QCONST16(.5,8),frac)-QCONST16(.5f,8));
       oldEBands[i] += PSHR32(MULT16_16(DB_SCALING*6,offset),8);
       /*printf ("%f ", error[i] - offset);*/
    }
@@ -227,7 +271,11 @@ static void unquant_energy_mono(const CELTMode *m, celt_ener_t *eBands, celt_wor
    celt_word16_t prev = 0;
    celt_word16_t coef = m->ePredCoef;
    /* The .7 is a heuristic */
+   VARDECL(celt_int16_t, fine_quant);
    celt_word16_t beta = MULT16_16_Q15(QCONST16(.8f,15),coef);
+   SAVE_STACK;
+   
+   ALLOC(fine_quant, m->nbEBands, celt_int16_t);
    bits = ec_dec_tell(dec, 0);
    
    /* Decode at a fixed coarse resolution */
@@ -236,8 +284,9 @@ static void unquant_energy_mono(const CELTMode *m, celt_ener_t *eBands, celt_wor
       int qi;
       celt_word16_t q;
       celt_word16_t mean = MULT16_16_Q15(Q15ONE-coef,eMeans[i]);
-      /* If we didn't have enough bits to encode all the energy, just assume something safe. */
-      if (ec_dec_tell(dec, 0) - bits > budget)
+      /* If we didn't have enough bits to encode all the energy, just assume something safe.
+         We allow slightly busting the budget here */
+      if (ec_dec_tell(dec, 0) - bits > budget+16)
          qi = -1;
       else
          qi = ec_laplace_decode_start(dec, prob[2*i], prob[2*i+1]);
@@ -247,21 +296,24 @@ static void unquant_energy_mono(const CELTMode *m, celt_ener_t *eBands, celt_wor
       
       prev = mean+prev+MULT16_16_Q15(Q15ONE-beta,q);
    }
+   
+   compute_fine_allocation(m, fine_quant, budget-(ec_dec_tell(dec, 0)-bits));
+
    /* Decode finer resolution */
    for (i=0;i<m->nbEBands;i++)
    {
       int q2;
+      celt_int16_t frac = 1<<fine_quant[i];
       celt_word16_t offset;
-      if (ec_dec_tell(dec, 0) - bits + celt_ilog2(frac[i]) >= budget)
-         break;
-      q2 = dec_frac(dec, frac[i]);
-      offset = EXTRACT16(celt_div(SHL16(q2,8)+QCONST16(.5,8),frac[i])-QCONST16(.5f,8));
+      q2 = dec_frac(dec, frac);
+      offset = EXTRACT16(celt_div(SHL16(q2,8)+QCONST16(.5,8),frac)-QCONST16(.5f,8));
       oldEBands[i] += PSHR32(MULT16_16(DB_SCALING*6,offset),8);
    }
    for (i=0;i<m->nbEBands;i++)
    {
       eBands[i] = dB2Amp(oldEBands[i]);
    }
+   RESTORE_STACK;
    /*printf ("\n");*/
 }