/*****************************************************************************/
/* 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_mchkat48(sig, &s_attack, &m_attack, InitFlag);

    }
#if (FRAME_LENGTH_MODE==1||FRAME_LENGTH_MODE==3)
m_attack = 0;
#endif
/*
    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 );
/*
fprintf(stderr,"ntt_tf_pre_process:w_type %d %d %d\n",index->w_type, s_attack, m_attack);
*/
}


void ntt_get_wty(int flag,      /* Input : trigger for short block length */
		 int m_flag,    /* Input : trigger for medium block length */
		 WINDOW_TYPE *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_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;
}
