/*
 *===================================================================
 *  3GPP AMR Wideband Floating-point Speech Codec
 *===================================================================
 */

#include "typedef.h"
#include "dec_if.h"
#include "if_rom.h"
#include "dec.h"

#define L_FRAME16k   320            /* Frame size at 16kHz  */
#define MODE_7k       0             /* modes                */
#define MODE_9k       1
#define MODE_12k      2
#define MODE_14k      3
#define MODE_16k      4
#define MODE_18k      5
#define MODE_20k      6
#define MODE_23k      7
#define MODE_24k      8
#define MRDTX        9
#define NUM_OF_MODES 10
#define LOST_FRAME   14
#define MRNO_DATA    15
#define EHF_MASK     (Word16)0x0008 /* homing frame pattern */

typedef struct
{
   Word16 reset_flag_old;     /* previous was homing frame  */
   Word16 prev_ft;            /* previous frame type        */
   Word16 prev_mode;          /* previous mode              */
   void *decoder_state;       /* Points decoder state       */
} WB_dec_if_state;

Word16 nb_of_param_first[NUM_OF_SPMODES]=
{
	9,  14, 15,
	15, 15, 19,
	19, 19, 19
};

extern const Word16 mode_7k[];
extern const Word16 mode_9k[];
extern const Word16 mode_12k[];
extern const Word16 mode_14k[];
extern const Word16 mode_16k[];
extern const Word16 mode_18k[];
extern const Word16 mode_20k[];
extern const Word16 mode_23k[];
extern const Word16 mode_24k[];
extern const Word16 mode_DTX[];

extern const Word16 nb_of_param[];

extern const Word16 dfh_M7k[];
extern const Word16 dfh_M9k[];
extern const Word16 dfh_M12k[];
extern const Word16 dfh_M14k[];
extern const Word16 dfh_M16k[];
extern const Word16 dfh_M18k[];
extern const Word16 dfh_M20k[];
extern const Word16 dfh_M23k[];
extern const Word16 dfh_M24k[];

/* overall table with the parameters of the
   decoder homing frames for all modes */

extern Word16 *dhf[10];

/*
 * Decoder_Interface_Homing_Frame_test
 *
 * Parameters:
 *    input_frame    I: input parameters
 *    mode           I: speech mode
 *
 * Function:
 *    Check parameters for matching homing frame
 *
 * Returns:
 *    If homing frame
 */
Word16 D_IF_homing_frame_test(Word16 input_frame[], Word16 mode)
{

   if (mode != MODE_24k)
   {
      /* perform test for COMPLETE parameter frame */
      return (Word16)!memcmp(input_frame, dhf[mode], nb_of_param[mode] * sizeof(Word16));
   }
   else
   {
      /* discard high-band energy */
      return (Word16)!(
         (memcmp(input_frame, dhf[MODE_24k], 19 * sizeof(Word16))) |
         (memcmp(input_frame + 20, dhf[MODE_24k] + 20, 11 * sizeof(Word16))) |
         (memcmp(input_frame + 32, dhf[MODE_24k] + 32, 11 * sizeof(Word16))) |
         (memcmp(input_frame + 44, dhf[MODE_24k] + 44, 11 * sizeof(Word16))) );

   }
}


Word16 D_IF_homing_frame_test_first(Word16 input_frame[], Word16 mode)
{
   /* perform test for FIRST SUBFRAME of parameter frame ONLY */
   return (Word16)!memcmp(input_frame, dhf[mode], nb_of_param_first[mode] * sizeof(Word16));
}

#ifdef IF2
/*
 * D_IF_conversion
 *
 *
 * Parameters:
 *    param             O: AMR parameters
 *    stream            I: input bitstream
 *    frame_type        O: frame type
 *    speech_mode       O: speech mode in DTX
 *    fqi               O: frame quality indicator
 *
 * Function:
 *    Unpacks IF2 octet stream
 *
 * Returns:
 *    mode              used mode
 */
