/*****************************************************************************/
/* This software module was originally developed by                          */
/*   Naoki Iwakami (NTT)                                                     */
/* and edited by                                                             */
/*   Naoki Iwakami (NTT) on 1997-07-17,                                      */
/*   Akio Jin (NTT) on 1997-10-23,                                           */
/* in the course of development of the                                       */
/* MPEG-2 NBC/MPEG-4 Audio standard ISO/IEC 13818-7, 14496-1,2 and 3.        */
/* This software module is an implementation of a part of one or more        */
/* MPEG-2 NBC/MPEG-4 Audio tools as specified by the MPEG-2 NBC/MPEG-4 Audio */
/* standard. ISO/IEC  gives users of the MPEG-2 NBC/MPEG-4 Audio standards   */
/* free license to this software module or modifications thereof for use in  */
/* hardware or software products claiming conformance to the MPEG-2 NBC/     */
/* MPEG-4 Audio  standards. Those intending to use this software module in   */
/* hardware or software products are advised that this use may infringe      */
/* existing patents. The original developer of this software module and      */
/* his/her company, the subsequent editors and their companies, and ISO/IEC  */
/* have no liability for use of this software module or modifications        */
/* thereof in an implementation. Copyright is not released for non           */
/* MPEG-2 NBC/MPEG-4 Audio conforming products. The original developer       */
/* retains full right to use the code for his/her  own purpose, assign or    */
/* donate the code to a third party and to inhibit third party from using    */
/* the code for non MPEG-2 NBC/MPEG-4 Audio conforming products.             */
/* This copyright notice must be included in all copies or derivative works. */
/* Copyright (c)1997.                                                        */
/*****************************************************************************/


#include "ntt_conf.h"
#include "ntt_scale_conf.h"
#include "ntt_encode.h"
#include "ntt_tools.h"


#define N_MEAS_MEM 2

#define FINE_CUTOFF 10

#define PST_BASS   10  /* postfilter switch measure base address */
#define PST_CUT_L  30  /* postfilter switch measure lower ntt_cutoff */
#define PST_CUT_U  100 /* postfilter switch measure upper ntt_cutoff */

#define PST_THR_U  0.8 /* postfilter switch upper threshold */
#define PST_THR_L  0.45 /* postfilter switch lower threshold */

void ntt_tf_pre_process(/* Input */
			double sig[],         /* input signal */
			/* Output */
			ntt_INDEX *index,     /* code index for block type */
			ntt_PARAM *param_ntt, /* encoding parameters */
			/* Control */
			int    med_sw,  /* enable/disable flag for medium block length */
			int    InitFlag)/* initialization flag */
{

    /*--- Variables ---*/
    int fine_sw, s_attack, m_attack;

    param_ntt->fine_sw = 0;
    param_ntt->speech_sw = 0;
    fine_sw = param_ntt->fine_sw;
    index->pf = param_ntt->speech_sw;


    /*--- A.Jin 1997.10.19 ---*/
    if (ntt_NSclLay == 0){
	ntt_mchkat48(sig, &s_attack, &m_attack, InitFlag);
    }
    if (ntt_NSclLay>0){
	ntt_scale_mchkat48(sig, fine_sw, &s_attack, &m_attack, InitFlag);
    }
/*
    if (ntt_NSclLay>0){
      if (s_attack == 1) m_attack = 1;
      s_attack = 0;
    }
*/
    if (med_sw == 0) m_attack = 0;
    ntt_get_wty( s_attack, m_attack,  &(index->w_type), InitFlag );
    
}


