shithub: opus

Download patch

ref: e65978fea75e6583bbea527fe92e0ffbe025b24b
parent: 100ae8ce34e25766868c11fb952cec5b1f1f57a1
author: Jean-Marc Valin <[email protected]>
date: Thu Dec 2 08:46:48 EST 2010

Adding a dual stereo option.

Left and right are coded independently.

--- a/libcelt/bands.c
+++ b/libcelt/bands.c
@@ -902,13 +902,13 @@
 
 void quant_all_bands(int encode, const CELTMode *m, int start, int end,
       celt_norm *_X, celt_norm *_Y, const celt_ener *bandE, int *pulses,
-      int shortBlocks, int fold, int intensity, int *tf_res, int resynth,
+      int shortBlocks, int fold, int dual_stereo, int intensity, int *tf_res, int resynth,
       int total_bits, void *ec, int LM, int codedBands)
 {
    int i, balance;
    celt_int32 remaining_bits;
    const celt_int16 * restrict eBands = m->eBands;
-   celt_norm * restrict norm;
+   celt_norm * restrict norm, * restrict norm2;
    VARDECL(celt_norm, _norm);
    VARDECL(celt_norm, lowband_scratch);
    int B;
@@ -921,10 +921,10 @@
 
    M = 1<<LM;
    B = shortBlocks ? M : 1;
-   ALLOC(_norm, M*eBands[m->nbEBands], celt_norm);
+   ALLOC(_norm, C*M*eBands[m->nbEBands], celt_norm);
    ALLOC(lowband_scratch, M*(eBands[m->nbEBands]-eBands[m->nbEBands-1]), celt_norm);
    norm = _norm;
-
+   norm2 = norm + M*eBands[m->nbEBands];
    if (C==2)
    {
       int j;
@@ -1015,10 +1015,28 @@
          if (effective_lowband < M*eBands[start])
             effective_lowband = M*eBands[start];
       }
-      quant_band(encode, m, i, X, Y, N, b, fold, B, intensity, tf_change,
-            effective_lowband != -1 ? norm+effective_lowband : NULL, resynth, ec, &remaining_bits, LM,
-            norm+M*eBands[i], bandE, 0, &seed, Q15ONE, lowband_scratch);
+      if (dual_stereo && i==intensity)
+      {
+         int j;
 
+         /* Switch off dual stereo to do intensity */
+         dual_stereo = 0;
+         for (j=0;j<M*eBands[i];j++)
+            norm[j] = HALF32(norm[j]+norm2[j]);
+      }
+      if (dual_stereo)
+      {
+         quant_band(encode, m, i, X, NULL, N, b/2, fold, B, intensity, tf_change,
+               effective_lowband != -1 ? norm+effective_lowband : NULL, resynth, ec, &remaining_bits, LM,
+               norm+M*eBands[i], bandE, 0, &seed, Q15ONE, lowband_scratch);
+         quant_band(encode, m, i, Y, NULL, N, b/2, fold, B, intensity, tf_change,
+               effective_lowband != -1 ? norm2+effective_lowband : NULL, resynth, ec, &remaining_bits, LM,
+               norm2+M*eBands[i], bandE, 0, &seed, Q15ONE, lowband_scratch);
+      } else {
+         quant_band(encode, m, i, X, Y, N, b, fold, B, intensity, tf_change,
+               effective_lowband != -1 ? norm+effective_lowband : NULL, resynth, ec, &remaining_bits, LM,
+               norm+M*eBands[i], bandE, 0, &seed, Q15ONE, lowband_scratch);
+      }
       balance += pulses[i] + tell;
 
       /* Update the folding position only as long as we have 1 bit/sample depth */
--- a/libcelt/bands.h
+++ b/libcelt/bands.h
@@ -80,7 +80,7 @@
  */
 void quant_all_bands(int encode, const CELTMode *m, int start, int end,
       celt_norm * X, celt_norm * Y, const celt_ener *bandE, int *pulses,
-      int time_domain, int fold, int intensity, int *tf_res, int resynth,
+      int time_domain, int fold, int dual_stereo, int intensity, int *tf_res, int resynth,
       int total_bits, void *enc, int M, int codedBands);
 
 
--- a/libcelt/celt.c
+++ b/libcelt/celt.c
@@ -649,6 +649,37 @@
    return trim_index;
 }
 