Word16 D_IF_conversion(Word16 *param, UWord8 *stream, UWord8 *frame_type,
                       Word16 *speech_mode, Word16 *fqi)
{
   Word32 mode;
   Word32 j;
   Word16 const *mask;

   memset(param, 0, PRMNO_24k << 1);
   mode = *stream >> 4;
   *fqi = (Word16)((*stream >> 3) & 0x1);
   *stream <<= (HEADER_SIZE - 1);

   switch (mode)
   {
   case MRDTX:
      mask = mode_DTX;

      for (j = HEADER_SIZE; j < T_NBBITS_SID; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }

         mask += 2;

         if ( j % 8 )
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }
      }

      /* get SID type bit */

      *frame_type = RX_SID_FIRST;

      if (*stream & 0x80)
      {
         *frame_type = RX_SID_UPDATE;
      }

      *stream <<= 1;

      /* speech mode indicator */
      *speech_mode = (Word16)(*stream >> 4);
      break;

   case MRNO_DATA:
      *frame_type = RX_NO_DATA;
      break;

   case LOST_FRAME:
      *frame_type = RX_SPEECH_LOST;
      break;

   case MODE_7k:
      mask = mode_7k;

      for (j = HEADER_SIZE; j < T_NBBITS_7k; j++)
      {
         if ( *stream & 0x80 )
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }
         mask += 2;

         if (j % 8)
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }
      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   case MODE_9k:
      mask = mode_9k;

      for (j = HEADER_SIZE; j < T_NBBITS_9k; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }
         mask += 2;

         if (j % 8)
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }
      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   case MODE_12k:
      mask = mode_12k;

      for (j = HEADER_SIZE; j < T_NBBITS_12k; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }
         mask += 2;

         if ( j % 8 )
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }
      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   case MODE_14k:
      mask = mode_14k;

      for (j = HEADER_SIZE; j < T_NBBITS_14k; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }

         mask += 2;

         if ( j % 8 )
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }
      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   case MODE_16k:
      mask = mode_16k;

      for (j = HEADER_SIZE; j < T_NBBITS_16k; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }

         mask += 2;

         if (j % 8)
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }
      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   case MODE_18k:
      mask = mode_18k;

      for (j = HEADER_SIZE; j < T_NBBITS_18k; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }

         mask += 2;

         if (j % 8)
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }
      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   case MODE_20k:
      mask = mode_20k;

      for (j = HEADER_SIZE; j < T_NBBITS_20k; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }

         mask += 2;

         if (j % 8)
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }
      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   case MODE_23k:
      mask = mode_23k;

      for (j = HEADER_SIZE; j < T_NBBITS_23k; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }

         mask += 2;

         if (j % 8)
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }

      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   case MODE_24k:
      mask = mode_24k;

      for (j = HEADER_SIZE; j < T_NBBITS_24k; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }

         mask += 2;

         if (j % 8)
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }

      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   default:
      *frame_type = RX_SPEECH_LOST;
      *fqi = 0;
      break;

   }

   if (*fqi == 0)
   {
      if (*frame_type == RX_SPEECH_GOOD)
      {
         *frame_type = RX_SPEECH_BAD;
      }
      if ((*frame_type == RX_SID_FIRST) | (*frame_type == RX_SID_UPDATE))
      {
         *frame_type = RX_SID_BAD;
      }
   }

   return (Word16)mode;
}

#else

/*
 * D_IF_mms_conversion
 *
 *
 * Parameters:
 *    param             O: AMR parameters
 *    stream            I: input bitstream
 *    frame_type        O: frame type
 *    speech_mode       O: speech mode in DTX
 *    fqi               O: frame quality indicator
 *
 * Function:
 *    Unpacks MMS formatted octet stream (see RFC 3267, section 5.3)
 *
 * Returns:
 *    mode              used mode
 */