void ntt_get_wty(int flag,      /* Input : trigger for short block length */
		 int m_flag,    /* Input : trigger for medium block length */
		 int *w_type,   /* Output : code index for block type */
		 int InitFlag ) /* Control : initialization flag */
{
    static int	w_type_pre;
    static int	flag_pre, m_flag_pre;

    if ( InitFlag ){
	flag_pre = 0;
	m_flag_pre = 0;
	w_type_pre = ONLY_LONG_WINDOW;
    }

    if (InitFlag){
      if (flag)        *w_type = ONLY_SHORT_WINDOW;
      else if (m_flag) *w_type = ONLY_MEDIUM_WINDOW;
      else             *w_type = ONLY_LONG_WINDOW;
    }
    else{
      switch( w_type_pre ){
      case ONLY_LONG_WINDOW:
	if ( flag )      *w_type = LONG_SHORT_WINDOW;
	else if (m_flag) *w_type = LONG_MEDIUM_WINDOW;
	else             *w_type = ONLY_LONG_WINDOW;
	break;
      case LONG_SHORT_WINDOW:
	*w_type = ONLY_SHORT_WINDOW;
	break;
      case SHORT_LONG_WINDOW:
	if ( flag )      *w_type = LONG_SHORT_WINDOW;
	else if (m_flag) *w_type = LONG_MEDIUM_WINDOW;
	else             *w_type = ONLY_LONG_WINDOW;
	break;
      case LONG_MEDIUM_WINDOW:
	if (flag)        *w_type = MEDIUM_SHORT_WINDOW;
	else             *w_type = ONLY_MEDIUM_WINDOW;
	break;
      case MEDIUM_SHORT_WINDOW:
	*w_type = ONLY_SHORT_WINDOW;
	break;
      case SHORT_MEDIUM_WINDOW:
	if ( flag )   *w_type = MEDIUM_SHORT_WINDOW;
	else          *w_type = ONLY_MEDIUM_WINDOW;
	break;
      case MEDIUM_LONG_WINDOW:
	if      ( flag ) *w_type = LONG_SHORT_WINDOW;
	else if (m_flag) *w_type = LONG_MEDIUM_WINDOW;
	else             *w_type = ONLY_LONG_WINDOW;
	break;
      case ONLY_MEDIUM_WINDOW:
	if (m_flag || m_flag_pre) *w_type = ONLY_MEDIUM_WINDOW;
	else                      *w_type = MEDIUM_LONG_WINDOW;
	if (flag)                 *w_type = MEDIUM_SHORT_WINDOW;
	break;
      case ONLY_SHORT_WINDOW:
	if (flag || flag_pre) *w_type = ONLY_SHORT_WINDOW;
	else if (m_flag)      *w_type = SHORT_MEDIUM_WINDOW;
	else                  *w_type = SHORT_LONG_WINDOW;
	break;
      default:
	fprintf( stderr,
		"Fatal error! %d: no such window type.\n", w_type_pre );
	exit(1);
      }
    }
    w_type_pre  = *w_type;
    flag_pre = flag;
    m_flag_pre = m_flag;
}


#define ST_CHKATK    (ntt_N_FR/2+ntt_N_FR_S/2)

#define N_BLK_MAX	4096
#define	N_SFT_MAX       256
#define	L_POW_MAX	2048
#define	N_LPC_MAX	2


