/*---------------------------------------------------------------------------*/
/*
  File: sparslec.h

  Sparse LEC.
*/
/*---------------------------------------------------------------------------*/

#ifndef SPARSLEC_H_
#define SPARSLEC_H_


#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------*/
NAMESPACE_BEGIN

#define DSP_LEC_ENABLE_ECHO_CANCELLER           0x0001
#define DSP_LEC_ENABLE_2100HZ_DETECTOR          0x0002
#define DSP_LEC_REQUIRE_2100HZ_REVERSALS        0x0004
#define DSP_LEC_MANUAL_DISABLE                  0x0008
#define DSP_LEC_ENABLE_NONLINEAR_PROCESSING     0x0010
#define DSP_LEC_FREEZE_COEFFICIENTS             0x0020
#define DSP_LEC_ENABLE_COMFORT_NOISE_GENERATION 0x0040
#define DSP_LEC_NLP_WITH_ATTENUATION            0x0100
#define DSP_LEC_RESET_COEFFICIENTS              0x8000

#define DSP_LEC_STATE_ERROR_DETECTED            0x0001
#define DSP_LEC_STATE_CONTIGNUOUS_2100HZ        0x0002
#define DSP_LEC_STATE_REVERSED_2100HZ           0x0004
#define DSP_LEC_STATE_AUTO_DISABLED             0x0008


#define ANS_DETECTOR_STATE_ENERGY_DETECTED  0x0001
#define ANS_DETECTOR_STATE_G164_DETECTED    0x0002
#define ANS_DETECTOR_STATE_G165_DETECTED    0x0004

#define ANS_DETECTOR_REDUCTION_RATIO        8
#define ANS_DETECTOR_NOM_ANGLE_INCREMENT    17203
#define ANS_DETECTOR_MAX_INCREMENT_OFFSET   344
#define ANS_DETECTOR_MIN_ANGLE_INCREMENT    (ANS_DETECTOR_NOM_ANGLE_INCREMENT - ANS_DETECTOR_MAX_INCREMENT_OFFSET)
#define ANS_DETECTOR_MAX_ANGLE_INCREMENT    (ANS_DETECTOR_NOM_ANGLE_INCREMENT + ANS_DETECTOR_MAX_INCREMENT_OFFSET)
#define ANS_DETECTOR_INCREMENT_OFFSET_HALF  64
#define ANS_DETECTOR_INCREMENT_OFFSET       (2 * ANS_DETECTOR_INCREMENT_OFFSET_HALF)
#define ANS_DETECTOR_ANGLE_HIT_EXP          4
#define ANS_DETECTOR_ENERGY_GAIN            0x0080
#define ANS_DETECTOR_PHASE_GAIN             0x1000
#define ANS_DETECTOR_ENERGY_LOW_THRESHOLD   0x3000
#define ANS_DETECTOR_ENERGY_HIGH_THRESHOLD  0xc000
#define ANS_DETECTOR_DETECT_ENERGY          0x0136  /* -33 dBm */
#define ANS_DETECTOR_RELEASE_ENERGY         0x00DB  /* -36 dBm */
#define ANS_DETECTOR_MAX_FAIL_TIME          (10 * 8)
#define ANS_DETECTOR_MIN_PASS_TIME          (10 * 8)
#define ANS_DETECTOR_MIN_G164_DETECT_TIME   (300 * 8)
#define ANS_DETECTOR_MIN_REVERSAL_DISTANCE  (420 * 8)
#define ANS_DETECTOR_MAX_REVERSAL_DISTANCE  (480 * 8)
#define ANS_DETECTOR_MIN_G165_REVERSALS     2
#define ANS_DETECTOR_RELEASE_TIME           400

#define ANS_DETECTOR_SIN_COS_TABLE_EXP      6
#define ANS_DETECTOR_SIN_COS_TABLE_SIZE\
  ((1 << ANS_DETECTOR_SIN_COS_TABLE_EXP) + (1 << (ANS_DETECTOR_SIN_COS_TABLE_EXP - 2)))


