ref: ad6371906a816bef202f10fb3cca602280a8765f
parent: 827f93175bc532beab5c5d49eed6649282795708
author: Jean-Marc Valin <[email protected]>
date: Wed May 7 09:44:39 EDT 2008
Implemented rate-dependant allocation for the fine energy quantisation.
--- a/libcelt/celt.c
+++ b/libcelt/celt.c
@@ -321,7 +321,7 @@
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 @@
}
/* 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);
--- a/libcelt/dump_modes.c
+++ b/libcelt/dump_modes.c
@@ -161,6 +161,7 @@
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");
}
--- a/libcelt/modes.c
+++ b/libcelt/modes.c
@@ -232,6 +232,38 @@
#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 @@
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 @@
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);
}
--- a/libcelt/modes.h
+++ b/libcelt/modes.h
@@ -96,6 +96,7 @@
struct PsyDecay psy;
int *prob;
+ const celt_int16_t *energy_alloc;
celt_uint32_t marker_end;
};
--- a/libcelt/quant_bands.c
+++ b/libcelt/quant_bands.c
@@ -48,8 +48,48 @@
#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 @@
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 @@
#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,14 +232,15 @@
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;
@@ -203,10 +247,10 @@
#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 @@
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 @@
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,15 +296,17 @@
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++)
@@ -262,6 +313,7 @@
{
eBands[i] = dB2Amp(oldEBands[i]);
}
+ RESTORE_STACK;
/*printf ("\n");*/
}