Word16 D_IF_mms_conversion(Word16 *param, UWord8 *stream, UWord8 *frame_type,
                           Word16 *speech_mode, Word16 *fqi)
{
   Word32 mode;
   Word32 j;
   Word16 const *mask;

   memset(param, 0, PRMNO_24k << 1);

   *fqi = (Word16)((*stream >> 2) & 0x01);
   mode = (Word32)((*stream >> 3) & 0x0F);

   stream++;

   switch (mode)
   {
   case MRDTX:
      mask = mode_DTX;

      for (j = 1; j <= NBBITS_SID; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }

         mask += 2;

         if ( j % 8 )
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }
      }

      /* get SID type bit */

      *frame_type = RX_SID_FIRST;

      if (*stream & 0x80)
      {
         *frame_type = RX_SID_UPDATE;
      }

      *stream <<= 1;

      /* speech mode indicator */
      *speech_mode = (Word16)(*stream >> 4);
      break;

   case MRNO_DATA:
      *frame_type = RX_NO_DATA;
      break;

   case LOST_FRAME:
      *frame_type = RX_SPEECH_LOST;
      break;

   case MODE_7k:
      mask = mode_7k;

      for (j = 1; j <= NBBITS_7k; j++)
      {
         if ( *stream & 0x80 )
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }
         mask += 2;

         if (j % 8)
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }
      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   case MODE_9k:
      mask = mode_9k;

      for (j = 1; j <= NBBITS_9k; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }
         mask += 2;

         if (j % 8)
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }
      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   case MODE_12k:
      mask = mode_12k;

      for (j = 1; j <= NBBITS_12k; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }
         mask += 2;

         if ( j % 8 )
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }
      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   case MODE_14k:
      mask = mode_14k;

      for (j = 1; j <= NBBITS_14k; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }

         mask += 2;

         if ( j % 8 )
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }
      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   case MODE_16k:
      mask = mode_16k;

      for (j = 1; j <= NBBITS_16k; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }

         mask += 2;

         if (j % 8)
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }
      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   case MODE_18k:
      mask = mode_18k;

      for (j = 1; j <= NBBITS_18k; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }

         mask += 2;

         if (j % 8)
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }
      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   case MODE_20k:
      mask = mode_20k;

      for (j = 1; j <= NBBITS_20k; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }

         mask += 2;

         if (j % 8)
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }
      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   case MODE_23k:
      mask = mode_23k;

      for (j = 1; j <= NBBITS_23k; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }

         mask += 2;

         if (j % 8)
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }

      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   case MODE_24k:
      mask = mode_24k;

      for (j = 1; j <= NBBITS_24k; j++)
      {
         if (*stream & 0x80)
         {
            param[*mask] = (Word16)(param[*mask] + *(mask + 1));
         }

         mask += 2;

         if (j % 8)
         {
            *stream <<= 1;
         }
         else
         {
            stream++;
         }

      }

      *frame_type = RX_SPEECH_GOOD;
      break;

   default:
      *frame_type = RX_SPEECH_LOST;
      *fqi = 0;
      break;

   }

   if (*fqi == 0)
   {
      if (*frame_type == RX_SPEECH_GOOD)
      {
         *frame_type = RX_SPEECH_BAD;
      }
      if ((*frame_type == RX_SID_FIRST) | (*frame_type == RX_SID_UPDATE))
      {
         *frame_type = RX_SID_BAD;
      }
   }

   return (Word16)mode;
}

#endif

/*
 * D_IF_decode
 *
 *
 * Parameters:
 *    st       B: pointer to state structure
 *    bits     I: bitstream form the encoder
 *    synth    O: decoder output
 *    lfi      I: lost frame indicator
 *                _good_frame, _bad_frame, _lost_frame, _no_frame
 *
 * Function:
 *    Decoding one frame of speech. Lost frame indicator can be used
 *    to inform encoder about the problems in the received frame.
 *    _good_frame:good speech or sid frame is received.
 *    _bad_frame: frame with possible bit errors
 *    _lost_frame:speech of sid frame is lost in transmission
 *    _no_frame:  indicates non-received frames in dtx-operation
 * Returns:
 *
 */