#ifdef __ANDROID__
#define SPARSE_LEC_MAX_TOTAL_LENGTH_EXP     13
#define SPARSE_LEC_PASSIVE_DEPTH_EXP        7
#else
#define SPARSE_LEC_MAX_TOTAL_LENGTH_EXP     11
#define SPARSE_LEC_PASSIVE_DEPTH_EXP        6
#endif
#define SPARSE_LEC_MAX_TOTAL_LENGTH         (1 << SPARSE_LEC_MAX_TOTAL_LENGTH_EXP)
#define SPARSE_LEC_MAX_TAIL_LENGTH          256 /* not needed if buffers are adapted */
#define SPARSE_LEC_ACTIVE_DEPTH_EXP         2
#define SPARSE_LEC_ACTIVE_DEPTH             (1 << SPARSE_LEC_ACTIVE_DEPTH_EXP)
#define SPARSE_LEC_PASSIVE_DEPTH            (1 << SPARSE_LEC_PASSIVE_DEPTH_EXP)
#define SPARSE_LEC_PASSIVE_STEPS            6
#define SPARSE_LEC_MAX_DEPTH                SPARSE_LEC_PASSIVE_DEPTH
#define SPARSE_LEC_SECTION_LENGTH_EXP       4
#define SPARSE_LEC_SECTION_LENGTH           (1 << SPARSE_LEC_SECTION_LENGTH_EXP)
#define SPARSE_LEC_SECTION_BLOCKS           (1 << (SPARSE_LEC_SECTION_LENGTH_EXP - SPARSE_LEC_ACTIVE_DEPTH_EXP))


#define SPARSE_LEC_LIMITER_FAST_SLOPE       0x7fff
#define SPARSE_LEC_LIMITER_SLOW_SLOPE       0x0400
#define SPARSE_LEC_LIMITER_MAX_GAIN         0xc000
#define SPARSE_LEC_LIMITER_DOUBLE_TALK_GAIN 0x0800

#define SPARSE_LEC_NLP_THRESHOLD            0x1400
#define SPARSE_LEC_NLP_LEVEL_SLOPE          0x0400

#define SPARSE_LEC_DOUBLE_TALK_THRESHOLD    0x5000
#define SPARSE_LEC_DOUBLE_TALK_THRESHOLD_IN 0x7fff
#define SPARSE_LEC_DOUBLE_TALK_HANGOVER     (240 >> SPARSE_LEC_ACTIVE_DEPTH_EXP)

#define SPARSE_LEC_PROPORTIONATE_EXP        3

#define SPARSE_LEC_MIN_LOSS_LIMIT           0x01d6
#define SPARSE_LEC_MIN_LOSS_LIMIT_INACTIVE  0x0004
#define SPARSE_LEC_LOSS_LIMIT_DOUBLETALK    0x0040
#define SPARSE_LEC_EXPECTED_RETURN_LOSS     0x1d7f
#define SPARSE_LEC_ENHANCED_RETURN_LOSS     (SPARSE_LEC_EXPECTED_RETURN_LOSS >> ((15 - 3 - SPARSE_LEC_PROPORTIONATE_EXP) >> 1))

#if (SPARSE_LEC_ENHANCED_RETURN_LOSS < SPARSE_LEC_MIN_LOSS_LIMIT)
#error (SPARSE_LEC_ENHANCED_RETURN_LOSS < SPARSE_LEC_MIN_LOSS_LIMIT)
#endif

#define SPARSE_LEC_RIN_ENERGY_BIAS          0x0080
#define SPARSE_LEC_ACTIVE_RIN_ENERGY_BIAS   0x0080
#define SPARSE_LEC_MAX_RIN_BIAS             0x0040

#define SPARSE_LEC_ACTIVITY_INTERVAL        (512 >> SPARSE_LEC_SECTION_LENGTH_EXP)
#define SPARSE_LEC_ACTIVITY_RATIO           0x7800

#define SPARSE_LEC_CNG_HISTORY_SIZE_EXP     4
#define SPARSE_LEC_CNG_HISTORY_SIZE         (1 << SPARSE_LEC_CNG_HISTORY_SIZE_EXP)
#define SPARSE_LEC_CNG_ADAPTATION_SLOPE     0x0010
#define SPARSE_LEC_CNG_MAX_LEVEL            0x0040


