shithub: opus

Download patch

ref: 59dce643b1e79b4b3a15c70a19e6d4992e92b967
parent: 4414db08f953bad0677403bcfa5696cd5c720178
author: Jean-Marc Valin <jmvalin@amazon.com>
date: Thu Sep 15 10:38:13 EDT 2022

More general Laplace encoder

--- a/celt/entdec.c
+++ b/celt/entdec.c
@@ -195,6 +195,27 @@
   return ret;
 }
 
+int ec_dec_icdf16(ec_dec *_this,const opus_uint16 *_icdf,unsigned _ftb){
+  opus_uint32 r;
+  opus_uint32 d;
+  opus_uint32 s;
+  opus_uint32 t;
+  int         ret;
+  s=_this->rng;
+  d=_this->val;
+  r=s>>_ftb;
+  ret=-1;
+  do{
+    t=s;
+    s=IMUL32(r,_icdf[++ret]);
+  }
+  while(d<s);
+  _this->val=d-s;
+  _this->rng=t-s;
+  ec_dec_normalize(_this);
+  return ret;
+}
+
 opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft){
   unsigned ft;
   unsigned s;
--- a/celt/entdec.h
+++ b/celt/entdec.h
@@ -81,6 +81,16 @@
   Return: The decoded symbol s.*/
 int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb);
 
+/*Decodes a symbol given an "inverse" CDF table.
+  No call to ec_dec_update() is necessary after this call.
+  _icdf: The "inverse" CDF, such that symbol s falls in the range
+          [s>0?ft-_icdf[s-1]:0,ft-_icdf[s]), where ft=1<<_ftb.
+         The values must be monotonically non-increasing, and the last value
+          must be 0.
+  _ftb: The number of bits of precision in the cumulative distribution.
+  Return: The decoded symbol s.*/
+int ec_dec_icdf16(ec_dec *_this,const opus_uint16 *_icdf,unsigned _ftb);
+
 /*Extracts a raw unsigned integer with a non-power-of-2 range from the stream.
   The bits must have been encoded with ec_enc_uint().
   No call to ec_dec_update() is necessary after this call.
--- a/celt/entenc.c
+++ b/celt/entenc.c
@@ -172,6 +172,17 @@
   ec_enc_normalize(_this);
 }
 
+void ec_enc_icdf16(ec_enc *_this,int _s,const opus_uint16 *_icdf,unsigned _ftb){
+  opus_uint32 r;
+  r=_this->rng>>_ftb;
+  if(_s>0){
+    _this->val+=_this->rng-IMUL32(r,_icdf[_s-1]);
+    _this->rng=IMUL32(r,_icdf[_s-1]-_icdf[_s]);
+  }
+  else _this->rng-=IMUL32(r,_icdf[_s]);
+  ec_enc_normalize(_this);
+}
+
 void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft){
   unsigned  ft;
   unsigned  fl;
--- a/celt/entenc.h
+++ b/celt/entenc.h
@@ -64,6 +64,15 @@
   _ftb: The number of bits of precision in the cumulative distribution.*/
 void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb);
 
+/*Encodes a symbol given an "inverse" CDF table.
+  _s:    The index of the symbol to encode.
+  _icdf: The "inverse" CDF, such that symbol _s falls in the range
+          [_s>0?ft-_icdf[_s-1]:0,ft-_icdf[_s]), where ft=1<<_ftb.
+         The values must be monotonically non-increasing, and the last value
+          must be 0.
+  _ftb: The number of bits of precision in the cumulative distribution.*/
+void ec_enc_icdf16(ec_enc *_this,int _s,const opus_uint16 *_icdf,unsigned _ftb);
+
 /*Encodes a raw unsigned integer in the stream.
   _fl: The integer to encode.
   _ft: The number of integers that can be encoded (one more than the max).
--- a/celt/laplace.c
+++ b/celt/laplace.c
@@ -132,3 +132,105 @@
    ec_dec_update(dec, fl, IMIN(fl+fs,32768), 32768);
    return val;
 }
+
+
+void ec_laplace_encode_p0(ec_enc *enc, int value, opus_uint16 p0, opus_uint16 decay)
+{
+   int s;
+   opus_uint16 sign_icdf[3];
+   sign_icdf[0] = 32768-p0;
+   sign_icdf[1] = sign_icdf[0]/2;
+   sign_icdf[2] = 0;
+   s = value == 0 ? 0 : (value > 0 ? 1 : 2);
+   ec_enc_icdf16(enc, s, sign_icdf, 15);
+   value = abs(value);
+   if (value)
+   {
+      int i;
+      opus_uint16 icdf[8];
+      icdf[0] = decay;
+      for (i=1;i<7;i++)
+      {
+         icdf[i] = IMAX(7-i, (icdf[i-1] * (opus_int32)decay) >> 15);
+      }
+      icdf[7] = 0;
+      value--;
+      do {
+         ec_enc_icdf16(enc, IMIN(value, 7), icdf, 15);
+         value -= 7;
+      } while (value >= 0);
+   }
+}
+
+int ec_laplace_decode_p0(ec_dec *dec, opus_uint16 p0, opus_uint16 decay)
+{
+   int s;
+   int value;
+   opus_uint16 sign_icdf[3];
+   sign_icdf[0] = 32768-p0;
+   sign_icdf[1] = sign_icdf[0]/2;
+   sign_icdf[2] = 0;
+   s = ec_dec_icdf16(dec, sign_icdf, 15);
+   if (s==2) s = -1;
+   if (s != 0)
+   {
+      int i;
+      int v;
+      opus_uint16 icdf[8];
+      icdf[0] = decay;
+      for (i=1;i<7;i++)
+      {
+         icdf[i] = IMAX(7-i, (icdf[i-1] * (opus_int32)decay) >> 15);
+      }
+      icdf[7] = 0;
+      value = 1;
+      do {
+         v = ec_dec_icdf16(dec, icdf, 15);
+         value += v;
+      } while (v == 7);
+      return s*value;
+   } else return 0;
+}
+
+#if 0
+
+#include <stdio.h>
+#define NB_VALS 10
+#define DATA_SIZE 10000
+int main() {
+   ec_enc enc;
+   ec_dec dec;
+   unsigned char *ptr;
+   int i;
+   int decay, p0;
+   int val[NB_VALS] = {6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+   /*for (i=0;i<NB_VALS;i++) {
+      val[i] = -log(rand()/(float)RAND_MAX);
+      if (rand()%2) val[i] = -val[i];
+   }*/
+   p0 = 16000;
+   decay = 16000;
+   ptr = (unsigned char *)malloc(DATA_SIZE);
+   ec_enc_init(&enc,ptr,DATA_SIZE);
+   for (i=0;i<NB_VALS;i++) {
+      printf("%d ", val[i]);
+   }
+   printf("\n");
+   for (i=0;i<NB_VALS;i++) {
+      ec_laplace_encode_p0(&enc, val[i], p0, decay);
+   }
+
+   ec_enc_done(&enc);
+
+   ec_dec_init(&dec,ec_get_buffer(&enc),ec_range_bytes(&enc));
+
+   for (i=0;i<NB_VALS;i++) {
+      val[i] = ec_laplace_decode_p0(&dec, p0, decay);
+   }
+   for (i=0;i<NB_VALS;i++) {
+      printf("%d ", val[i]);
+   }
+   printf("\n");
+}
+
+#endif
--