shithub: aacenc

ref: 11af283c2493c1b03adcc5d668f4b1a415178883
dir: /enc_tf.c/

View raw version
/*
 *	Frame encoding
 *
 *	Copyright (c) 1999 M. Bakker
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/**************************************************************************
  Version Control Information			Method: CVS
  Identifiers:
  $Revision: 1.69 $
  $Date: 2000/11/10 13:27:06 $ (check in)
  $Author: menno $
  *************************************************************************/

#include <stdlib.h>
#include <memory.h>

#include "aacenc.h"
#include "bitstream.h"
#include "interface.h"
#include "enc.h"
#include "psych.h"
#include "mc_enc.h"
#include "ms.h"
#include "quant.h"
#include "aac_se_enc.h"
#include "ltp_enc.h"
#include "transfo.h"


/* AAC tables */

SR_INFO sr_info_aac[MAX_SAMPLING_RATES+1] =
{
	{ 8000, 40, 15,
		{
			12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 16, 
			16, 16, 16, 16, 16, 16, 20, 20, 20, 20, 24, 24, 24, 28, 
			28, 32, 32, 36, 40, 44, 48, 52, 56, 60, 64, 80
		}, {
			4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 12, 16, 20, 20
		}
	}, { 11025, 43, 15,
		{
			8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 
			12, 12, 12, 12, 12, 12, 16, 16, 16, 16, 20, 20, 20, 24,
			24, 28, 28, 32, 36, 40, 40, 44, 48, 52, 56, 60, 64, 64, 64
		}, {
			4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 12, 12, 16, 20, 20
		}
	}, { 12000, 43, 15,
		{
			8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 
			12, 12, 12, 12, 12, 12, 16, 16, 16, 16, 20, 20, 20, 24, 
			24, 28, 28, 32, 36, 40, 40, 44, 48, 52, 56, 60, 64, 64, 64
		}, {
			4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 12, 12, 16, 20, 20
		}
	}, { 16000, 43, 15,
		{
			8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 
			12, 12, 12, 12, 12, 12, 16, 16, 16, 16, 20, 20, 20, 24, 
			24, 28, 28, 32, 36, 40, 40, 44, 48, 52, 56, 60, 64, 64, 64
		}, {
			4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 12, 12, 16, 20, 20
		}
	}, { 22050, 47, 15,
		{
			4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  8,  8,  8,  8,  8,  8,  8,
			8,  8,  8,  12, 12, 12, 12, 16, 16, 16, 20, 20, 24, 24, 28, 28, 32,
			36, 36, 40, 44, 48, 52, 52, 64, 64, 64, 64, 64
		}, {
			4,  4,  4,  4,  4,  4,  4,  8,  8,  8,  8, 12, 16, 16, 20
		}
	},{ 24000, 47, 15,
		{
			4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  8,  8,  8,  8,  8,  8,  8,
			8,  8,  8,  12, 12, 12, 12, 16, 16, 16, 20, 20, 24, 24, 28, 28, 32,
			36, 36, 40, 44, 48, 52, 52, 64, 64, 64, 64, 64
		}, {
			4,  4,  4,  4,  4,  4,  4,  8,  8,  8,  8, 12, 16, 16, 20
		}
	}, { 32000, 51, 14,
		{
			4,	4,	4,	4,	4,	4,	4,	4,	4,	4,	8,	8,	8,	8,	
			8,	8,	8,	12,	12,	12,	12,	16,	16,	20,	20,	24,	24,	28,	
			28,	32,	32,	32,	32,	32,	32,	32,	32,	32,	32,	32,	32,	32,
			32,	32,	32,	32,	32,	32,	32,	32,	32
		},{
			4,	4,	4,	4,	4,	8,	8,	8,	12,	12,	12,	16,	16,	16
		}
	}, { 44100, 49, 14,
		{
			4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  8,  8,  8,  8,  8,  8,  8, 
			12, 12, 12, 12, 16, 16, 20, 20, 24, 24, 28, 28, 32, 32, 32, 32, 32, 32,
			32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 96
		}, {
			4,  4,  4,  4,  4,  8,  8,  8, 12, 12, 12, 16, 16, 16 
		}
	}, { 48000, 49, 14,
		{
			4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  8,  8,  8,  8,  8,  8,  8, 
			12, 12, 12, 12, 16, 16, 20, 20, 24, 24, 28, 28, 32, 32, 32, 32, 32, 32,
			32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 96
		}, {
			4,  4,  4,  4,  4,  8,  8,  8, 12, 12, 12, 16, 16, 16 
		}
	}, {64000, 47, 12,
		{
			4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
			8, 8, 8, 8, 12, 12, 12, 16, 16, 16, 20, 24, 24, 28,
			36, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
			40, 40, 40, 40, 40
		},{
			4, 4, 4, 4, 4, 4, 8, 8, 8, 16, 28, 32
		}
	}, { 88200, 41, 12,
		{
			4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
			8, 8, 8, 8, 8, 12, 12, 12, 12, 12, 16, 16, 24, 28, 
			36, 44, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
		},{
			4, 4, 4, 4, 4, 4, 8, 8, 8, 16, 28, 36
		}
	}, { 96000, 41, 12,
		{
			4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
			8, 8, 8, 8, 8, 12, 12, 12, 12, 12, 16, 16, 24, 28, 
			36, 44, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
		},{
			4, 4, 4, 4, 4, 4, 8, 8, 8, 16, 28, 36
		}
	},
	{ -1 }
};