void ntt_mchkat48(double in[],  /* Input signal */
                  int    *flag, /* flag for attack */
                  int    *mflag,
                  int    InitFlag) /* Initialization Flag */
{
  /*--- Variables ---*/
  int                 n_div, iblk, ismp, ich;
  double              bufin[N_SFT_MAX];
  static double sig[ntt_N_SUP_MAX][N_BLK_MAX+N_LPC_MAX];
  double        wsig[N_BLK_MAX];
  static double wdw[N_BLK_MAX];
  static double wlag[N_LPC_MAX+1];
  double        cor[N_LPC_MAX+1],ref[N_LPC_MAX+1],alf[N_LPC_MAX+1];
  static double prev_alf[ntt_N_SUP_MAX][N_LPC_MAX+1];
  double        resid, wpowfr;
  double        long_power;
  double        synth, resid2;
  static int    botflag, botflagm;
  static int    N_BLK, N_SFT, S_POW, L_POW, N_LPC;
  double ratio, sum, product;
  double mod, band;

  /*--- Initialization ---*/
  if ( InitFlag ){
    /* Set parameters */
    N_BLK      = ntt_N_FR;
    N_SFT      = ntt_N_FR_S;
    S_POW      = ntt_N_FR_S;
    L_POW      = ntt_N_FR;
    N_LPC      = 1;
    /* clear buffers */
    for ( ich=0; ich<ntt_N_SUP; ich++ ){
      ntt_zerod( N_LPC+N_BLK, sig[ich] );
      ntt_zerod( N_LPC+1, prev_alf[ich] );
  }
    /* set windows */
    ntt_lagwdw( wlag, N_LPC, 0.02 );
    ntt_hamwdw( wdw, N_BLK );
    botflag=botflagm=0;
}


  n_div = ntt_N_FR/N_SFT;
  *flag = *mflag = 0;
  if (botflag) *flag=1;
  botflag=0;
  botflagm=0;
  sum=0.0; product=1.0;
  for ( ich=0; ich<ntt_N_SUP; ich++ ){
    for ( iblk=0; iblk<n_div; iblk++ ){
      ntt_cutfr( ST_CHKATK+iblk*N_SFT, N_SFT, ich, in, bufin );
      ntt_movdd(N_SFT,bufin,&sig[ich][N_LPC+N_BLK-N_SFT]);
      /*--- Calculate long power ---*/
      long_power =
        (ntt_dotdd( L_POW, &sig[ich][N_BLK-L_POW], &sig[ich][N_BLK-L_POW] )+0.1)
          / L_POW;
      long_power = sqrt(long_power);

      /*--- Calculate alpha parameter ---*/
      ntt_mulddd( N_BLK, &sig[ich][N_LPC], wdw, wsig );
      ntt_sigcor( wsig, N_BLK, &wpowfr, cor, N_LPC ); cor[0] = 1.0;
      ntt_mulddd( N_LPC+1, cor, wlag, cor );
      ntt_corref( N_LPC, cor, alf, ref, &resid );
      /*--- Get residual signal and its power ---*/
      resid2 = 0.;
      for ( ismp=N_BLK-S_POW; ismp<N_BLK; ismp++ ){
        synth = sig[ich][ismp]+
          prev_alf[ich][1]*sig[ich][ismp-1];
        resid2 += synth*synth;
    }
      resid2 /= long_power;
      resid2 = sqrt(resid2);
      sum += resid2+0.0001;
      product *= (resid2+0.0001);

      ntt_movdd( N_LPC, &alf[1], &prev_alf[ich][1] );

      ntt_movdd( N_BLK-N_SFT, &sig[ich][N_LPC+N_SFT], &sig[ich][N_LPC] );
  }
}
  ratio = sum/(n_div*ntt_N_SUP)/pow(product, 1./(double)(n_div*ntt_N_SUP));
  mod =1.0;
  band =1.0;
  if(ntt_ISAMPF <44 ) band = 0.75;
  if(ntt_ISAMPF <16 ) band = 0.5;
  if(L_POW/S_POW ==8) mod = 0.95;
  if(L_POW/S_POW ==4) mod = 0.9;

  if((ratio > 1.8*mod)
     ||((ratio>1.4*mod) && (ratio > 0.5/band/(1.-ref[1]*ref[1])))){
    *mflag = 0;
    *flag = 1;
}
  else if((ratio > 1.25*mod)
          ||((ratio>1.2) && (ratio > 0.5/band/(1.-ref[1]*ref[1])))){
    *mflag = 1;
    *flag = 0;
}
  else {
    *mflag = 0;
    *flag = 0;
}
}