void D_IF_decode( void *st, UWord8 *bits, Word16 *synth, Word32 lfi)
{
   Word32 i;
   Word16 mode = 0;                 /* AMR mode                */
   Word16 speech_mode = MODE_7k;    /* speech mode             */
   Word16 fqi;                      /* frame quality indicator */

   Word16 prm[PRMNO_24k];           /* AMR parameters          */

   UWord8 frame_type;               /* frame type              */
   Word16 reset_flag = 0;           /* reset flag              */
   WB_dec_if_state * s;             /* pointer to structure    */

   s = (WB_dec_if_state*)st;

   /* bits -> param, if needed */
   if ((lfi == _good_frame) | (lfi == _bad_frame))
   {
      /* add fqi data */
#ifdef IF2
      *bits = (UWord8)((Word32)*bits & ~(lfi << 3));
#else
      *bits = (UWord8)((Word32)*bits & ~(lfi << 2));
#endif
      /*
       * extract mode information and frame_type,
       * octets to parameters
       */
#ifdef IF2
      mode = D_IF_conversion( prm, bits, &frame_type, &speech_mode, &fqi);
#else
      mode = D_IF_mms_conversion( prm, bits, &frame_type, &speech_mode, &fqi);
#endif

   }
   else if (lfi == _no_frame)
   {
      frame_type = RX_NO_DATA;
   }
   else
   {
      frame_type = RX_SPEECH_LOST;
   }

   /*
    * if no mode information
    * guess one from the previous frame
    */
   if ((frame_type == RX_SPEECH_LOST) | (frame_type == RX_NO_DATA))
   {
      mode = s->prev_mode;
   }

   if (mode == MRDTX)
   {
      mode = speech_mode;
   }

   /* if homed: check if this frame is another homing frame */
   if (s->reset_flag_old == 1)
   {
      /* only check until end of first subframe */
      reset_flag = D_IF_homing_frame_test_first(prm, mode);
   }

   /* produce encoder homing frame if homed & input=decoder homing frame */
   if ((reset_flag != 0) && (s->reset_flag_old != 0))
   {
      for (i = 0; i < L_FRAME16k; i++)
      {
         synth[i] = EHF_MASK;
      }
   }
   else
   {
      D_MAIN_decode(mode, prm, synth, s->decoder_state, frame_type);
   }

   for (i = 0; i < L_FRAME16k; i++)   /* Delete the 2 LSBs (14-bit input) */
   {
      synth[i] = (Word16) (synth[i] & 0xfffC);
   }

   /* if not homed: check whether current frame is a homing frame */
   if ((s->reset_flag_old == 0) & (mode < 9))
   {
      /* check whole frame */
      reset_flag = D_IF_homing_frame_test(prm, mode);
   }
   /* reset decoder if current frame is a homing frame */
   if (reset_flag != 0)
   {
      D_MAIN_reset(s->decoder_state, 1);
   }
   s->reset_flag_old = reset_flag;

   s->prev_ft = frame_type;
   s->prev_mode = mode;
}

/*
 * D_IF_reset
 *
 * Parameters:
 *    st                O: state struct
 *
 * Function:
 *    Reset homing frame counter
 *
 * Returns:
 *    void
 */
void D_IF_reset(WB_dec_if_state *st)
{
   st->reset_flag_old = 1;
   st->prev_ft = RX_SPEECH_GOOD;
   st->prev_mode = MODE_7k;   /* minimum bitrate */
}

/*
 * D_IF_init
 *
 * Parameters:
 *
 * Function:
 *    Allocates state memory and initializes state memory
 *
 * Returns:
 *    pointer to encoder interface structure
 */
void *D_IF_init( void)
{
   WB_dec_if_state *s = NULL;

   /* allocate memory */
   if ((s = (WB_dec_if_state*) malloc(sizeof(WB_dec_if_state))) == NULL)
   {
      return NULL;
   }

   D_MAIN_init(&(s->decoder_state));
   if (s->decoder_state == NULL)
   {
      free(s);
      return NULL;
   }

   D_IF_reset(s);

   return s;
}

/*
 * D_IF_exit
 *
 * Parameters:
 *    state             I: state structure
 *
 * Function:
 *    The memory used for state memory is freed
 *
 * Returns:
 *    Void
 */
void D_IF_exit(void *state)
{
   WB_dec_if_state *s;

   s = (WB_dec_if_state *)state;

   /* free memory */
   D_MAIN_close(&s->decoder_state);
   free(s);
   state = NULL;
}