/* First attempt at supporting multiple sampling rates   *
 * and bitrates correctly.                               */

/* Tables for maximum nomber of scalefactor bands */
/* Needs more fine-tuning. Only the values for 44.1kHz have been changed
   on lower bitrates. */
int max_sfb_s[] = { 12, 12, 12, 13, 14, 13, 15, 15, 15, 15, 15, 15 };
int max_sfb_l[] = { 49, 49, 47, 48, 49, 51, 47, 47, 43, 43, 43, 40 };


int     max_ch;    /* no of of audio channels */
double *spectral_line_vector[MAX_TIME_CHANNELS];
double *reconstructed_spectrum[MAX_TIME_CHANNELS];
double *overlap_buffer[MAX_TIME_CHANNELS];
double *DTimeSigBuf[MAX_TIME_CHANNELS];
double *DTimeSigLookAheadBuf[MAX_TIME_CHANNELS*2];
double *tmp_DTimeSigBuf[MAX_TIME_CHANNELS]; /* temporary fix to the buffer size problem. */

/* variables used by the T/F mapping */
enum WINDOW_TYPE block_type[MAX_TIME_CHANNELS];
enum WINDOW_TYPE desired_block_type[MAX_TIME_CHANNELS];
enum WINDOW_TYPE next_desired_block_type[MAX_TIME_CHANNELS];

AACQuantInfo quantInfo[MAX_TIME_CHANNELS];               /* Info structure for AAC quantization and coding */


/* EncTfFree() */
/* Free memory allocated by t/f-based encoder core. */

void EncTfFree (void)
{
  int chanNum;

  for (chanNum=0;chanNum<MAX_TIME_CHANNELS;chanNum++) {
    if (DTimeSigBuf[chanNum]) free(DTimeSigBuf[chanNum]);
    if (spectral_line_vector[chanNum]) free(spectral_line_vector[chanNum]);

    if (reconstructed_spectrum[chanNum]) free(reconstructed_spectrum[chanNum]);
    if (overlap_buffer[chanNum]) free(overlap_buffer[chanNum]);
    if (quantInfo[chanNum].ltpInfo.delay) free(quantInfo[chanNum].ltpInfo.delay);
    if (tmp_DTimeSigBuf[chanNum]) free(tmp_DTimeSigBuf[chanNum]);
  }
  for (chanNum=0;chanNum<MAX_TIME_CHANNELS*2;chanNum++) {
    if (DTimeSigLookAheadBuf[chanNum]) free(DTimeSigLookAheadBuf[chanNum]);
  }
}

/*******************************************************************************
 ***
 *** Function: EncTfInit
 ***
 *** Purpose:  Initialize the T/F-part and the macro blocks of the T/F part of the VM
 ***
 *** Description:
 ***
 ***
 *** Parameters:
 ***
 ***
 *** Return Value:
 ***
 *** **** MPEG-4 VM ****
 ***
 ******************************************************************************/