void ntt_scale_mchkat48(double in[],  /* Input signal */
                  int    fine_sw,
                  int    *flag, /* flag for attack */
                  int    *mflag,
                  int    InitFlag) /* Initialization Flag */
{
  /*--- Variables ---*/
  int                   n_div, iblk, ismp, icor, ich;
  double              bufin[N_SFT_MAX];
  static double sig[ntt_N_SUP_MAX][N_BLK_MAX+N_LPC_MAX];
  double                wsig[N_BLK_MAX];
  static double wdw[N_BLK_MAX];
  static double       wlag[N_LPC_MAX+1];
  double                cor[N_LPC_MAX+1],ref[N_LPC_MAX+1],alf[N_LPC_MAX+1];
  static double prev_alf[ntt_N_SUP_MAX][N_LPC_MAX+1];
  double                resid, wpowfr;
  double                long_power;
  double                synth, resid2, d_resid, d_resid_m, trend;
  static double prev_resid2[ntt_N_SUP_MAX];
  static double smth_resid[ntt_N_SUP_MAX];
  static int            botflag, botflagm;
  static double       SENSITIV, SENSITIV_M, SENSITIV_S, SENSITIV_S_F, SENSITIV_M_F;
  static double       TC_EAR, RR;
  static int          N_BLK, N_SFT, S_POW, L_POW, N_LPC;
  double corpit[L_POW_MAX];
  double cormax;
  int longflag;

  /*--- Initialization ---*/
  if ( InitFlag ){
    /* Set parameters */
    switch (ntt_ISAMPF){
    case 48:
      switch(ntt_IBPS){
      case 40:
        SENSITIV_M   = 1.4;
        SENSITIV_M_F = 1.8;
        SENSITIV_S   = 2.2;
        SENSITIV_S_F = 5.0;
        break;
    case 24:
        if(ntt_TBIT_P > 0 ){
          SENSITIV_M   = 1.25;
          SENSITIV_M_F = 8.0;
      }
        else{
          SENSITIV_M   = 1.7;
          SENSITIV_M_F = 2.0;
      }
        SENSITIV_S   = 2.2;
        SENSITIV_S_F = 10.0;
        break;
    case 6:
        SENSITIV_M   = 1.7;
        SENSITIV_M_F = 2.0;
        SENSITIV_S   = 4.0;
        SENSITIV_S_F = 15.0;
        break;
    default:
        SENSITIV_M   = 1.4;
        SENSITIV_M_F = 1.8;
        SENSITIV_S   = 2.2;
        SENSITIV_S_F = 5.0;
        break;
    }
      TC_EAR     = 0.04;
      N_BLK      = 2048;
      N_SFT      = 128;
      S_POW      = 1024;
      L_POW      = 2048;
      N_LPC      = 1;
      break;
  case 44:
      SENSITIV = 1.55;
      TC_EAR   = 0.07;
      N_BLK    = 2048;
      N_SFT    = 256;
      S_POW    = 512;
      L_POW    = 1024;
      N_LPC    = 1;
      break;
  case 24:
      SENSITIV = 1.36;
      TC_EAR   = 0.08;
      N_BLK    = 1024;
      N_SFT    = 128;
      S_POW    = 512;
      L_POW    = 1024;
      N_LPC    = 1;
      break;
  case 22:
      SENSITIV = 1.3;
      TC_EAR   = 0.08;
      N_BLK    = 1024;
      N_SFT    = 128;
      S_POW    = 512;
      L_POW    = 1024;
      N_LPC    = 1;
      break;
  case 16:
      SENSITIV_M   = 1.02;
      SENSITIV_M_F = 1.05;
      SENSITIV_S   = 2.0;
      SENSITIV_S_F = 4.0;
      SENSITIV = 1.8;
      TC_EAR   = 0.08;
      N_BLK    = 1024;
      N_SFT    = 128;
      S_POW    = 512;
      L_POW    = 1024;
      N_LPC    = 1;
      break;
  case 12:
      SENSITIV = 1.8;
      TC_EAR   = 0.08;
      N_BLK    = 1024;
      N_SFT    = 128;
      S_POW    = 512;
      L_POW    = 1024;
      N_LPC    = 1;
      break;
  case 11:
      SENSITIV = 1.9;
      TC_EAR   = 0.08;
      N_BLK    = 1024;
      N_SFT    = 128;
      S_POW    = 512;
      L_POW    = 1024;
      N_LPC    = 1;
      break;
  case 8:
      SENSITIV_M   = 1.4;
      SENSITIV_M_F = 1.8;
      SENSITIV_S   = 2.2;
      SENSITIV_S_F = 5.0;
      SENSITIV = 1.8;
      TC_EAR   = 0.08;
      N_BLK    = 512;
      N_SFT    = 64;
      S_POW    = 256;
      L_POW    = 256;
      N_LPC    = 1;
      break;
  default:
      fprintf(stderr, "ntt_mchkat48(): ntt_ISAMPF=%d: Not supported.\n",
              ntt_ISAMPF);
      exit(1);
  }
    RR = (exp(-(double)N_SFT/ntt_SAMPF/TC_EAR));
}

  if ( InitFlag ){
    /* clear buffers */
    for ( ich=0; ich<ntt_N_SUP; ich++ ){
      ntt_zerod( N_LPC+N_BLK, sig[ich] );
      ntt_zerod( N_LPC+1, prev_alf[ich] );
      smth_resid[ich] = prev_resid2[ich] = 0.;
  }
    /* set windows */
    ntt_lagwdw( wlag, N_LPC, 0.02 );
    ntt_hamwdw( wdw, N_BLK );
    botflag=botflagm=0;
}

  n_div = ntt_N_FR/N_SFT+1;
  *flag = *mflag = 0;
  if (botflag) *flag=1;
  /*    if (botflagm) *mflag=1; */
  botflag=0;
  botflagm=0;

  for ( ich=0; ich<ntt_N_SUP; ich++ ){
    for ( iblk=0; iblk<n_div; iblk++ ){
      ntt_cutfr( ST_CHKATK+iblk*N_SFT, N_SFT, ich, in, bufin );
      ntt_movdd(N_SFT,bufin,&sig[ich][N_LPC+N_BLK-N_SFT]);
      /*--- Calculate long power ---*/
      long_power = (ntt_dotdd( L_POW, &sig[ich][N_BLK-L_POW], &sig[ich][N_BLK-L_POW] )+0.1) / L_POW;
      long_power = sqrt(long_power);

      /*--- Calculate alpha parameter ---*/
      ntt_mulddd( N_BLK, &sig[ich][N_LPC], wdw, wsig );
      ntt_sigcor( wsig, N_BLK, &wpowfr, cor, N_LPC ); cor[0] = 1.0;
      ntt_mulddd( N_LPC+1, cor, wlag, cor );
      ntt_corref( N_LPC, cor, alf, ref, &resid );
      /*--- Get residual signal and its power ---*/
      resid2 = 0.;
      if(N_LPC==1){
        for ( ismp=N_BLK-S_POW; ismp<N_BLK; ismp++ ){
          synth = sig[ich][ismp]+
            prev_alf[ich][1]*sig[ich][ismp-1];
          resid2 += synth*synth;
      }
    }
      else{
        for ( ismp=N_BLK-S_POW; ismp<N_BLK; ismp++ ){
          synth = sig[ich][ismp];
          for ( icor=1; icor<=N_LPC; icor++ ){
            synth += prev_alf[ich][icor]*sig[ich][ismp-icor];
	}
          resid2 += synth*synth;
      }
    }
      resid2 /= long_power;
      resid2 = sqrt(resid2);

      /*--- Smoothing ---*/
      smth_resid[ich] = ntt_max( resid2, smth_resid[ich]*RR );

      /*--- Check attack ---*/
      if (fine_sw) SENSITIV = SENSITIV_S_F;
      else         SENSITIV = SENSITIV_S;
      d_resid = smth_resid[ich] - SENSITIV*prev_resid2[ich];

      if (fine_sw) SENSITIV = SENSITIV_M_F;
      else         SENSITIV = SENSITIV_M;
      d_resid_m = smth_resid[ich] - SENSITIV * prev_resid2[ich];

      cormax = 0.4;
      if(cormax<0.85 && cormax>=0.2){
        if ( d_resid_m > 0.0 ){
          *mflag = 1;
          if ( iblk==n_div-1 ) botflagm=1;
      }
        if ( d_resid > 0.0 ){
          *mflag = 0;
          *flag = 1;
          if ( iblk==n_div-1 ) botflag=1;
      }
    }
      else if(cormax<0.2){
        if ( d_resid_m > -1.0 ){
          *mflag = 1;
          if ( iblk==n_div-1 ) botflagm=1;
      }
        if ( d_resid > -1.0 ){
          *mflag = 0;
          *flag = 1;
          if ( iblk==n_div-1 ) botflag=1;
      }
    }

      prev_resid2[ich]=smth_resid[ich];
      ntt_movdd( N_LPC, &alf[1], &prev_alf[ich][1] );

      ntt_movdd( N_BLK-N_SFT, &sig[ich][N_LPC+N_SFT], &sig[ich][N_LPC] );
  }
}
}

void ntt_win_sw_init(/* Input */
		     int max_ch,
		     int block_size_samples,
		     int sampling_rate,
		     int bit_rate,
		     int short_win_in_long)
{
    ntt_N_SUP = max_ch;
    ntt_N_FR  = block_size_samples;
    ntt_N_FR_EX = (int)(log((double)ntt_N_FR)/log(2.)+0.5);
    ntt_ISAMPF = (int)(sampling_rate/1000.+0.5);
    ntt_IBPS   = (int)(bit_rate/1000.+0.5);
    ntt_TBIT_P = 0;
    ntt_N_FR_S = ntt_N_FR / short_win_in_long;
}