+static int stereo_analysis(const CELTMode *m, const celt_norm *X,
+      int nbEBands, int LM, int C, int N0)
+{
+   int i;
+   int thetas;
+   celt_word32 sumLR = EPSILON, sumMS = EPSILON;
+
+   /* Use the L1 norm to model the entropy of the L/R signal vs the M/S signal */
+   for (i=0;i<13;i++)
+   {
+      int j;
+      for (j=m->eBands[i]<<LM;j<m->eBands[i+1]<<LM;j++)
+      {
+         celt_word16 L, R, M, S;
+         L = X[j];
+         R = X[N0+j];
+         M = L+R;
+         S = L-R;
+         sumLR += EXTEND32(ABS16(L)) + EXTEND32(ABS16(R));
+         sumMS += EXTEND32(ABS16(M)) + EXTEND32(ABS16(S));
+      }
+   }
+   sumMS = MULT16_32_Q15(QCONST16(0.707107f, 15), sumMS);
+   thetas = 13;
+   /* We don't need thetas for lower bands with LM<=1 */
+   if (LM<=1)
+      thetas -= 8;
+   return MULT16_32_Q15((m->eBands[13]<<(LM+1))+thetas, sumMS)
+         > MULT16_32_Q15(m->eBands[13]<<(LM+1), sumLR);
+}
+
 #ifdef FIXED_POINT
 int celt_encode_with_ec(CELTEncoder * restrict st, const celt_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
 {
@@ -689,6 +720,7 @@
    int pitch_index=0;
    celt_word16 gain1 = 0;
    int intensity=0;
+   int dual_stereo=0;
    SAVE_STACK;
 
    if (nbCompressedBytes<0 || pcm==NULL)
@@ -1003,6 +1035,11 @@
 
    if (C==2)
    {
+      dual_stereo = stereo_analysis(st->mode, X, st->mode->nbEBands, LM, C, N);
+      ec_enc_bit_prob(enc, dual_stereo, 32768);
+   }
+   if (C==2)
+   {
       int effectiveRate;
 
       if (st->vbr_rate_norm>0)
@@ -1055,7 +1092,7 @@
 
    /* Residual quantisation */
    quant_all_bands(1, st->mode, st->start, st->end, X, C==2 ? X+N : NULL,
-         bandE, pulses, shortBlocks, has_fold, intensity, tf_res, resynth,
+         bandE, pulses, shortBlocks, has_fold, dual_stereo, intensity, tf_res, resynth,
          nbCompressedBytes*8, enc, LM, codedBands);
 
    quant_energy_finalise(st->mode, st->start, st->end, bandE, oldBandE, error, fine_quant, fine_priority, nbCompressedBytes*8-ec_enc_tell(enc, 0), enc, C);
@@ -1619,6 +1656,7 @@
    int postfilter_pitch;
    celt_word16 postfilter_gain;
    int intensity=0;
+   int dual_stereo=0;
    SAVE_STACK;
 
    if (pcm==NULL)
@@ -1747,7 +1785,10 @@
    }
 
    if (C==2)
+   {
+      dual_stereo = ec_dec_bit_prob(dec, 32768);
       intensity = ec_dec_uint(dec, 1+st->end-st->start);
+   }
 
    bits = len*8 - ec_dec_tell(dec, 0) - 1;
    codedBands = compute_allocation(st->mode, st->start, st->end, offsets, alloc_trim, bits, pulses, fine_quant, fine_priority, C, LM);
@@ -1756,7 +1797,7 @@
 
    /* Decode fixed codebook */
    quant_all_bands(0, st->mode, st->start, st->end, X, C==2 ? X+N : NULL,
-         NULL, pulses, shortBlocks, has_fold, intensity, tf_res, 1,
+         NULL, pulses, shortBlocks, has_fold, dual_stereo, intensity, tf_res, 1,
          len*8, dec, LM, codedBands);
 
    unquant_energy_finalise(st->mode, st->start, st->end, bandE, oldBandE,