view libtwamr/cod_amr.c @ 585:3c6bf0d26ee7 default tip

TW-TS-005 reader: fix maximum line length bug TW-TS-005 section 4.1 states: The maximum allowed length of each line is 80 characters, not including the OS-specific newline encoding. The implementation of this line length limit in the TW-TS-005 hex file reader function in the present suite was wrong, such that lines of the full maximum length could not be read. Fix it. Note that this bug affects comment lines too, not just actual RTP payloads. Neither Annex A nor Annex B features an RTP payload format that goes to the maximum of 40 bytes, but if a comment line goes to the maximum allowed length of 80 characters not including the terminating newline, the bug will be triggered, necessitating the present fix.
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 25 Feb 2025 07:49:28 +0000
parents 93d6c6960a46
children
line wrap: on
line source

/*
*****************************************************************************
*
*      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             : cod_amr.c
*      Purpose          : Main encoder routine operating on a frame basis.
*
*****************************************************************************
*/
#include "namespace.h"
#include "cod_amr.h"

/*
*****************************************************************************
*                         INCLUDE FILES
*****************************************************************************
*/

#include "typedef.h"
#include "basic_op.h"
#include "no_count.h"
#include "cnst.h"
#include "memops.h"
#include "qua_gain.h"

#include "lpc.h"
#include "lsp.h"
#include "pre_big.h"
#include "ol_ltp.h"
#include "p_ol_wgh.h"
#include "spreproc.h"
#include "cl_ltp.h"
#include "pred_lt.h"
#include "spstproc.h"
#include "cbsearch.h"
#include "gain_q.h"
#include "convolve.h"
#include "ton_stab.h"
#include "vad.h"
#include "dtx_enc.h"

/*
*****************************************************************************
*                         LOCAL VARIABLES AND TABLES
*****************************************************************************
*/

/*
*****************************************************************************
*                         PUBLIC VARIABLES AND TABLES
*****************************************************************************
*/
/* Spectral expansion factors */

static const Word16 gamma1[M] =
{
   30802, 28954, 27217, 25584, 24049,
   22606, 21250, 19975, 18777, 17650
};

/* gamma1 differs for the 12k2 coder */
static const Word16 gamma1_12k2[M] =
{
    29491, 26542, 23888, 21499, 19349,
    17414, 15672, 14105, 12694, 11425
};

static const Word16 gamma2[M] =
{
   19661, 11797, 7078, 4247, 2548,
   1529, 917, 550, 330, 198
};

/*
*****************************************************************************
*                         PUBLIC PROGRAM CODE
*****************************************************************************
*/
 
/*
**************************************************************************
*
*  Function    : cod_amr_reset
*  Purpose     : Resets state memory
*
**************************************************************************
*/
void cod_amr_reset (cod_amrState *st, Flag dtx, Flag use_vad2)
{
   Word16 i;

   /* save DTX flag */
   st->dtx = dtx;

   /*-----------------------------------------------------------------------*
    *          Initialize pointers to speech vector.                        *
    *-----------------------------------------------------------------------*/

   st->new_speech = st->old_speech + L_TOTAL - L_FRAME;   /* New speech     */
   
   st->speech = st->new_speech - L_NEXT;                  /* Present frame  */
   
   st->p_window = st->old_speech + L_TOTAL - L_WINDOW;    /* For LPC window */
   st->p_window_12k2 = st->p_window - L_NEXT; /* EFR LPC window: no lookahead */

   /* Initialize static pointers */
   
   st->wsp = st->old_wsp + PIT_MAX;
   st->exc = st->old_exc + PIT_MAX + L_INTERPOL;
   st->zero = st->ai_zero + MP1;
   st->error = st->mem_err + M;
   st->h1 = &st->hvec[L_SUBFR];
   
   /* Static vectors to zero */
   
   Set_zero(st->old_speech, L_TOTAL);
   Set_zero(st->old_exc,    PIT_MAX + L_INTERPOL);
   Set_zero(st->old_wsp,    PIT_MAX);
   Set_zero(st->mem_syn,    M);
   Set_zero(st->mem_w,      M);
   Set_zero(st->mem_w0,     M);
   Set_zero(st->mem_err,    M);
   Set_zero(st->zero,       L_SUBFR);
   Set_zero(st->hvec,       L_SUBFR);    /* set to zero "h1[-L_SUBFR..-1]" */

   /* OL LTP states */
   for (i = 0; i < 5; i++)
   {
      st->old_lags[i] = 40; 
   }

   /* Reset lpc states */
   lpc_reset(&st->lpcSt);

   /* Reset lsp states */
   lsp_reset(&st->lspSt);

   /* Reset clLtp states */
   cl_ltp_reset(&st->clLtpSt);

   gainQuant_reset(&st->gainQuantSt);

   p_ol_wgh_reset(&st->pitchOLWghtSt);

   ton_stab_reset(&st->tonStabSt);   

   vad_reset(&st->vadSt, use_vad2);

   dtx_enc_reset(&st->dtx_encSt);

   st->sharp = SHARPMIN;
}
 
