#ifndef G711PLC_H_
#define G711PLC_H_
/*---------------------------------------------------------------------------*/
/* g711plc.h                                                                 */
/* copyright (c) innovaphone 2012                                            */
/*                                                                           */
/* Packet loss concealment based on correlation analysis                     */
/*---------------------------------------------------------------------------*/

NAMESPACE_BEGIN

#define G711PLC_VOCAL_PERIOD_MIN        40      /* 200 Hz */
#define G711PLC_VOCAL_PERIOD_MAX        120     /* 66 Hz */
#define G711PLC_CORRELATION_LENGTH      160     /* 20 ms */
#define G711PLC_CORRELATION_BUF_LEN     (G711PLC_VOCAL_PERIOD_MAX + G711PLC_CORRELATION_LENGTH)
#define G711PLC_INTERPOLATION_TAPS_HALF 8
#define G711PLC_INTERPOLATION_TAPS      (2 * G711PLC_INTERPOLATION_TAPS_HALF)

typedef struct g711plc_s
{
  short samples[G711PLC_CORRELATION_BUF_LEN];
  short vocal_wave_first[G711PLC_VOCAL_PERIOD_MAX];
  short vocal_wave_second[G711PLC_VOCAL_PERIOD_MAX];
  short vocal_wave_short[G711PLC_VOCAL_PERIOD_MAX];
  short vocal_wave_long[G711PLC_VOCAL_PERIOD_MAX];
  short vocal_wave_pad;
  short vocal_wave_pad_next;

  short samples_odd[G711PLC_CORRELATION_BUF_LEN];
  short vocal_wave_first_odd[G711PLC_VOCAL_PERIOD_MAX];
  short vocal_wave_second_odd[G711PLC_VOCAL_PERIOD_MAX];
  short vocal_wave_short_odd[G711PLC_VOCAL_PERIOD_MAX];
  short vocal_wave_long_odd[G711PLC_VOCAL_PERIOD_MAX];
  short vocal_wave_pad_odd;
  short vocal_wave_pad_next_odd;

  unsigned sample_pos;
  word vocal_period_low;
  word vocal_period;
  unsigned vocal_overlap;
  bool merging;
  word merge_gain;
  word vocal_pos_low;
  unsigned vocal_pos;
  short *vocal_wave;
  short *vocal_wave_s;
  short *vocal_wave_l;
  short *vocal_wave_odd;
  short *vocal_wave_s_odd;
  short *vocal_wave_l_odd;
  bool vocal;
  word vocal_gain;
  word vocal_gain_dec;
  bool concealing;
  word conceal_gain;
  dword random_number_seed;
  word noise_level;
} t_g711plc;

void  g711plc_init (t_g711plc *g711plc);
short g711plc_put_get_sample_cng (t_g711plc *g711plc, short input_sample, short input_sample_odd,
  short cng_sample, short cng_sample_odd, short *p_result_sample_odd, byte *p_tail);
short g711plc_get_plc_sample_cng (t_g711plc *g711plc, short cng_sample, short cng_sample_odd, short *p_result_sample_odd);
#define g711plc_put_get_sample(g711plc,input_sample,input_sample_odd,p_result_sample_odd,p_tail)\
  g711plc_put_get_sample_cng(g711plc,input_sample,input_sample_odd,0,0,p_result_sample_odd,p_tail)
#define g711plc_get_plc_sample(g711plc,p_result_sample_odd)\
  g711plc_get_plc_sample_cng(g711plc,0,0,p_result_sample_odd)

NAMESPACE_END

/*---------------------------------------------------------------------------*/
#endif /* G711PLC_H_ */
