diff libtwamr/gc_pred.c @ 336:7f99b8ed30e5

libtwamr: integrate gc_pred.c
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 18 Apr 2024 23:02:35 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libtwamr/gc_pred.c	Thu Apr 18 23:02:35 2024 +0000
@@ -0,0 +1,376 @@
+/*
+*****************************************************************************
+*
+*      GSM AMR-NB speech codec   R98   Version 7.6.0   December 12, 2001
+*                                R99   Version 3.3.0                
+*                                REL-4 Version 4.1.0                
+*
+*****************************************************************************
+*
+*      File             : gc_pred.c
+*      Purpose          : codebook gain MA prediction
+*
+*****************************************************************************
+*/
+
+/*
+*****************************************************************************
+*                         MODULE INCLUDE FILE AND VERSION ID
+*****************************************************************************
+*/
+#include "namespace.h"
+#include "gc_pred.h"
+
+/*
+*****************************************************************************
+*                         INCLUDE FILES
+*****************************************************************************
+*/
+#include "typedef.h"
+#include "basic_op.h"
+#include "oper_32b.h"
+#include "cnst.h"
+#include "no_count.h"
+#include "log2.h"
+#include "memops.h"
+
+/*
+*****************************************************************************
+*                         LOCAL VARIABLES AND TABLES
+*****************************************************************************
+*/
+
+#define NPRED 4  /* number of prediction taps */
+
+/* MA prediction coefficients (Q13) */
+static const Word16 pred[NPRED] = {5571, 4751, 2785, 1556};
+
+/* average innovation energy.                               */
+/* MEAN_ENER  = 36.0/constant, constant = 20*Log10(2)       */
+#define MEAN_ENER_MR122  783741L  /* 36/(20*log10(2)) (Q17) */
+
+/* MA prediction coefficients (Q6)  */
+static const Word16 pred_MR122[NPRED] = {44, 37, 22, 12};
+
+/* minimum quantized energy: -14 dB */
+#define MIN_ENERGY       -14336       /* 14                 Q10 */
+#define MIN_ENERGY_MR122  -2381       /* 14 / (20*log10(2)) Q10 */ 
+/*
+*****************************************************************************
+*                         PUBLIC PROGRAM CODE
+*****************************************************************************
+*/
+/*************************************************************************
+*
+*  Function:   gc_pred_reset
+*  Purpose:    Initializes state memory to zero
+*
+**************************************************************************
+*/
+void gc_pred_reset (gc_predState *state)
+{
+   Word16 i;
+
+   for(i = 0; i < NPRED; i++)
+   {
+      state->past_qua_en[i] = MIN_ENERGY;
+      state->past_qua_en_MR122[i] = MIN_ENERGY_MR122;
+   }
+}
+
+/*************************************************************************
+ *
+ * FUNCTION:  gc_pred_copy()
+ *
+ * PURPOSE: Copy MA predictor state variable
+ *
+ *************************************************************************/
+void
+gc_pred_copy(
+    gc_predState *st_src,  /* i : State struct                           */
+    gc_predState *st_dest  /* o : State struct                           */
+)
+{
+    Copy (st_src->past_qua_en, st_dest->past_qua_en, NPRED);
+    Copy (st_src->past_qua_en_MR122, st_dest->past_qua_en_MR122, NPRED);
+}
+
+/*************************************************************************
+ *
+ * FUNCTION:  gc_pred()
+ *
+ * PURPOSE: MA prediction of the innovation energy
+ *          (in dB/(20*log10(2))) with mean  removed).
+ *
+ *************************************************************************/
+void
+gc_pred(
+    gc_predState *st,   /* i/o: State struct                           */
+    enum Mode mode,     /* i  : AMR mode                               */
+    Word16 *code,       /* i  : innovative codebook vector (L_SUBFR)   */
+                        /*      MR122: Q12, other modes: Q13           */
+    Word16 *exp_gcode0, /* o  : exponent of predicted gain factor, Q0  */
+    Word16 *frac_gcode0,/* o  : fraction of predicted gain factor  Q15 */
+    Word16 *exp_en,     /* o  : exponent of innovation energy,     Q0  */
+                        /*      (only calculated for MR795)            */
+    Word16 *frac_en     /* o  : fraction of innovation energy,     Q15 */
+                        /*      (only calculated for MR795)            */
+)
+{
+    Word16 i;
+    Word32 ener_code;
+    Word16 exp, frac;
+
+    /*-------------------------------------------------------------------*
+     *  energy of code:                                                  *
+     *  ~~~~~~~~~~~~~~~                                                  *
+     *  ener_code = sum(code[i]^2)                                       *
+     *-------------------------------------------------------------------*/
+    ener_code = L_mac((Word32) 0, code[0], code[0]);
+                                                 /* MR122:  Q12*Q12 -> Q25 */
+                                                 /* others: Q13*Q13 -> Q27 */
+    for (i = 1; i < L_SUBFR; i++)
+        ener_code = L_mac(ener_code, code[i], code[i]);
+    
+    test ();
+    if (sub (mode, MR122) == 0)
+    {
+        Word32 ener;
+
+        /* ener_code = ener_code / lcode; lcode = 40; 1/40 = 26214 Q20       */
+        ener_code = L_mult (round (ener_code), 26214);   /* Q9  * Q20 -> Q30 */
+
+        /*-------------------------------------------------------------------*
+         *  energy of code:                                                  *
+         *  ~~~~~~~~~~~~~~~                                                  *
+         *  ener_code(Q17) = 10 * Log10(energy) / constant                   *
+         *                 = 1/2 * Log2(energy)                              *
+         *                                           constant = 20*Log10(2)  *
+         *-------------------------------------------------------------------*/
+        /* ener_code = 1/2 * Log2(ener_code); Note: Log2=log2+30 */
+        Log2(ener_code, &exp, &frac);
+        ener_code = L_Comp (sub (exp, 30), frac);     /* Q16 for log()    */
+                                                    /* ->Q17 for 1/2 log()*/
+
+        /*-------------------------------------------------------------------*
+         *  predicted energy:                                                *
+         *  ~~~~~~~~~~~~~~~~~                                                *
+         *  ener(Q24) = (Emean + sum{pred[i]*past_en[i]})/constant           *
+         *            = MEAN_ENER + sum(pred[i]*past_qua_en[i])              *
+         *                                           constant = 20*Log10(2)  *
+         *-------------------------------------------------------------------*/
+
+        ener = MEAN_ENER_MR122; move32 ();                  /* Q24 (Q17) */
+        for (i = 0; i < NPRED; i++)
+        {
+            ener = L_mac (ener, st->past_qua_en_MR122[i], pred_MR122[i]);
+                                                     /* Q10 * Q13 -> Q24 */
+                                                     /* Q10 * Q6  -> Q17 */
+        }
+
+        /*-------------------------------------------------------------------*
+         *  predicted codebook gain                                          *
+         *  ~~~~~~~~~~~~~~~~~~~~~~~                                          *
+         *  gc0     = Pow10( (ener*constant - ener_code*constant) / 20 )     *
+         *          = Pow2(ener-ener_code)                                   *
+         *          = Pow2(int(d)+frac(d))                                   *
+         *                                                                   *
+         *  (store exp and frac for pow2())                                  *
+         *-------------------------------------------------------------------*/
+
+        ener = L_shr (L_sub (ener, ener_code), 1);                /* Q16 */
+        L_Extract(ener, exp_gcode0, frac_gcode0);
+    }
+    else /* all modes except 12.2 */
+    {
+        Word32 L_tmp;
+        Word16 exp_code, gcode0;
+        
+        /*-----------------------------------------------------------------*
+         *  Compute: means_ener - 10log10(ener_code/ L_sufr)               *
+         *-----------------------------------------------------------------*/
+
+        exp_code = norm_l (ener_code);
+        ener_code = L_shl (ener_code, exp_code);
+        
+        /* Log2 = log2 + 27 */
+        Log2_norm (ener_code, exp_code, &exp, &frac);
+        
+        /* fact = 10/log2(10) = 3.01 = 24660 Q13 */
+        L_tmp = Mpy_32_16(exp, frac, -24660); /* Q0.Q15 * Q13 -> Q14 */
+
+        /*   L_tmp = means_ener - 10log10(ener_code/L_SUBFR)
+         *         = means_ener - 10log10(ener_code) + 10log10(L_SUBFR)
+         *         = K - fact * Log2(ener_code)
+         *         = K - fact * log2(ener_code) - fact*27
+         *
+         *   ==> K = means_ener + fact*27 + 10log10(L_SUBFR)
+         *
+         *   means_ener =       33    =  540672    Q14  (MR475, MR515, MR59)
+         *   means_ener =       28.75 =  471040    Q14  (MR67)
+         *   means_ener =       30    =  491520    Q14  (MR74)
+         *   means_ener =       36    =  589824    Q14  (MR795)
+         *   means_ener =       33    =  540672    Q14  (MR102)         
+         *   10log10(L_SUBFR) = 16.02 =  262481.51 Q14
+         *   fact * 27                = 1331640    Q14
+         *   -----------------------------------------
+         *   (MR475, MR515, MR59)   K = 2134793.51 Q14 ~= 16678 * 64 * 2
+         *   (MR67)                 K = 2065161.51 Q14 ~= 32268 * 32 * 2
+         *   (MR74)                 K = 2085641.51 Q14 ~= 32588 * 32 * 2
+         *   (MR795)                K = 2183945.51 Q14 ~= 17062 * 64 * 2
+         *   (MR102)                K = 2134793.51 Q14 ~= 16678 * 64 * 2         
+         */
+
+        if (test (), sub (mode, MR102) == 0)
+        {
+            /* mean = 33 dB */
+            L_tmp = L_mac(L_tmp, 16678, 64);     /* Q14 */
+        }
+        else if (test (), sub (mode, MR795) == 0)
+        {
+            /* ener_code  = <xn xn> * 2^27*2^exp_code
+               frac_en    = ener_code / 2^16
+                          = <xn xn> * 2^11*2^exp_code
+               <xn xn>    = <xn xn>*2^11*2^exp * 2^exp_en
+                         := frac_en            * 2^exp_en
+
+               ==> exp_en = -11-exp_code;
+             */
+            *frac_en = extract_h (ener_code); move16 ();
+            *exp_en = sub (-11, exp_code);    move16 ();
+
+            /* mean = 36 dB */
+            L_tmp = L_mac(L_tmp, 17062, 64);     /* Q14 */
+        }
+        else if (test (), sub (mode, MR74) == 0)
+        {
+            /* mean = 30 dB */
+            L_tmp = L_mac(L_tmp, 32588, 32);     /* Q14 */
+        }
+        else if (test (), sub (mode, MR67) == 0)
+        {
+            /* mean = 28.75 dB */
+            L_tmp = L_mac(L_tmp, 32268, 32);     /* Q14 */
+        }
+        else /* MR59, MR515, MR475 */
+        {
+            /* mean = 33 dB */
+            L_tmp = L_mac(L_tmp, 16678, 64);     /* Q14 */
+        }
+        
+        /*-----------------------------------------------------------------*
+         * Compute gcode0.                                                 *
+         *  = Sum(i=0,3) pred[i]*past_qua_en[i] - ener_code + mean_ener    *
+         *-----------------------------------------------------------------*/
+
+        L_tmp = L_shl(L_tmp, 10);                /* Q24 */
+        for (i = 0; i < 4; i++)
+            L_tmp = L_mac(L_tmp, pred[i], st->past_qua_en[i]);
+                                                 /* Q13 * Q10 -> Q24 */
+
+        gcode0 = extract_h(L_tmp);               /* Q8  */
+
+        /*-----------------------------------------------------------------*
+         * gcode0 = pow(10.0, gcode0/20)                                   *
+         *        = pow(2, 3.3219*gcode0/20)                               *
+         *        = pow(2, 0.166*gcode0)                                   *
+         *-----------------------------------------------------------------*/
+
+        /* 5439 Q15 = 0.165985                                        */
+        /* (correct: 1/(20*log10(2)) 0.166096 = 5443 Q15)             */
+        test ();
+        if (sub (mode, MR74) == 0) /* For IS641 bitexactness */
+            L_tmp = L_mult(gcode0, 5439);  /* Q8 * Q15 -> Q24 */
+        else
+            L_tmp = L_mult(gcode0, 5443);  /* Q8 * Q15 -> Q24 */
+
+        L_tmp = L_shr(L_tmp, 8);                   /*          -> Q16 */
+        L_Extract(L_tmp, exp_gcode0, frac_gcode0); /*       -> Q0.Q15 */
+    }
+}
+
+
+/*************************************************************************
+ *
+ * FUNCTION:  gc_pred_update()
+ *
+ * PURPOSE: update MA predictor with last quantized energy
+ *
+ *************************************************************************/
+void gc_pred_update(
+    gc_predState *st,      /* i/o: State struct                     */
+    Word16 qua_ener_MR122, /* i  : quantized energy for update, Q10 */
+                           /*      (log2(qua_err))                  */
+    Word16 qua_ener        /* i  : quantized energy for update, Q10 */
+                           /*      (20*log10(qua_err))              */
+)
+{
+    Word16 i;
+
+    for (i = 3; i > 0; i--)
+    {
+        st->past_qua_en[i] = st->past_qua_en[i - 1];             move16 ();
+        st->past_qua_en_MR122[i] = st->past_qua_en_MR122[i - 1]; move16 ();
+    }
+
+    st->past_qua_en_MR122[0] = qua_ener_MR122;  /*    log2 (qua_err), Q10 */
+	                                                             move16 ();
+    st->past_qua_en[0] = qua_ener;              /* 20*log10(qua_err), Q10 */
+	                                                             move16 ();
+}
+
+/*************************************************************************
+ *
+ * FUNCTION:  gc_pred_average_limited()
+ *
+ * PURPOSE: get average of MA predictor state values (with a lower limit)
+ *          [used in error concealment]
+ *
+ *************************************************************************/
+void gc_pred_average_limited(
+    gc_predState *st,       /* i: State struct                    */
+    Word16 *ener_avg_MR122, /* o: everaged quantized energy,  Q10 */
+                            /*    (log2(qua_err))                 */
+    Word16 *ener_avg        /* o: averaged quantized energy,  Q10 */
+                            /*    (20*log10(qua_err))             */
+)
+{
+    Word16 av_pred_en;
+    Word16 i;
+
+    /* do average in MR122 mode (log2() domain) */
+    av_pred_en = 0;                                        move16 ();
+    for (i = 0; i < NPRED; i++)
+    {
+        av_pred_en = add (av_pred_en, st->past_qua_en_MR122[i]);
+    }
+
+    /* av_pred_en = 0.25*av_pred_en */
+    av_pred_en = mult (av_pred_en, 8192);
+
+    /* if (av_pred_en < -14/(20Log10(2))) av_pred_en = .. */
+    test ();
+    if (sub (av_pred_en, MIN_ENERGY_MR122) < 0)
+    {
+        av_pred_en = MIN_ENERGY_MR122;                     move16 ();
+    }
+    *ener_avg_MR122 = av_pred_en;                          move16 ();
+
+    /* do average for other modes (20*log10() domain) */
+    av_pred_en = 0;                                        move16 ();
+    for (i = 0; i < NPRED; i++)
+    {
+        av_pred_en = add (av_pred_en, st->past_qua_en[i]);
+    }
+
+    /* av_pred_en = 0.25*av_pred_en */
+    av_pred_en = mult (av_pred_en, 8192);
+
+    /* if (av_pred_en < -14) av_pred_en = .. */
+    test ();
+    if (sub (av_pred_en, MIN_ENERGY) < 0)
+    {
+        av_pred_en = MIN_ENERGY;                           move16 ();
+    }
+    *ener_avg = av_pred_en;                                move16 ();
+}