/***************************************************************************
 *   FUNCTION:   cod_amr_first
 *
 *   PURPOSE:  Copes with look-ahead.
 *
 *   INPUTS:
 *       No input argument are passed to this function. However, before
 *       calling this function, 40 new speech data should be copied to the
 *       vector new_speech[]. This is a global pointer which is declared in
 *       this file (it points to the end of speech buffer minus 200).
 *
 ***************************************************************************/
 
int cod_amr_first(cod_amrState *st,     /* i/o : State struct           */
                  Word16 new_speech[])  /* i   : speech input (L_FRAME) */
{ 
   Copy(new_speech,&st->new_speech[-L_NEXT], L_NEXT);
   /*   Copy(new_speech,st->new_speech,L_FRAME); */
  
   return 0;
}


/***************************************************************************
 *   FUNCTION: cod_amr
 *
 *   PURPOSE:  Main encoder routine.
 *
 *   DESCRIPTION: This function is called every 20 ms speech frame,
 *       operating on the newly read 160 speech samples. It performs the
 *       principle encoding functions to produce the set of encoded parameters
 *       which include the LSP, adaptive codebook, and fixed codebook
 *       quantization indices (addresses and gains).
 *
 *   INPUTS:
 *       No input argument are passed to this function. However, before
 *       calling this function, 160 new speech data should be copied to the
 *       vector new_speech[]. This is a global pointer which is declared in
 *       this file (it points to the end of speech buffer minus 160).
 *
 *   OUTPUTS:
 *
 *       ana[]:     vector of analysis parameters.
 *       synth[]:   Local synthesis speech (for debugging purposes)
 *
 ***************************************************************************/