void EncTfInit (faacAACStream *as)
{
  int chanNum, i;
  int SampleRates[] = { 96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000,0};
  int srate_idx;
//	int BitRates[] = {
//		64000,80000,96000,112000,128000,160000,192000,224000,256000,0
//	};

  for (i = 0; ; i++) {
    if (SampleRates[i] == as->out_sampling_rate) {
      srate_idx = i;
      break;
    }
  }

  if (as->use_PNS)
    pns_sfb_start = 0;
  else
    pns_sfb_start = 60;

  /* set the return values */
  max_ch = as->channels;

  /* some global initializations */
  for (chanNum=0;chanNum<MAX_TIME_CHANNELS;chanNum++) {
    DTimeSigBuf[chanNum]            = (double*)malloc(BLOCK_LEN_LONG*sizeof(double));
    memset(DTimeSigBuf[chanNum],0,BLOCK_LEN_LONG*sizeof(double));
    spectral_line_vector[chanNum]   = (double*)malloc(2*BLOCK_LEN_LONG*sizeof(double));
    reconstructed_spectrum[chanNum] = (double*)malloc(BLOCK_LEN_LONG*sizeof(double));
    memset(reconstructed_spectrum[chanNum], 0, BLOCK_LEN_LONG*sizeof(double));
    overlap_buffer[chanNum] = (double*)malloc(sizeof(double)*BLOCK_LEN_LONG);
    memset(overlap_buffer[chanNum],0,(BLOCK_LEN_LONG)*sizeof(double));
    block_type[chanNum] = ONLY_LONG_WINDOW;
    quantInfo[chanNum].ltpInfo.delay =  (int*)malloc(MAX_SHORT_WINDOWS*sizeof(int));
    tmp_DTimeSigBuf[chanNum]  = (double*)malloc(2*BLOCK_LEN_LONG*sizeof(double));
    memset(tmp_DTimeSigBuf[chanNum],0,(2*BLOCK_LEN_LONG)*sizeof(double));
  }
  for (chanNum=0;chanNum<MAX_TIME_CHANNELS*2;chanNum++) {
    DTimeSigLookAheadBuf[chanNum]   = (double*)malloc((BLOCK_LEN_LONG)*sizeof(double));
    memset(DTimeSigLookAheadBuf[chanNum],0,(BLOCK_LEN_LONG)*sizeof(double));
  }

  /* initialize psychoacoustic module */
  Psy_Init();

  /* initialize spectrum processing */
  /* initialize quantization and coding */
  aacQuantizeInit(0);

  /* Init TNS */
  for (chanNum=0;chanNum<MAX_TIME_CHANNELS;chanNum++) {
    TnsInit(as->out_sampling_rate,as->profile,&quantInfo[chanNum].tnsInfo);
  }

  /* Init LTP predictor */
  for (chanNum=0;chanNum<MAX_TIME_CHANNELS;chanNum++) {
    init_lt_pred (&quantInfo[chanNum].ltpInfo);
    quantInfo[chanNum].window_shape = WS_SIN;
  }

  for (chanNum=0;chanNum<MAX_TIME_CHANNELS;chanNum++) {
		quantInfo[chanNum].sr_info = &sr_info_aac[0];
			
		/* find correct sampling rate depending parameters */
		while( quantInfo[chanNum].sr_info->sampling_rate != as->out_sampling_rate ) {
			quantInfo[chanNum].sr_info++;
		}

    quantInfo[chanNum].srate_idx = srate_idx;
    quantInfo[chanNum].profile = as->profile;
  }

  /* Initialisation for FFT & MDCT stuff */
  make_MDCT_windows();
  make_FFT_order();
  initrft();
}



/*******************************************************************************
 ***
 *** Function:    EncTfFrame
 ***
 *** Purpose:     processes a block of time signal input samples into a bitstream
 ***              based on T/F encoding
 ***
 *** Description:
 ***
 ***
 *** Parameters:
 ***
 ***
 *** Return Value:  returns the number of used bits
 ***
 *** **** MPEG-4 VM ****
 ***
 ******************************************************************************/