/*---------------------------------------------------------------------------*/

typedef struct tag_ans_detector
{
  word angle;
  word angle_increment;
  short increment_offset;
  int32 energy;
  int32 phase_x;
  int32 phase_y;
  word fails;
  word reversals;
  word reduction_counter;
  word pass_counter;
  word fail_counter;
  word pass_reversals;
  word state;
} t_ans_detector;


typedef struct tag_sparse_lec_update
{
  dword rin_energy_low;
  dword rin_energy_high;
  dword eout_gain;
  dword loss_limit;
  word min_loss_limit;
  word max_loss_limit;
  word max_rin;
  word double_talk_threshold;
  word double_talk;
  short mu_exponent;
  word mu_fraction;
} t_sparse_lec_update;

typedef struct tag_sparse_lec
{
  word options;
  word state;
  word total_length;
  word tail_length;
  int32 rin_dc_offset;
  int32 sin_dc_offset;
  word max_sin;
  word delay_pos;
  word section_offset;
  word activity_counter;
  word active_step_number;
  word passive_step_number;
  word max_rin_pos;
  word max_rin;
   /* Should be MAX_CACHE_LINE_SIZE aligned here */
  short coef_buffer[SPARSE_LEC_MAX_TOTAL_LENGTH]; /* could be adapted */
  short delay_buffer[SPARSE_LEC_MAX_TOTAL_LENGTH + SPARSE_LEC_MAX_DEPTH]; /* could be adapted */
  t_sparse_lec_update active;
  t_sparse_lec_update passive;
  short active_step_table[SPARSE_LEC_ACTIVE_DEPTH];
  short passive_step_table[SPARSE_LEC_PASSIVE_DEPTH];
  dword active_rin_energy_low_table[SPARSE_LEC_SECTION_BLOCKS];
  dword active_rin_energy_high_table[SPARSE_LEC_SECTION_BLOCKS];
  word max_rin_buffer[SPARSE_LEC_MAX_TOTAL_LENGTH >> SPARSE_LEC_SECTION_LENGTH_EXP]; /* could be adapted */
  word section_base_buffer[SPARSE_LEC_MAX_TOTAL_LENGTH >> SPARSE_LEC_SECTION_LENGTH_EXP]; /* could be adapted */
  word proportionate_buffer[SPARSE_LEC_MAX_TAIL_LENGTH >> SPARSE_LEC_SECTION_LENGTH_EXP]; /* could be adapted */
  word coef_sum_buffer[SPARSE_LEC_MAX_TOTAL_LENGTH >> SPARSE_LEC_SECTION_LENGTH_EXP]; /* could be on stack and adapted */

  word g164_disable_release;
  word g165_disable_release;
  t_ans_detector rin_ans_detector;
  t_ans_detector sin_ans_detector;
  int32 nlp_level;
  word activity_max_rin;
  word activity_max_rin_2;
  byte first_section_active;
  word first_section_proportionate;
  dword cng_random_number_seed;
  int32 cng_lowpass_accu;
  dword cng_lowpass_gain;
  dword cng_lowpass_slope;
  short cng_eout_history[SPARSE_LEC_CNG_HISTORY_SIZE];
  short cng_noise_history[SPARSE_LEC_CNG_HISTORY_SIZE];
  word cng_history_pos;
  dword cng_eout_energy;
  dword cng_noise_energy;
  dword cng_eout_hp_energy;
  dword cng_noise_hp_energy;
  byte cng_active;

  word ans_trace_reduction_counter;
  word lec_trace_reduction_counter;
  const char *trace_tag;
} t_sparse_lec;


void sparse_lec_init (t_sparse_lec *p_lec, word total_length, word tail_length);
void sparse_lec_flush (t_sparse_lec *p_lec);
short sparse_lec_exec (t_sparse_lec *p_lec, short Rin, short Sin);


NAMESPACE_END
/*---------------------------------------------------------------------------*/
#ifdef __cplusplus
}
#endif

#endif

/*---------------------------------------------------------------------------*/
