From fb83fb422f56bfe033c81bf4211e4766b7a35b1e Mon Sep 17 00:00:00 2001
From: Jean-Marc Valin <jean-marc.valin@usherbrooke.ca>
Date: Sat, 8 Dec 2007 00:56:04 +1100
Subject: [PATCH] Very basic packet loss concealment code

---
 libcelt/celt.c     | 57 ++++++++++++++++++++++++++++++++++++++++++++++
 libcelt/testcelt.c |  5 +++-
 2 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/libcelt/celt.c b/libcelt/celt.c
index 99fe097cc..56055a5d8 100644
--- a/libcelt/celt.c
+++ b/libcelt/celt.c
@@ -330,6 +330,8 @@ struct CELTDecoder {
    float *out_mem;
 
    float *oldBandE;
+   
+   int last_pitch_index;
 };
 
 CELTDecoder *celt_decoder_new(const CELTMode *mode)
@@ -355,6 +357,8 @@ CELTDecoder *celt_decoder_new(const CELTMode *mode)
    st->oldBandE = celt_alloc(mode->nbEBands*sizeof(float));
 
    st->preemph = 0.8;
+   
+   st->last_pitch_index = 0;
    return st;
 }
 
@@ -376,6 +380,51 @@ void celt_decoder_destroy(CELTDecoder *st)
    celt_free(st);
 }
 
+int celt_decode_lost(CELTDecoder *st, short *pcm)
+{
+   int i, N, B;
+   N = st->block_size;
+   B = st->nb_blocks;
+   
+   float X[B*N];         /**< Interleaved signal MDCTs */
+   float P[B*N];         /**< Interleaved pitch MDCTs*/
+   float bandE[st->mode->nbEBands];
+   float gains[st->mode->nbPBands];
+   int pitch_index;
+   
+   pitch_index = st->last_pitch_index;
+   
+   /* Pitch MDCT */
+   compute_mdcts(&st->mdct_lookup, st->window, st->out_mem+pitch_index, X, N, B);
+
+   CELT_MOVE(st->out_mem, st->out_mem+B*N, MAX_PERIOD-B*N);
+   /* Compute inverse MDCTs */
+   for (i=0;i<B;i++)
+   {
+      int j;
+      float x[2*N];
+      float tmp[N];
+      /* De-interleaving the sub-frames */
+      for (j=0;j<N;j++)
+         tmp[j] = X[B*j+i];
+      mdct_backward(&st->mdct_lookup, tmp, x);
+      for (j=0;j<2*N;j++)
+         x[j] = st->window[j]*x[j];
+      for (j=0;j<N;j++)
+         st->out_mem[MAX_PERIOD+(i-B)*N+j] = x[j]+st->mdct_overlap[j];
+      for (j=0;j<N;j++)
+         st->mdct_overlap[j] = x[N+j];
+      
+      for (j=0;j<N;j++)
+      {
+         float tmp = st->out_mem[MAX_PERIOD+(i-B)*N+j] + st->preemph*st->preemph_memD;
+         st->preemph_memD = tmp;
+         pcm[i*N+j] = (short)floor(.5+tmp);
+      }
+   }
+
+}
+
 int celt_decode(CELTDecoder *st, char *data, int len, short *pcm)
 {
    int i, N, B;
@@ -390,11 +439,18 @@ int celt_decode(CELTDecoder *st, char *data, int len, short *pcm)
    ec_dec dec;
    ec_byte_buffer buf;
    
+   if (data == NULL)
+   {
+      celt_decode_lost(st, pcm);
+      return 0;
+   }
+   
    ec_byte_readinit(&buf,data,len);
    ec_dec_init(&dec,&buf);
    
    /* Get the pitch index */
    pitch_index = ec_dec_uint(&dec, MAX_PERIOD-(B+1)*N);;
+   st->last_pitch_index = pitch_index;
    
    /* Get band energies */
    unquant_energy(st->mode, bandE, st->oldBandE, &dec);
@@ -449,6 +505,7 @@ int celt_decode(CELTDecoder *st, char *data, int len, short *pcm)
          pcm[i*N+j] = (short)floor(.5+tmp);
       }
    }
+   return 0;
    //printf ("\n");
 }
 
diff --git a/libcelt/testcelt.c b/libcelt/testcelt.c
index c67707be2..b7abc6179 100644
--- a/libcelt/testcelt.c
+++ b/libcelt/testcelt.c
@@ -60,7 +60,10 @@ int main(int argc, char *argv[])
       celt_encode(enc, in);
       data = celt_encoder_get_bytes(enc, &len);
       //printf ("%d\n", len);
-      celt_decode(dec, data, len, in);
+      if (rand()%100==-1)
+         celt_decode(dec, NULL, len, in);
+      else
+         celt_decode(dec, data, len, in);
       fwrite(in, sizeof(short), FRAME_SIZE, fout);
    }
    //data = celt_encoder_get_bytes(enc, &len);
-- 
GitLab