int cod_amr(
    cod_amrState *st,          /* i/o : State struct                   */
    enum Mode mode,            /* i   : AMR mode                       */
    Word16 new_speech[],       /* i   : speech input (L_FRAME)         */
    Word16 ana[],              /* o   : Analysis parameters            */
    enum Mode *usedMode,       /* o   : used mode                    */
    Word16 synth[]             /* o   : Local synthesis                */
)
{
   /* LPC coefficients */
   Word16 A_t[(MP1) * 4];      /* A(z) unquantized for the 4 subframes */
   Word16 Aq_t[(MP1) * 4];     /* A(z)   quantized for the 4 subframes */
   Word16 *A, *Aq;             /* Pointer on A_t and Aq_t              */
   Word16 lsp_new[M];
   
   /* Other vectors */
   Word16 xn[L_SUBFR];         /* Target vector for pitch search       */
   Word16 xn2[L_SUBFR];        /* Target vector for codebook search    */
   Word16 code[L_SUBFR];       /* Fixed codebook excitation            */
   Word16 y1[L_SUBFR];         /* Filtered adaptive excitation         */
   Word16 y2[L_SUBFR];         /* Filtered fixed codebook excitation   */
   Word16 gCoeff[6];           /* Correlations between xn, y1, & y2:   */
   Word16 res[L_SUBFR];        /* Short term (LPC) prediction residual */
   Word16 res2[L_SUBFR];       /* Long term (LTP) prediction residual  */

   /* Vector and scalars needed for the MR475 */
   Word16 xn_sf0[L_SUBFR];     /* Target vector for pitch search       */
   Word16 y2_sf0[L_SUBFR];     /* Filtered codebook innovation         */   
   Word16 code_sf0[L_SUBFR];   /* Fixed codebook excitation            */
   Word16 h1_sf0[L_SUBFR];     /* The impulse response of sf0          */
   Word16 mem_syn_save[M];     /* Filter memory                        */
   Word16 mem_w0_save[M];      /* Filter memory                        */
   Word16 mem_err_save[M];     /* Filter memory                        */
   Word16 sharp_save;          /* Sharpening                           */
   Word16 evenSubfr;           /* Even subframe indicator              */ 
   Word16 T0_sf0 = 0;          /* Integer pitch lag of sf0             */  
   Word16 T0_frac_sf0 = 0;     /* Fractional pitch lag of sf0          */  
   Word16 i_subfr_sf0 = 0;     /* Position in exc[] for sf0            */
   Word16 gain_pit_sf0;        /* Quantized pitch gain for sf0         */
   Word16 gain_code_sf0;       /* Quantized codebook gain for sf0      */
    
   /* Scalars */
   Word16 i_subfr, subfrNr;
   Word16 T_op[L_FRAME/L_FRAME_BY2];
   Word16 T0, T0_frac;
   Word16 gain_pit, gain_code;

   /* Flags */
   Word16 lsp_flag = 0;        /* indicates resonance in LPC filter */   
   Word16 gp_limit;            /* pitch gain limit value            */
   Word16 vad_flag;            /* VAD decision flag                 */
   Word16 compute_sid_flag;    /* SID analysis  flag                 */

   Copy(new_speech, st->new_speech, L_FRAME);

   *usedMode = mode;                     move16 ();

   /* DTX processing */
   if (st->dtx)
   {  /* no test() call since this if is only in simulation env */
      /* Find VAD decision */

      if (st->vadSt.use_vad2) {
         vad_flag = vad2(st->new_speech,    &st->vadSt.u.v2);
         vad_flag = vad2(st->new_speech+80, &st->vadSt.u.v2) || vad_flag;
      } else {
         vad_flag = vad1(&st->vadSt.u.v1, st->new_speech);     
      }

      /* NB! usedMode may change here */
      compute_sid_flag = tx_dtx_handler(&st->dtx_encSt,
                                        vad_flag, 
                                        usedMode);
   }
   else 
   {
      compute_sid_flag = 0;              move16 ();
   }
   
   /*------------------------------------------------------------------------*
    *  - Perform LPC analysis:                                               *
    *       * autocorrelation + lag windowing                                *
    *       * Levinson-durbin algorithm to find a[]                          *
    *       * convert a[] to lsp[]                                           *
    *       * quantize and code the LSPs                                     *
    *       * find the interpolated LSPs and convert to a[] for all          *
    *         subframes (both quantized and unquantized)                     *
    *------------------------------------------------------------------------*/
   
   /* LP analysis */
   lpc(&st->lpcSt, mode, st->p_window, st->p_window_12k2, A_t);

   /* From A(z) to lsp. LSP quantization and interpolation */
   lsp(&st->lspSt, mode, *usedMode, A_t, Aq_t, lsp_new, &ana);

   /* Buffer lsp's and energy */
   dtx_buffer(&st->dtx_encSt,
	      lsp_new,
	      st->new_speech);

   /* Check if in DTX mode */
   test();
   if (sub(*usedMode, MRDTX) == 0)
   {
      dtx_enc(&st->dtx_encSt,
              compute_sid_flag,
              &st->lspSt.qSt, 
              &st->gainQuantSt.gc_predSt,
              &ana);
      
      Set_zero(st->old_exc,    PIT_MAX + L_INTERPOL);
      Set_zero(st->mem_w0,     M);
      Set_zero(st->mem_err,    M);
      Set_zero(st->zero,       L_SUBFR);
      Set_zero(st->hvec,       L_SUBFR);    /* set to zero "h1[-L_SUBFR..-1]" */
      /* Reset lsp states */
      lsp_reset(&st->lspSt);
      Copy(lsp_new, st->lspSt.lsp_old, M);
      Copy(lsp_new, st->lspSt.lsp_old_q, M);
      
      /* Reset clLtp states */
      cl_ltp_reset(&st->clLtpSt);
      st->sharp = SHARPMIN;
   }
   else
   {
       /* check resonance in the filter */
      lsp_flag = check_lsp(&st->tonStabSt, st->lspSt.lsp_old);
   }
   
   /*----------------------------------------------------------------------*
    * - Find the weighted input speech w_sp[] for the whole speech frame   *
    * - Find the open-loop pitch delay for first 2 subframes               *
    * - Set the range for searching closed-loop pitch in 1st subframe      *
    * - Find the open-loop pitch delay for last 2 subframes                *
    *----------------------------------------------------------------------*/

   if (st->dtx && st->vadSt.use_vad2)
   {  /* no test() call since this if is only in simulation env */
       st->vadSt.u.v2.L_Rmax = 0;
       st->vadSt.u.v2.L_R0 = 0;
   }
   for(subfrNr = 0, i_subfr = 0; 
       subfrNr < L_FRAME/L_FRAME_BY2; 
       subfrNr++, i_subfr += L_FRAME_BY2)
   {
      /* Pre-processing on 80 samples */
      pre_big(mode, gamma1, gamma1_12k2, gamma2, A_t, i_subfr, st->speech,
              st->mem_w, st->wsp);
    
      test (); test ();
      if ((sub(mode, MR475) != 0) && (sub(mode, MR515) != 0))
      {
         /* Find open loop pitch lag for two subframes */
         ol_ltp(&st->pitchOLWghtSt, &st->vadSt, mode, &st->wsp[i_subfr],
                &T_op[subfrNr], st->old_lags, st->ol_gain_flg, subfrNr,
                st->dtx);
      }
   }

   if ((sub(mode, MR475) == 0) || (sub(mode, MR515) == 0))
   {
      /* Find open loop pitch lag for ONE FRAME ONLY */
      /* search on 160 samples */
      
      ol_ltp(&st->pitchOLWghtSt, &st->vadSt, mode, &st->wsp[0], &T_op[0],
             st->old_lags, st->ol_gain_flg, 1, st->dtx);
      T_op[1] = T_op[0];
   }         

   if (st->dtx && st->vadSt.use_vad2)
   {  /* no test() call since this if is only in simulation env */
      LTP_flag_update(&st->vadSt.u.v2, mode);
   }

   /* run VAD pitch detection */
   if (st->dtx && !st->vadSt.use_vad2)
   {  /* no test() call since this if is only in simulation env */
      vad_pitch_detection(&st->vadSt.u.v1, T_op);
   } 

   if (sub(*usedMode, MRDTX) == 0)
   {
      goto the_end;
   }
   
   /*------------------------------------------------------------------------*
    *          Loop for every subframe in the analysis frame                 *
    *------------------------------------------------------------------------*
    *  To find the pitch and innovation parameters. The subframe size is     *
    *  L_SUBFR and the loop is repeated L_FRAME/L_SUBFR times.               *
    *     - find the weighted LPC coefficients                               *
    *     - find the LPC residual signal res[]                               *
    *     - compute the target signal for pitch search                       *
    *     - compute impulse response of weighted synthesis filter (h1[])     *
    *     - find the closed-loop pitch parameters                            *
    *     - encode the pitch dealy                                           *
    *     - update the impulse response h1[] by including fixed-gain pitch   *
    *     - find target vector for codebook search                           *
    *     - codebook search                                                  *
    *     - encode codebook address                                          *
    *     - VQ of pitch and codebook gains                                   *
    *     - find synthesis speech                                            *
    *     - update states of weighting filter                                *
    *------------------------------------------------------------------------*/

   A = A_t;      /* pointer to interpolated LPC parameters */
   Aq = Aq_t;    /* pointer to interpolated quantized LPC parameters */

   evenSubfr = 0;                                                  move16 ();
   subfrNr = -1;                                                   move16 ();
   for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR)
   {
      subfrNr = add(subfrNr, 1);
      evenSubfr = sub(1, evenSubfr);

      /* Save states for the MR475 mode */
      test(); test();
      if ((evenSubfr != 0) && (sub(*usedMode, MR475) == 0))
      {
         Copy(st->mem_syn, mem_syn_save, M);
         Copy(st->mem_w0, mem_w0_save, M);         
         Copy(st->mem_err, mem_err_save, M);         
         sharp_save = st->sharp;
      }
      
      /*-----------------------------------------------------------------*
       * - Preprocessing of subframe                                     *
       *-----------------------------------------------------------------*/
      if (sub(*usedMode, MR475) != 0)
      {
         subframePreProc(*usedMode, gamma1, gamma1_12k2,
                         gamma2, A, Aq, &st->speech[i_subfr],
                         st->mem_err, st->mem_w0, st->zero,
                         st->ai_zero, &st->exc[i_subfr],
                         st->h1, xn, res, st->error);
      }
      else
      { /* MR475 */
         subframePreProc(*usedMode, gamma1, gamma1_12k2, 
                         gamma2, A, Aq, &st->speech[i_subfr],
                         st->mem_err, mem_w0_save, st->zero,
                         st->ai_zero, &st->exc[i_subfr],
                         st->h1, xn, res, st->error);

         /* save impulse response (modified in cbsearch) */
         if (evenSubfr != 0)
         {
             Copy (st->h1, h1_sf0, L_SUBFR);
         }
      }
      
      /* copy the LP residual (res2 is modified in the CL LTP search)    */
      Copy (res, res2, L_SUBFR);

      /*-----------------------------------------------------------------*
       * - Closed-loop LTP search                                        *
       *-----------------------------------------------------------------*/
      cl_ltp(&st->clLtpSt, &st->tonStabSt, *usedMode, i_subfr, T_op, st->h1, 
             &st->exc[i_subfr], res2, xn, lsp_flag, xn2, y1, 
             &T0, &T0_frac, &gain_pit, gCoeff, &ana,
             &gp_limit);

      /* update LTP lag history */
      if ((subfrNr == 0) && (st->ol_gain_flg[0] > 0))
      {
         st->old_lags[1] = T0;
      }
      
      if ((sub(subfrNr, 3) == 0) && (st->ol_gain_flg[1] > 0))
      {
         st->old_lags[0] = T0;
      }      

      /*-----------------------------------------------------------------*
       * - Inovative codebook search (find index and gain)               *
       *-----------------------------------------------------------------*/
      cbsearch(xn2, st->h1, T0, st->sharp, gain_pit, res2, 
               code, y2, &ana, *usedMode, subfrNr);

      /*------------------------------------------------------*
       * - Quantization of gains.                             *
       *------------------------------------------------------*/
      gainQuant(&st->gainQuantSt, *usedMode, res, &st->exc[i_subfr], code,
                xn, xn2,  y1, y2, gCoeff, evenSubfr, gp_limit,
                &gain_pit_sf0, &gain_code_sf0,
                &gain_pit, &gain_code, &ana);

      /* update gain history */
      update_gp_clipping(&st->tonStabSt, gain_pit);

      if (sub(*usedMode, MR475) != 0)
      {
         /* Subframe Post Porcessing */
         subframePostProc(st->speech, *usedMode, i_subfr, gain_pit,
                          gain_code, Aq, synth, xn, code, y1, y2, st->mem_syn,
                          st->mem_err, st->mem_w0, st->exc, &st->sharp);
      }
      else
      {
         if (evenSubfr != 0)
         {
            i_subfr_sf0 = i_subfr;             move16 ();
            Copy(xn, xn_sf0, L_SUBFR);
            Copy(y2, y2_sf0, L_SUBFR);          
            Copy(code, code_sf0, L_SUBFR);
            T0_sf0 = T0;                       move16 ();
            T0_frac_sf0 = T0_frac;             move16 ();
            
            /* Subframe Post Porcessing */
            subframePostProc(st->speech, *usedMode, i_subfr, gain_pit,
                             gain_code, Aq, synth, xn, code, y1, y2,
                             mem_syn_save, st->mem_err, mem_w0_save,
                             st->exc, &st->sharp);
            st->sharp = sharp_save;                         move16();
         }
         else
         {
            /* update both subframes for the MR475 */
            
            /* Restore states for the MR475 mode */
            Copy(mem_err_save, st->mem_err, M);         
            
            /* re-build excitation for sf 0 */
            Pred_lt_3or6(&st->exc[i_subfr_sf0], T0_sf0, T0_frac_sf0,
                         L_SUBFR, 1);
            Convolve(&st->exc[i_subfr_sf0], h1_sf0, y1, L_SUBFR);
            
            Aq -= MP1;
            subframePostProc(st->speech, *usedMode, i_subfr_sf0,
                             gain_pit_sf0, gain_code_sf0, Aq,
                             synth, xn_sf0, code_sf0, y1, y2_sf0,
                             st->mem_syn, st->mem_err, st->mem_w0, st->exc,
                             &sharp_save); /* overwrites sharp_save */
            Aq += MP1;
            
            /* re-run pre-processing to get xn right (needed by postproc) */
            /* (this also reconstructs the unsharpened h1 for sf 1)       */
            subframePreProc(*usedMode, gamma1, gamma1_12k2,
                            gamma2, A, Aq, &st->speech[i_subfr],
                            st->mem_err, st->mem_w0, st->zero,
                            st->ai_zero, &st->exc[i_subfr],
                            st->h1, xn, res, st->error);
            
            /* re-build excitation sf 1 (changed if lag < L_SUBFR) */
            Pred_lt_3or6(&st->exc[i_subfr], T0, T0_frac, L_SUBFR, 1);
            Convolve(&st->exc[i_subfr], st->h1, y1, L_SUBFR);
            
            subframePostProc(st->speech, *usedMode, i_subfr, gain_pit,
                             gain_code, Aq, synth, xn, code, y1, y2,
                             st->mem_syn, st->mem_err, st->mem_w0,
                             st->exc, &st->sharp);
         }
      }      
               
      A += MP1;    /* interpolated LPC parameters for next subframe */
      Aq += MP1;
   }

   Copy(&st->old_exc[L_FRAME], &st->old_exc[0], PIT_MAX + L_INTERPOL);
   
the_end:
   
   /*--------------------------------------------------*
    * Update signal for next frame.                    *
    *--------------------------------------------------*/
   Copy(&st->old_wsp[L_FRAME], &st->old_wsp[0], PIT_MAX);
   
   Copy(&st->old_speech[L_FRAME], &st->old_speech[0], L_TOTAL - L_FRAME);

   return 0;
}