int EncTfFrame (faacAACStream *as, BsBitStream  *fixed_stream)
{
  int used_bits;
  int error;

  /* Energy array (computed before prediction for long windows) */
  double energy[MAX_TIME_CHANNELS][MAX_SCFAC_BANDS];

  /* determine the function parameters used earlier */
  int          average_bits = as->frame_bits;
  int          available_bitreservoir_bits = as->available_bits-as->frame_bits;

  /* max. allowed amount of bits in the reservoir  (used to avoid padding bits) */
  long num_bits_available;

  double *p_ratio[MAX_TIME_CHANNELS], allowed_distortion[MAX_TIME_CHANNELS][MAX_SCFAC_BANDS];
  static double p_ratio_long[2][MAX_TIME_CHANNELS][MAX_SCFAC_BANDS];
  static double p_ratio_short[2][MAX_TIME_CHANNELS][MAX_SCFAC_BANDS];
  int    nr_of_sfb[MAX_TIME_CHANNELS], sfb_width_table[MAX_TIME_CHANNELS][MAX_SCFAC_BANDS];
  int sfb_offset_table[MAX_TIME_CHANNELS][MAX_SCFAC_BANDS+1];


  /* structures holding the output of the psychoacoustic model */
  CH_PSYCH_OUTPUT_LONG chpo_long[MAX_TIME_CHANNELS];
  CH_PSYCH_OUTPUT_SHORT chpo_short[MAX_TIME_CHANNELS][MAX_SHORT_WINDOWS];
  static int ps = 1;
  ps = !ps;

  if (as->header_type==ADTS_HEADER)
    available_bitreservoir_bits += 58;

  /***********************************************************************/
  /* Determine channel elements */
  /***********************************************************************/
  DetermineChInfo(quantInfo, max_ch, as->lfePresent);


  /***********************************************************************/
  /* Fill buffers  */
  /* store input data in look ahead buffer which may be necessary */
  /* for the window switching decision */
  /***********************************************************************/
  {
	  int chanNum;
	  int i;

	  for (chanNum = 0; chanNum < max_ch; chanNum++) {

		  if (quantInfo[chanNum].channelInfo.present) {
			  if ((quantInfo[chanNum].channelInfo.cpe) && (quantInfo[chanNum].channelInfo.ch_is_left)) { /* CPE */
				  int leftChan = chanNum;
				  int rightChan = quantInfo[chanNum].channelInfo.paired_ch;

				  if (as->use_MS == 1) {
					  for(i = 0; i < BLOCK_LEN_LONG; i++){
						  DTimeSigLookAheadBuf[leftChan][i] = (as->inputBuffer[leftChan][i]+as->inputBuffer[rightChan][i])*0.5;
						  DTimeSigLookAheadBuf[rightChan][i] = (as->inputBuffer[leftChan][i]-as->inputBuffer[rightChan][i])*0.5;
					  }
				  }
			  }

			  if(as->use_LTP) {
				  for( i=0; i< BLOCK_LEN_LONG; i++ ) {
					  tmp_DTimeSigBuf[chanNum][i] = DTimeSigBuf[chanNum][i];
					  tmp_DTimeSigBuf[chanNum][BLOCK_LEN_LONG + i] = DTimeSigLookAheadBuf[chanNum][i];
				  }
			  }
			  for( i=0; i< BLOCK_LEN_LONG; i++ ) {
				  DTimeSigBuf[chanNum][i] = DTimeSigLookAheadBuf[chanNum][i];
				  DTimeSigLookAheadBuf[chanNum][i] = as->inputBuffer[chanNum][i];
			  }
		  }
	  }
  }


  if (fixed_stream == NULL) {
    Psy_FillBuffer(DTimeSigLookAheadBuf, max_ch);
    return FNO_ERROR; /* quick'n'dirty fix for encoder startup */
  }

  /* Keep track of number of bits used */
  used_bits = 0;

  /*****************************************************************************/
  /* psychoacoustics */
  /*****************************************************************************/
  Psy_Calculate(
	  quantInfo,
	  as->out_sampling_rate,
	  max_ch,
	  DTimeSigLookAheadBuf,
	  next_desired_block_type,
	  as->use_MS,
	  chpo_long,
	  chpo_short
	  );

  /*****************************************************************************/
  /* block_switch processing */
  /*****************************************************************************/
  {
    int chanNum;
	
    for (chanNum=0;chanNum<max_ch;chanNum++) {
    /* A few definitions:                                                      */
    /*   block_type:  Initially, the block_type used in the previous frame.    */
    /*                Will be set to the block_type to use this frame.         */
    /*                A block type will be selected to ensure a meaningful     */
    /*                window transition.                                       */
    /*   next_desired_block_type:  Block_type (LONG or SHORT) which the psycho */
    /*                model wants to use next frame.  The psycho model is      */
    /*                using a look-ahead buffer.                               */
    /*   desired_block_type:  Block_type (LONG or SHORT) which the psycho      */
    /*                previously wanted to use.  It is the desired block_type  */
    /*                for this frame.                                          */
    if ( (block_type[chanNum]==ONLY_SHORT_WINDOW)||(block_type[chanNum]==LONG_SHORT_WINDOW) ) {
      if ( (desired_block_type[chanNum]==ONLY_LONG_WINDOW)&&(next_desired_block_type[chanNum]==ONLY_LONG_WINDOW) ) {
	block_type[chanNum]=SHORT_LONG_WINDOW;
      }
      else {
	block_type[chanNum]=ONLY_SHORT_WINDOW;
      }
    }
    else if (next_desired_block_type[chanNum]==ONLY_SHORT_WINDOW) {
      block_type[chanNum]=LONG_SHORT_WINDOW;
      }
      else {
	block_type[chanNum]=ONLY_LONG_WINDOW;
      }
      desired_block_type[chanNum]=next_desired_block_type[chanNum];
    }
  }

//	printf("%d\t\n", block_type[0]);
//	block_type[0] = ONLY_LONG_WINDOW;
//	block_type[1] = ONLY_LONG_WINDOW;
//	block_type[0] = ONLY_SHORT_WINDOW;
//	block_type[1] = ONLY_SHORT_WINDOW;

  {
	  int chanNum;

	  for (chanNum = 0; chanNum < max_ch; chanNum++) {
		  /* Set window shape paremeter in quantInfo */
		  switch( block_type[chanNum] ) {
		  case ONLY_SHORT_WINDOW:
		  case LONG_SHORT_WINDOW:
			  quantInfo[chanNum].prev_window_shape = quantInfo[chanNum].window_shape;
			  quantInfo[chanNum].window_shape = WS_SIN;
			  break;
		  case ONLY_LONG_WINDOW:
		  case SHORT_LONG_WINDOW:
			  quantInfo[chanNum].prev_window_shape = quantInfo[chanNum].window_shape;
			  quantInfo[chanNum].window_shape = WS_KBD;
			  break;
		  }
	  }
  }

  {
    int chanNum;

    for (chanNum=0;chanNum<max_ch;chanNum++) {
      switch( block_type[chanNum] ) {
        case ONLY_SHORT_WINDOW:

        quantInfo[chanNum].max_sfb = max_sfb_s[quantInfo[chanNum].srate_idx];
        quantInfo[chanNum].num_window_groups = 8;
        quantInfo[chanNum].window_group_length[0] = 1;
        quantInfo[chanNum].window_group_length[1] = 1;
        quantInfo[chanNum].window_group_length[2] = 1;
        quantInfo[chanNum].window_group_length[3] = 1;
        quantInfo[chanNum].window_group_length[4] = 1;
        quantInfo[chanNum].window_group_length[5] = 1;
        quantInfo[chanNum].window_group_length[6] = 1;
        quantInfo[chanNum].window_group_length[7] = 1;
        break;

        default:
        quantInfo[chanNum].max_sfb = max_sfb_l[quantInfo[chanNum].srate_idx];
        quantInfo[chanNum].num_window_groups = 1;
        quantInfo[chanNum].window_group_length[0]=1;
        break;
      }
    }
  }

  {
    int chanNum;
    for (chanNum=0;chanNum<max_ch;chanNum++) {
      /* Count number of bits used for gain_control_data */
      used_bits += WriteGainControlData(NULL,0); /* Zero write flag means don't write */
    }
  }


  /*****************************************************************************
  * T/F mapping (MDCT)
  *****************************************************************************/
  {
    int chanNum, k;
    for (chanNum=0;chanNum<max_ch;chanNum++) {
      buffer2freq(
		  DTimeSigBuf[chanNum],
		  spectral_line_vector[chanNum],
		  overlap_buffer[chanNum],
		  block_type[chanNum],
		  quantInfo[chanNum].window_shape,
		  quantInfo[chanNum].prev_window_shape,
		  MOVERLAPPED
		  );

      if (block_type[chanNum] == ONLY_SHORT_WINDOW) {
	for (k = 0; k < 8; k++) {
	  specFilter(spectral_line_vector[chanNum]+k*BLOCK_LEN_SHORT, spectral_line_vector[chanNum]+k*BLOCK_LEN_SHORT, as->out_sampling_rate, as->cut_off, BLOCK_LEN_SHORT);
        }
      }
      else {
	specFilter(spectral_line_vector[chanNum], spectral_line_vector[chanNum], as->out_sampling_rate, as->cut_off, BLOCK_LEN_LONG);
      }
    }
  }

  /*****************************************************************************
  * adapt ratios of psychoacoustic module to codec scale factor bands
  *****************************************************************************/

  {
    int chanNum;
    for (chanNum=0;chanNum<max_ch;chanNum++) {
      switch( block_type[chanNum] ) {
	case ONLY_LONG_WINDOW:
	  memcpy( (char*)sfb_width_table[chanNum], (char*)quantInfo[chanNum].sr_info->cb_width_long, (NSFB_LONG+1)*sizeof(int) );
	  nr_of_sfb[chanNum] = quantInfo[chanNum].sr_info->num_cb_long;
	  p_ratio[chanNum]   = p_ratio_long[ps][chanNum];
	  break;
        case LONG_SHORT_WINDOW:
	  memcpy( (char*)sfb_width_table[chanNum], (char*)quantInfo[chanNum].sr_info->cb_width_long, (NSFB_LONG+1)*sizeof(int) );
	  nr_of_sfb[chanNum] = quantInfo[chanNum].sr_info->num_cb_long;
	  p_ratio[chanNum]   = p_ratio_long[ps][chanNum];
	  break;
        case ONLY_SHORT_WINDOW:
	  memcpy( (char*)sfb_width_table[chanNum], (char*)quantInfo[chanNum].sr_info->cb_width_short, (NSFB_SHORT+1)*sizeof(int) );
	  nr_of_sfb[chanNum] = quantInfo[chanNum].sr_info->num_cb_short;
	  p_ratio[chanNum]   = p_ratio_short[ps][chanNum];
          break;
        case SHORT_LONG_WINDOW:
	  memcpy( (char*)sfb_width_table[chanNum], (char*)quantInfo[chanNum].sr_info->cb_width_long, (NSFB_LONG+1)*sizeof(int) );
	  nr_of_sfb[chanNum] = quantInfo[chanNum].sr_info->num_cb_long;
	  p_ratio[chanNum]   = p_ratio_long[ps][chanNum];
          break;
      }
    }
  }

  MSPreprocess(p_ratio_long[!ps], p_ratio_short[!ps], chpo_long, chpo_short,
		block_type, quantInfo, as->use_MS, max_ch);

  MSEnergy(spectral_line_vector, energy, chpo_long, chpo_short, sfb_width_table,
		block_type, quantInfo, as->use_MS, max_ch);

  {
    int chanNum;
    for (chanNum=0;chanNum<max_ch;chanNum++) {
      /* Construct sf band offset table */
      int offset=0;
      int sfb;
      for (sfb=0;sfb<nr_of_sfb[chanNum];sfb++) {
	sfb_offset_table[chanNum][sfb] = offset;
	offset+=sfb_width_table[chanNum][sfb];
      }
      sfb_offset_table[chanNum][nr_of_sfb[chanNum]]=offset;
    }
  }


  /************************************************************************
   Set upper spectral coefficients to zero for LFE
   ************************************************************************/
  {
    int chanNum;
    for (chanNum=0;chanNum<max_ch;chanNum++) {
      if (quantInfo[chanNum].channelInfo.lfe) {
        int i;
        for (i = sfb_offset_table[chanNum][10];
			i < sfb_offset_table[chanNum][nr_of_sfb[chanNum]]; i++)
          spectral_line_vector[chanNum][i] = 0;
      }
    }
  }

  /*****************************************************************************
  * quantization and coding
  *****************************************************************************/
  {
//  int padding_limit = max_bitreservoir_bits;
    int maxNumBitsByteAligned;
    int chanNum;
    int numFillBits;
    int bitsLeftAfterFill;
    int orig_used_bits;

    /* bit budget */
    num_bits_available = (long)(average_bits + available_bitreservoir_bits - used_bits);

    /* find the largest byte-aligned section with fewer bits than num_bits_available */
    maxNumBitsByteAligned = ((num_bits_available >> 3) << 3);

    /* Compute how many reservoir bits can be used and still be able to byte */
    /* align without exceeding num_bits_available, and have room for an ID_END marker   */
    available_bitreservoir_bits = maxNumBitsByteAligned - LEN_SE_ID - average_bits;

    /******************************************/
    /* Perform TNS analysis and filtering     */
    /******************************************/
    for (chanNum=0;chanNum<max_ch;chanNum++) {
		if (!quantInfo[chanNum].channelInfo.lfe) {
			error = TnsEncode(&quantInfo[chanNum],
				nr_of_sfb[chanNum],            /* Number of bands per window */
				block_type[chanNum],
				sfb_offset_table[chanNum],
				spectral_line_vector[chanNum],
				as->use_TNS);
			if (error == FERROR)
				return FERROR;
		} else {
			quantInfo[chanNum].tnsInfo.tnsDataPresent=0;      /* TNS not used for LFE */
		}
    }

    /*******************************************************************************/
    /* If LTP prediction is used, compute LTP predictor info and residual spectrum */
    /*******************************************************************************/
    for(chanNum=0;chanNum<max_ch;chanNum++) {
      if(as->use_LTP && quantInfo[chanNum].channelInfo.present &&
		  (!quantInfo[chanNum].channelInfo.lfe) && (block_type[chanNum] != ONLY_SHORT_WINDOW)) {
        if(quantInfo[chanNum].channelInfo.cpe) {
    	  if(quantInfo[chanNum].channelInfo.ch_is_left) {
	    int i;
	    int leftChan=chanNum;
	    int rightChan=quantInfo[chanNum].channelInfo.paired_ch;

  	    ltp_enc(spectral_line_vector[leftChan],
		        tmp_DTimeSigBuf[leftChan],
		        block_type[leftChan],
		        WS_SIN,
		        &sfb_offset_table[leftChan][0],
		        nr_of_sfb[leftChan],
		        &quantInfo[leftChan].ltpInfo);

            quantInfo[rightChan].ltpInfo.global_pred_flag = quantInfo[leftChan].ltpInfo.global_pred_flag;
  	    for(i = 0; i < BLOCK_LEN_LONG; i++)
    	      quantInfo[rightChan].ltpInfo.pred_mdct[i] = quantInfo[leftChan].ltpInfo.pred_mdct[i];
  	    for(i = 0; i < MAX_SCFAC_BANDS; i++)
  	      quantInfo[rightChan].ltpInfo.sfb_prediction_used[i] = quantInfo[leftChan].ltpInfo.sfb_prediction_used[i];
  	    quantInfo[rightChan].ltpInfo.weight = quantInfo[leftChan].ltpInfo.weight;
	    quantInfo[rightChan].ltpInfo.delay[0] = quantInfo[leftChan].ltpInfo.delay[0];

	    if (!quantInfo[leftChan].channelInfo.common_window) {
	      ltp_enc(spectral_line_vector[rightChan],
			  tmp_DTimeSigBuf[rightChan],
			  block_type[rightChan],
			  WS_SIN,
			  &sfb_offset_table[rightChan][0],
			  nr_of_sfb[rightChan],
			  &quantInfo[rightChan].ltpInfo);
            }
          } /* if(channelInfo[chanNum].ch_is_left) */
        } /* if(channelInfo[chanNum].cpe) */
        else
	  ltp_enc(spectral_line_vector[chanNum],
		      tmp_DTimeSigBuf[chanNum],
		      block_type[chanNum],
		      WS_SIN,
		      &sfb_offset_table[chanNum][0],
		      nr_of_sfb[chanNum],
		      &quantInfo[chanNum].ltpInfo);
      } /* if(channelInfo[chanNum].present... */
      else
        quantInfo[chanNum].ltpInfo.global_pred_flag = 0;
    } /* for(chanNum... */

    /******************************************/
    /* Apply MS stereo                        */
    /******************************************/
    if (as->use_MS == 1) {
      MSEncode(spectral_line_vector,
	       sfb_offset_table,
	       block_type,
	       quantInfo,
	       max_ch);
    }
    else if (as->use_MS == 0) {
      MSEncodeSwitch(spectral_line_vector,
		     sfb_offset_table,
		     quantInfo,
		     max_ch
			 );
    }

    /************************************************/
    /* Call the AAC quantization and coding module. */
    /************************************************/
    for (chanNum = 0; chanNum < max_ch; chanNum++) {
      int bitsToUse;
	  if (!as->lfePresent) {
		  bitsToUse = (int)((average_bits - used_bits)/max_ch);
		  bitsToUse += (int)(0.2*available_bitreservoir_bits/max_ch);
	  } else {
		  /* Calculation of reduced bitrate for LFE */
		  double lfeBitRatio = 0.14;       /* ratio of LFE bits to bits of one SCE */
		  int lfeBits = max(200,(int)((average_bits - used_bits) * lfeBitRatio / (max_ch - 1))); /* number of bits for LFE */ 
		  
		  if (quantInfo[chanNum].channelInfo.lfe) {
			  bitsToUse = lfeBits;
			  bitsToUse += (int)(0.2*available_bitreservoir_bits 
				  * lfeBitRatio / (max_ch - 1));
		  } else {
			  bitsToUse = (int)((average_bits - used_bits - lfeBits) / (max_ch - 1));
			  bitsToUse += (int)(0.2*available_bitreservoir_bits 
				  * (1 - lfeBitRatio / (max_ch - 1)) / (max_ch - 1));
		  }
	  }

      error = aacQuantize(&quantInfo[chanNum],
		  &spectral_line_vector[chanNum],
		  &p_ratio[chanNum],
		  &allowed_distortion[chanNum],
		  &energy[chanNum],
		  &block_type[chanNum],
		  &sfb_width_table[chanNum],
		  bitsToUse,
		  fixed_stream,
		  &reconstructed_spectrum[chanNum]		  
		  );
      if (error == FERROR)
        return error;
    }

    /**********************************************************/
    /* Reconstruct MS Stereo bands for prediction            */
    /**********************************************************/
    if (as->use_MS != -1) {
      MSReconstruct(reconstructed_spectrum,
		    sfb_offset_table,
//		    block_type,
		    quantInfo,
		    max_ch);
    }

    /**********************************************************/
    /* Update LTP history buffer                              */
    /**********************************************************/
    if(as->use_LTP)
      for (chanNum=0;chanNum<max_ch;chanNum++) {
		  if (!quantInfo[chanNum].channelInfo.lfe) {  /* no reconstruction needed for LFE channel*/
			  ltp_reconstruct(reconstructed_spectrum[chanNum],
				  block_type[chanNum],
				  WS_SIN,
				  &sfb_offset_table[chanNum][0],
				  nr_of_sfb[chanNum],
				  &quantInfo[chanNum].ltpInfo);
		  }
      }


    /**********************************/
    /* Write out all encoded channels */
    /**********************************/
    used_bits = 0;
    if (as->header_type==ADTS_HEADER)
      used_bits += WriteADTSHeader(&quantInfo[0], fixed_stream, used_bits, 0);

    for (chanNum=0;chanNum<max_ch;chanNum++) {
      if (quantInfo[chanNum].channelInfo.present) {
        /* Write out a single_channel_element */
        if (!quantInfo[chanNum].channelInfo.cpe) {
           if (quantInfo[chanNum].channelInfo.lfe) {
			   /* Write out lfe */ 
			   used_bits += WriteLFE(&quantInfo[chanNum],   /* Quantization information */
				   quantInfo[chanNum].channelInfo.tag,
				   fixed_stream,           /* Bitstream */
				   0);                     /* Write flag, 1 means write */
           } else {
			   /* Write out sce */
			   used_bits += WriteSCE(&quantInfo[chanNum],   /* Quantization information */
				   quantInfo[chanNum].channelInfo.tag,
				   fixed_stream,           /* Bitstream */
				   0);                     /* Write flag, 1 means write */
		   }
        }
        else {
	  if (quantInfo[chanNum].channelInfo.ch_is_left) {
	    /* Write out cpe */
	    used_bits += WriteCPE(&quantInfo[chanNum],   /* Quantization information,left */
				  &quantInfo[quantInfo[chanNum].channelInfo.paired_ch],   /* Right */
				  quantInfo[chanNum].channelInfo.tag,
				  quantInfo[chanNum].channelInfo.common_window,    /* common window */
				  &(quantInfo[chanNum].channelInfo.ms_info),
				  fixed_stream,           /* Bitstream */
				  0);                     /* Write flag, 1 means write */
          }
        }  /* if (!channelInfo[chanNum].cpe)  else */
      } /* if (chann...*/
    } /* for (chanNum...*/

    orig_used_bits = used_bits;

    /* Compute how many fill bits are needed to avoid overflowing bit reservoir */
    /* Save room for ID_END terminator */
    if (used_bits < (8 - LEN_SE_ID) ) {
      numFillBits = 8 - LEN_SE_ID - used_bits;
    }
    else {
      numFillBits = 0;
    }

    /* Write AAC fill_elements, smallest fill element is 7 bits. */
    /* Function may leave up to 6 bits left after fill, so tell it to fill a few extra */
    numFillBits += 6;
    bitsLeftAfterFill=WriteAACFillBits(fixed_stream,numFillBits, 0);
    used_bits += (numFillBits - bitsLeftAfterFill);

    /* Write ID_END terminator */
    used_bits += LEN_SE_ID;

    /* Now byte align the bitstream */
    used_bits += ByteAlign(fixed_stream, 0);

    if (as->header_type==ADTS_HEADER)
      WriteADTSHeader(&quantInfo[0], fixed_stream, used_bits, 1);

    for (chanNum=0;chanNum<max_ch;chanNum++) {
      if (quantInfo[chanNum].channelInfo.present) {
        /* Write out a single_channel_element */
        if (!quantInfo[chanNum].channelInfo.cpe) {
           if (quantInfo[chanNum].channelInfo.lfe) {
			   /* Write out lfe */ 
			   WriteLFE(&quantInfo[chanNum],   /* Quantization information */
				   quantInfo[chanNum].channelInfo.tag,
				   fixed_stream,           /* Bitstream */
				   1);                     /* Write flag, 1 means write */
           } else {
			   /* Write out sce */
			   WriteSCE(&quantInfo[chanNum],   /* Quantization information */
				   quantInfo[chanNum].channelInfo.tag,
				   fixed_stream,           /* Bitstream */
				   1);                     /* Write flag, 1 means write */
		   }
        }
        else {
       	  if (quantInfo[chanNum].channelInfo.ch_is_left) {
	    /* Write out cpe */
	    WriteCPE(&quantInfo[chanNum],   /* Quantization information,left */
		     &quantInfo[quantInfo[chanNum].channelInfo.paired_ch],   /* Right */
		     quantInfo[chanNum].channelInfo.tag,
		     quantInfo[chanNum].channelInfo.common_window,    /* common window */
		     &(quantInfo[chanNum].channelInfo.ms_info),
		     fixed_stream,           /* Bitstream */
		     1);                     /* Write flag, 1 means write */
          }
        }  /* if (!channelInfo[chanNum].cpe)  else */
      } /* if (chann...*/
    } /* for (chanNum...*/

    /* Compute how many fill bits are needed to avoid overflowing bit reservoir */
    /* Save room for ID_END terminator */
    if (orig_used_bits < (8 - LEN_SE_ID) ) {
    numFillBits = 8 - LEN_SE_ID - used_bits;
    }
    else {
      numFillBits = 0;
    }

    /* Write AAC fill_elements, smallest fill element is 7 bits. */
    /* Function may leave up to 6 bits left after fill, so tell it to fill a few extra */
    numFillBits += 6;
    bitsLeftAfterFill=WriteAACFillBits(fixed_stream,numFillBits, 1);

    /* Write ID_END terminator */
    BsPutBit(fixed_stream,ID_END,LEN_SE_ID);

    /* Now byte align the bitstream */
    ByteAlign(fixed_stream, 1);

  } /* End of quantization and coding */
  return FNO_ERROR;
}