/*****************************************************************************/
/* This software module was originally developed by                          */
/*   Naoki Iwakami (NTT)                                                     */
/* and edited by                                                             */
/*   Naoki Iwakami and Satoshi Miki (NTT) on 1996-05-01,                     */
/*   Naoki Iwakami (NTT) on 1996-08-27,                                      */
/*   Naoki Iwakami (NTT) on 1997-04-18,                                      */
/*   Naoki Iwakami (NTT) on 1997-07-17,                                      */
/*   Naoki Iwakami (NTT) on 1997-08-25                                       */
/* 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)1996.                                                        */
/*****************************************************************************/

/* 25-aug-1997  NI  bug fixes */

#include "tf_main.h"
#include "bitstream.h"
#include "ntt_conf.h"
#include "ntt_encode.h"

void ntt_vq_coder(double *in_init[MAX_TIME_CHANNELS],
		  double *in[MAX_TIME_CHANNELS],
		  double      *spectral_line_vector[MAX_TIME_CHANNELS],
		  double      external_pw[],
		  int         pw_select,
		  int         block_type,
		  ntt_INDEX   *index,
		  ntt_PARAM   *param_ntt,
		  int         available_bits,
		  double      lpc_spectrum[],
		  double      *reconstructed_spectrum[MAX_TIME_CHANNELS])
{
  static double sig_tmp[ntt_T_FR_MAX*3], *sig;
  static double bark_env[ntt_T_FR_MAX];
  static double spectrum[ntt_T_FR_MAX];
  static double pitch_sequence[ntt_T_FR_MAX];
  static double gain[ntt_T_SHRT_MAX];
  static double perceptual_weight[ntt_T_FR_MAX];
  static int InitFlag = 1;
  int    ismp, i_ch, top;
  double spectrum_gain;

  /*--- Initialization ---*/
  if (InitFlag){
    ntt_zerod(ntt_N_FR*ntt_N_SUP*2, sig_tmp);
    sig = sig_tmp + ntt_N_FR * ntt_N_SUP;
    for (i_ch=0; i_ch<ntt_N_SUP; i_ch++){
      top = ntt_N_FR * i_ch;
      ntt_movdd(ntt_N_FR, in_init[i_ch], sig+top);
    }
  }
  for (i_ch=0; i_ch<ntt_N_SUP; i_ch++){
    top = ntt_N_FR * i_ch;
    ntt_movdd(ntt_N_FR, in[i_ch], sig+ntt_N_FR*ntt_N_SUP+top);
  }

  /*--- Pre process ---*/
  if (param_ntt->ntt_param_set_flag == 0){
    ntt_tf_pre_process(sig, index, param_ntt, 1, InitFlag);
  }
  index->w_type = block_type;

  /*--- Bit number control ---*/
  switch(block_type){
    /* long frame */
  case ONLY_LONG_WINDOW: case LONG_SHORT_WINDOW: case SHORT_LONG_WINDOW:
  case LONG_MEDIUM_WINDOW: case MEDIUM_LONG_WINDOW:
#if (ntt_POSTFILT == YES)
    available_bits -= ntt_PF_SW_BIT;
#endif
    ntt_VQTOOL_BITS = available_bits - ntt_NMTOOL_BITS;
    spectrum_gain = 1./sqrt((double)ntt_N_FR*2.);
    break;
    /* medium frame */
  case ONLY_MEDIUM_WINDOW: case MEDIUM_SHORT_WINDOW:
  case SHORT_MEDIUM_WINDOW:
#if (ntt_POSTFILT == YES)
    available_bits -= ntt_PF_SW_BIT;
#endif
    ntt_VQTOOL_BITS_M = available_bits - ntt_NMTOOL_BITS_M;
    spectrum_gain = 1./sqrt((double)ntt_N_FR_M*2.);
    break;
    /* short frame */
  case ONLY_SHORT_WINDOW:
    ntt_VQTOOL_BITS_S = available_bits - ntt_NMTOOL_BITS_S;
    spectrum_gain = 1./sqrt((double)ntt_N_FR_S*2.);
    break;
  default:
    fprintf(stderr, "ntt_vq_coder(): Error. %d: No such window type.\n",
	    block_type);
    exit(1);
    break;
  }

  /*--- Spectrum line normalization
    (for gain alignment of NTT & MPEG4 VM MDCT ---*/
  for (i_ch=0; i_ch<ntt_N_SUP; i_ch++){
    top = i_ch * ntt_N_FR;
    for (ismp=0; ismp<ntt_N_FR; ismp++){
      spectrum[ismp+top] = spectral_line_vector[i_ch][ismp] * spectrum_gain;
    }
  }

  /*--- Process spectrum ---*/
  ntt_tf_proc_spectrum(sig, spectrum, index,
		       lpc_spectrum, bark_env,
		       pitch_sequence, gain, *param_ntt);

  /*--- Perceptual model ---*/
  if (pw_select == NTT_PW_EXTERNAL &&
      (index->w_type == ONLY_LONG_WINDOW ||
       index->w_type == LONG_SHORT_WINDOW ||
       index->w_type == SHORT_LONG_WINDOW ||
       index->w_type == LONG_MEDIUM_WINDOW ||
       index->w_type == MEDIUM_LONG_WINDOW)){
    /* external perceptual weighting */
    ntt_movdd(ntt_N_FR*ntt_N_SUP, external_pw, perceptual_weight);
  }
  else{
    /* internal perceptual weighting */
    ntt_tf_perceptual_model(lpc_spectrum, bark_env, gain, block_type,
			    spectrum, pitch_sequence, 
			    perceptual_weight, param_ntt);
  }

  /*--- Quantize spectrum ---*/
  ntt_tf_quantize_spectrum(spectrum, lpc_spectrum, bark_env,
			   pitch_sequence,
			   gain, perceptual_weight, index, param_ntt);
  ntt_tf_local_decode(index, lpc_spectrum, bark_env, pitch_sequence,
		      gain, 1./spectrum_gain, reconstructed_spectrum);

  ntt_movdd(ntt_N_FR*ntt_N_SUP*2, sig, sig-ntt_N_FR*ntt_N_SUP);
  InitFlag = 0;

}
