/**********************************************************************
MPEG-4 Audio VM
Bit stream module



This software module was originally developed by

Bernhard Grill (University of Erlangen)

and edited by

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.

*/

/* 23-oct-97   HP   merged Nokia's predictor 971013 & 971020 */
/*                  tried to fix PRED_TYPE */
/* 24-oct-97   Mikko Suonio   fixed PRED_TYPE */


#include <memory.h>
#include <math.h>
#include <string.h>
#include "dec.h"
#include "bitstream.h"
#include "common.h"
#include "util.h"

/* ---  AAC --- */
#include "aac.h"
#include "nok_bwp_enc.h"
#include "nok_ltp_enc.h"
#include "tns3.h"
#include "aac_qc.h"
#include "util.h"
#include "fir_filt.h"
#include "scaleable.h"
#include "dec.h"
#include "enc.h"
#include "bitmux.h"
#include "bitstream.h"
#include "celp_encoder.h"
#include "celp_decoder.h"
#include "flex_mux.h"
#define MAX_TF_LAYERS 5

/* --- TVQ --- */
#include "ntt_conf.h"
#include "ntt_scale_conf.h"

/* --- BSAC --- */
#include "sam_encode.h"

typedef struct {
  int ch_no_core;
  int ch_no_tf[MAX_TF_LAYERS];
  int ch_no_max;
  int tf_layers;
} OP_MODE_INFO;

OP_MODE_INFO opm_info[16] = {
  { 1, {0,0,0,0,0}, 1, 0 },
  { 2, {0,0,0,0,0}, 2, 0 },
  { 0, {1,0,0,0,0}, 1, 1 },
  { 0, {2,0,0,0,0}, 2, 1 },
  { 1, {1,0,0,0,0}, 1, 1 },
  { 1, {2,0,0,0,0}, 2, 1 },
  { 2, {2,0,0,0,0}, 2, 1 },
  { 1, {1,1,0,0,0}, 1, 2 },
  { 1, {1,2,0,0,0}, 2, 2 },
  { 1, {2,2,0,0,0}, 2, 2 },
  { 2, {2,2,0,0,0}, 2, 2 },
  { 0, {1,1,0,0,0}, 1, 2 },
  { 0, {1,2,0,0,0}, 2, 2 },
  { 0, {2,2,0,0,0}, 2, 2 },
  { 0, {1,1,1,0,0}, 1, 3 },
};

static FIR_FILT *lowpassFilt;
static int  downsamplFac;
static   BsBitBuffer *tmpBitBuf;
static   BsBitBuffer *dynpartBuf;
static   BsBitBuffer *fixedPartBuf[3];
static float *coreDecodedSampleBuf[MAX_TIME_CHANNELS];
static double *diffSpectrum[MAX_TIME_CHANNELS];
static int granule=0;
static int numGranules=3;

static int op_mode = 4;
static int diffContrSimu = 0;
static int intermediate_layers = 0;


/* Prediction */
static PRED_TYPE pred_type = PRED_NONE;
static NOK_LT_PRED_STATUS nok_lt_status[MAX_TIME_CHANNELS];
static NOK_BW_PRED_STATUS nok_bwp_status[MAX_TIME_CHANNELS];

/* MPEG 4 Celp core */
static long  bit_rate, sampling_frequency, frame_size, n_subframes, sbfrm_size, lpc_order;
static long  num_lpc_indices, num_shape_cbks, num_gain_cbks, *org_frame_bit_allocation;
static float min_pitch_frequency, max_pitch_frequency;    
static long SampleRateMode     = fs8kHz;  /* Default: 16 kHz */
static long QuantizationMode   = VectorQuantizer;  /* Default: Scalar Quantizer */
static long FineRateControl    = 1;  /* Default: FineRateControl is ON */
static long LosslessCodingMode = 0;  /* Default: Lossless coding is OFF */
static long WB_Configuration;
static long Wideband_VQ = 0;
static long NB_Configuration;
static long NumEnhLayers;
static long BandwidthScalabilityMode;
static long BWS_configuration;
static long BWS_nb_bitrate;

static long n_lpc_analysis;
static long *window_offsets;
static long *window_sizes;
static long n_lag_candidates; 

/* NTT Twin VQ */
static int ntt_InitFlag = 1;
static ntt_INDEX ntt_index;
static ntt_INDEX ntt_index_scl;
static int bitsPerFrame;

static	void *InstanceContextLPCEnc;	/* one instance context */
static	void *InstanceContextLPCDec;	/* one instance context */

static long samplRateCore;

extern int samplFreqIndex[];

int aacScaleEncInit( 
  BsBitStream *headerStream,
  char        *encPara,		 /* in: encoder parameter string */
  int         numChannel,
  int         frameNumSample,
  long        samplRate,
  ENC_FRAME_DATA* frameData,
  enum CORE_CODEC coreCodecIdx,
  int mode)
{
  int frameNumSampleCore, delayNumSampleCore;
  
  
  int tmp, ch, i, core_delay;
  char *pc;
  
  core_delay = 0;

  if( (pc=strstr( encPara, "-aac_simulcast" )) ) {
    sscanf( pc+14, "%1d", &diffContrSimu );
    if (diffContrSimu)
      fprintf (stdout,"aac scalable mode : using simulcast (no difference coding)\n");
    else
      fprintf (stdout,"aac scalable mode : using difference coding  for all bands \n");
  }
  if (frameData){
    op_mode=frameData->opMode;
  } else {
    op_mode=mode;
  }
  switch( op_mode ) {
    case 3:
    case 5:
    case 6:
    case 8:
    case 9:
    case 10:
    case 12:
    case 13:
      if( numChannel < 2 ) {
        CommonExit(1,"Encode scalab.: Stereo scalability mode selected, but mono input file");
      }
  }


  /* write object descriptor in case of aac_sys */
  if( frameData!=NULL ) {
    int sx;
    int layer, numLayers;
    int coreLayer;

    coreLayer = (opm_info[op_mode].ch_no_core==0)?0:1;

    /* get the total number of layers: AAC + core */
    numLayers = opm_info[op_mode].tf_layers + coreLayer;
    initObjDescr(frameData->od);
    presetObjDescr(frameData->od, numLayers);
    frameData->od->streamCount.value=numLayers;

    /* write ES descriptor of core layer */
    if (coreLayer) {
      initESDescr( &(frameData->od->ESDescriptor[0]),0); /* only TF coders */
      presetESDescr( frameData->od->ESDescriptor[0], 0);
      frameData->od->ESDescriptor[0]->DecConfigDescr.avgBitrate.value=frameData->layer[0].bitRate;
      for (sx=0;sx<16;sx++) { if (frameData->layer[0].sampleRate== samplFreqIndex[sx]) break;};
      if (sx >= 16) CommonExit(-1,"\nSampling rate not supported");
      frameData->od->ESDescriptor[0]->DecConfigDescr.audioSpecificConfig.samplingFreqencyIndex.value = sx;  
      frameData->od->ESDescriptor[0]->DecConfigDescr.bufferSizeDB.value=6122;
      frameData->od->ESDescriptor[0]->DecConfigDescr.audioSpecificConfig.specConf.TFSpecificConfig.TFCodingType.value = 0x2; /* Twin VQ */
      frameData->od->ESDescriptor[0]->DecConfigDescr.audioSpecificConfig.specConf.TFSpecificConfig.frameLength.value=0;/* 0: 1023; 1: 960 */
    }

    for(layer=coreLayer; layer<numLayers; layer++) {
      initESDescr( &(frameData->od->ESDescriptor[layer]), 0);
      presetESDescr( frameData->od->ESDescriptor[layer], layer);
      frameData->od->ESDescriptor[layer]->DecConfigDescr.avgBitrate.value=frameData->layer[layer].bitRate;
      for (sx=0;sx<16;sx++) { if (frameData->layer[layer].sampleRate== samplFreqIndex[sx]) break;} ; 
      frameData->od->ESDescriptor[layer]->DecConfigDescr.audioSpecificConfig.samplingFreqencyIndex.value = sx; 
      frameData->od->ESDescriptor[layer]->DecConfigDescr.bufferSizeDB.value=6122;
      frameData->od->ESDescriptor[layer]->DecConfigDescr.audioSpecificConfig.specConf.TFSpecificConfig.TFCodingType.value = 0x0; /* AAC scalable */
      if(strstr(encPara, "-aac_sys_bsac"))
        frameData->od->ESDescriptor[layer]->DecConfigDescr.audioSpecificConfig.specConf.TFSpecificConfig.TFCodingType.value = 0x1; /* BSAC */
      frameData->od->ESDescriptor[layer]->DecConfigDescr.audioSpecificConfig.specConf.TFSpecificConfig.frameLength.value=0;/* 0: 1023; 1: 960 */
    }

    advanceODescr (  headerStream, frameData->od,1) ;
    for (layer=0; layer<numLayers; layer++) {
      advanceESDescr ( headerStream, frameData->od->ESDescriptor[layer] ,1) ;      
    }
  }
  /* allocate memory */
  tmpBitBuf = BsAllocBuffer(8000);

  for(i=0;i<numGranules;i++){
    fixedPartBuf[i] =BsAllocBuffer(300);
  }
  dynpartBuf =BsAllocBuffer(numGranules*6000);

  for (ch=0; ch<numChannel; ch++){
    if ((coreDecodedSampleBuf[ch]=(float*)malloc(frameNumSample*sizeof(float)))==NULL)
      CommonExit(1,"Encode scalab.: memory allocation error");
    if ((diffSpectrum[ch]=(double*)malloc(frameNumSample*sizeof(double)))==NULL)
      CommonExit(1,"Encode scalab.: memory allocation error");
  }

  /* core coder initialization */
  samplRateCore = 8000;
  if( (samplRate%11025) == 0 ) {
    samplRateCore = 44100/6;
  }


  switch( coreCodecIdx ) {
   case CC_G729:
     lowpassFilt = initFirLowPass( samplRate/4000, 120 );
     downsamplFac = samplRate/samplRateCore;
     EncG729Init( 1 /* numChannel */, (float)samplRateCore, 8000.0, encPara, &frameNumSampleCore, &delayNumSampleCore, NULL );
     DecG729Init( 1, (float)samplRateCore, 8000, "", NULL, &tmp, &tmp );
     core_delay = 660;
     break;

   case CC_CELP_MPEG4_60:
    {

     BITSTREAM *p_bitstream;
     int bit_rate = 6000;
     BsBitBuffer *coreBitBuf;
     
     lowpassFilt = initFirLowPass( samplRate/4000, 120 );
     downsamplFac = samplRate/samplRateCore;
     coreBitBuf = BsAllocBuffer(2000);

     if((p_bitstream=(BITSTREAM *)malloc(sizeof(BITSTREAM)))==NULL) {
       CommonExit(1, "Memory allocation error for enc_lpc init in scal_enc_frame.c");
     }
     
     p_bitstream->p_bitstream_buffer_start = coreBitBuf->data;
     p_bitstream->buffer_length            = ((coreBitBuf->size)+7)/8;
     p_bitstream->valid_bits               = 0;
     p_bitstream->start_offset             = 0;
     
     SampleRateMode           = fs8kHz;
     QuantizationMode         = VectorQuantizer;
     FineRateControl          = OFF;
     LosslessCodingMode       = OFF;
     NumEnhLayers             = 0;
     BandwidthScalabilityMode = OFF;
     Wideband_VQ              = OFF;
     BWS_nb_bitrate           = 0;

     celp_initialisation_encoder ( 
       p_bitstream,                 /*1                     */   
       bit_rate,		    /*2in: bit rate */
       samplRateCore,               /*3in: sampling frequency */
       SampleRateMode,              /*4In: SampleRate Mode               */
       QuantizationMode,            /*5In: Type of Quantization          */
       FineRateControl,             /*6In: Fine Rate Control switch      */
       LosslessCodingMode,          /*7In: Lossless Coding Mode          */
       &WB_Configuration,           /*8In: Wideband configuration        */
       Wideband_VQ,                 /*9Out: Wideband VQ mode             */
       &NB_Configuration,           /*0Out: Narrowband configuration     */
       NumEnhLayers,                /*1In: Number of Enhancement Layers  */
       BandwidthScalabilityMode,    /*2In: bandwidth switch              */
       &BWS_configuration,          /*3Out: BWS_configuration            */
       BWS_nb_bitrate,              /*4In: narrowband bitrate for BWS    */
       &frame_size, 		/*5out: frame size */
       &n_subframes,	    /*6out: number of subframes */
       &sbfrm_size,	    /*7out: subframe size */
       &lpc_order,			/*8out: LP analysis order */
       &num_lpc_indices,	/*9out: number of LPC indices */
       &num_shape_cbks,	/* out:0number of shape indices */
       &num_gain_cbks,	    /*1out: number of gain indices */
       &n_lpc_analysis,    /*2out: number of LP analysis per frame */
       &window_offsets,    /*3out: window size for each LP analysis */
       &window_sizes,      /*4out: window offset for each LP analysis */
       &n_lag_candidates,	/*5out: number of pitch candidates */
       &min_pitch_frequency,    /*6out: minimum pitch frequency */
       &max_pitch_frequency,    /*7out: maximum pitch frequency */
       &org_frame_bit_allocation, /*8out: bit number for each index */
       InstanceContextLPCEnc /*9in/out: instance context */
     );

     celp_initialisation_decoder (
       p_bitstream,
       bit_rate,		 /* in: bit rate */
       0,                   /* In: complexity level decoder*/
       0,                   /* In: reduced order decoder   */
       0,                   /* DecEnhStage */
       0,                   /* DecBwsMode */
       0,                   /* disable postfilter */
       &frame_size, 	 /* out: frame size */
       &n_subframes,	 /* out: number of  subframes */
       &sbfrm_size,	 /* out: subframe size */ 
       &lpc_order,		 /* out: LP analysis order */
       &num_lpc_indices,	 /* out: number of LPC indices */
       &num_shape_cbks,	 /* out: number of shape indices */
       &num_gain_cbks,	 /* out: number of gain indices */
       &org_frame_bit_allocation, /* out: bit number of each index */
       &SampleRateMode,            /* Out: SampleRate Mode            */    
       &QuantizationMode,          /* Out: Type of Quantization   */        
       &FineRateControl,           /* Out: Fine Rate Control switch*/       
       &LosslessCodingMode,        /* Out: Lossless Coding Mode   */        
       &WB_Configuration,          /* Out: Wideband configuration */        
       &Wideband_VQ,               /* Out: Wideband VQ mode           */
       &NB_Configuration,          /* Out: Narrowband configuration*/       
       &NumEnhLayers,              /* Out: Number of Enhancement Layers */
       &BandwidthScalabilityMode,  /* Out: bandwidth switch           */    
       &BWS_configuration,          /* Out: BWS_configuration              */
       InstanceContextLPCDec       /* in/out: instance context */
     );

     core_delay = 660;

     free(p_bitstream);
     BsFreeBuffer( coreBitBuf );
    }
    break;
  case NTT_TVQ:
    /* only for TVQ core coder with AAC enhancement layers 
       */
    {

      float bit_rate_scl = 0.0F;
      long numChannel = 1;
      int med_win_in_long,short_win_in_long;

      bit_rate = frameData->layer[0].bitRate;
      fprintf(stdout,"\ncore bitrate: %d  kbit/sec \n",bit_rate);
      core_delay = 0;
      bitsPerFrame = (int)(((float)bit_rate/(float)samplRate)*(float)frameNumSample);

      ntt_TfInit((float)samplRate,(float)bit_rate,
                 bit_rate_scl, numChannel,
                 &frameNumSampleCore, &delayNumSampleCore,
                 &med_win_in_long,
                 &short_win_in_long);
      if ((frameNumSampleCore != 1024) ||
          (short_win_in_long !=8))
        CommonExit( 1, "Initialization of TVQ core failed (parameters incompatible with AAC settings)");

      ntt_TBITS_FR_SCL = 0;

      if(ntt_ISAMPF==48){
	ntt_BAND_LOWER_ID_SCL[0] = ntt_BW_0;   /*2ndlayer 16kbps:from 0 to 8kHz*/
	ntt_BAND_UPPER_ID_SCL[0] = ntt_BW_1_3;
	ntt_BAND_LOWER_ID_SCL[1] = ntt_BW_1_6; /*3rdlayer 24kbps:from 4 to 12kHz*/
	ntt_BAND_UPPER_ID_SCL[1] = ntt_BW_p5;
	ntt_BAND_LOWER_ID_SCL[2] = ntt_BW_0;   /*4thlayer 32kbps:from 0 to 8kHz*/
	ntt_BAND_UPPER_ID_SCL[2] = ntt_BW_1_3;
	ntt_BAND_LOWER_ID_SCL[3] = ntt_BW_1_3; /*5thlayer 40kbps:from 8 to 16kHz*/
	ntt_BAND_UPPER_ID_SCL[3] = ntt_BW_2_3;
	ntt_BAND_LOWER_ID_SCL[4] = ntt_BW_1_3; /*6thlayer 48kbps:from 8 to 16kHz*/
	ntt_BAND_UPPER_ID_SCL[4] = ntt_BW_2_3;
	ntt_BAND_LOWER_ID_SCL[5] = ntt_BW_2_3; /*7thlayer 56kbps:from 16 to 24kHz*/
	ntt_BAND_UPPER_ID_SCL[5] = ntt_BW_1p0;
	ntt_BAND_LOWER_ID_SCL[6] = ntt_BW_0;   /*8thlayer 64kbps:from 0 to 8kHz*/
	ntt_BAND_UPPER_ID_SCL[6] = ntt_BW_1_3;
      }
      else if(ntt_ISAMPF==24){
	ntt_BAND_LOWER_ID_SCL[0] = ntt_BW_0;/*2ndlayer 16kbps:from 0 to 8kHz*/
	ntt_BAND_UPPER_ID_SCL[0] = ntt_BW_2_3;
	ntt_BAND_LOWER_ID_SCL[1] = ntt_BW_1_3;/*3rdlayer 24kbps:from 4 to 12kHz*/
	ntt_BAND_UPPER_ID_SCL[1] = ntt_BW_1p0;
	ntt_BAND_LOWER_ID_SCL[2] = ntt_BW_0;/*4thlayer 32kbps:from 0 to 8kHz*/         ntt_BAND_UPPER_ID_SCL[2] = ntt_BW_2_3;
	ntt_BAND_LOWER_ID_SCL[3] = ntt_BW_1_3;/*5thlayer 40kbps:dummy*/
	ntt_BAND_UPPER_ID_SCL[3] = ntt_BW_1p0;
	ntt_BAND_LOWER_ID_SCL[4] = ntt_BW_0;/*6thlayer 48kbps:dummy*/
	ntt_BAND_UPPER_ID_SCL[4] = ntt_BW_2_3;
	ntt_BAND_LOWER_ID_SCL[5] = ntt_BW_1_3;/*7thlayer 56kbps:dummy*/
	ntt_BAND_UPPER_ID_SCL[5] = ntt_BW_1p0;
	ntt_BAND_LOWER_ID_SCL[6] = ntt_BW_0;  /*8thlayer 64kbps:dummy*/
	ntt_BAND_UPPER_ID_SCL[6] = ntt_BW_2_3;
      }

      
    }
    break;
  case NO_CORE:
    core_delay=0;
    break;     
  default:
    CommonExit( 1, "Encode scalab. init: core coder not yet supported" );
  }


  /* initialize Nokia's predictors */
  if (pred_type == NOK_LTP)
    nok_init_lt_pred (&nok_lt_status[MONO_CHAN]);

  if (pred_type == NOK_BWP)
    nok_InitPrediction (0);

  return( core_delay );
}

/********************************************************************************/

/********************************************************************************/

static void aacEncodeScalFrameHeader(
  BsBitStream     *fixedStream,
  int             op_mode,
  enum CORE_CODEC core_cc,
  long            samplRate,
  long            bitRate,
  int             intermediate_layers,
  int             mainDataBegin,
  ENC_FRAME_DATA* frameData
)
{
    BsPutBit( fixedStream, 0x37 , 7 );        /* syncword */

    BsPutBit( fixedStream, op_mode , 4 );     /* opMode */

    if( opm_info[op_mode].ch_no_core > 0 ) {
      BsPutBit( fixedStream,  core_cc , 4 );    /* coreCodecIdx*/
    }
    
    if( ( op_mode >= 7 ) && ( op_mode <= 13 ) ){
      BsPutBit( fixedStream, intermediate_layers, 2 );        /* number of intermediate layers */
    }
    
    BsPutBit( fixedStream, getSamplIdx(samplRate) , 4 ); /* mainSamplingFreqIdx */
    
    BsPutBit( fixedStream, getBitrateIdx(bitRate)  , 4 );/* bitrateIndex */
    
    BsPutBit( fixedStream, 0 , 1 );  /* paddingBit */
    BsPutBit( fixedStream, 1 , 1 );  /* protectionBit  */
    BsPutBit( fixedStream, mainDataBegin , 10 ); /* mainDataBegin */
}

/********************************************************************************/

/********************************************************************************/

static void EncodeCore(
  BsBitStream *fixedStream,
  float p_time_hsf[],
  float p_time_decoded[],
  int blockSizeSamples,
  int downsamplFac,
  enum CORE_CODEC coreCodecIdx
)
{
  int coreDecNumBit;
  int postProcMode = 1; /* don't use the postproc filter in g729 decoder for use with high layer signal*/
  int numSampleCore = blockSizeSamples;
  float *coreSampleBuf[MAX_TIME_CHANNELS], core_buff[4096], *p_out[MAX_TIME_CHANNELS];
  BsBitBuffer *coreBitBuf;

  coreSampleBuf[MONO_CHAN] = core_buff;
  p_out[MONO_CHAN]         = p_time_decoded;

  coreBitBuf = BsAllocBuffer(2000);

  firLowPass( p_time_hsf, coreSampleBuf[MONO_CHAN], blockSizeSamples, lowpassFilt );
  subSampl( coreSampleBuf[MONO_CHAN], coreSampleBuf[MONO_CHAN], downsamplFac, &numSampleCore );

  switch( coreCodecIdx ) {
   case CC_G729:
     EncG729Frame( coreSampleBuf, coreBitBuf, (int)160, (int)160, (int)160, (int)160 );
     BsPutBuffer( fixedStream, coreBitBuf );
     DecG729Frame( coreBitBuf, p_out, &coreDecNumBit, postProcMode ); /* mem_time_sig_core_ptr */
     break;

   case CC_CELP_MPEG4_60:
    {
     BITSTREAM bitstream;

     bitstream.p_bitstream_buffer_start = coreBitBuf->data;
     bitstream.buffer_length            = ((coreBitBuf->size)+7)/8;
     bitstream.start_offset             = 0;
     bitstream.valid_bits               = 0;

     celp_coder(
       coreSampleBuf,            /* in: input speech */ 
       &bitstream,               /* out: coded bitstream */
       sampling_frequency,       /* in: sampling frequency */
       bit_rate,	         /* in: bit rate */
       SampleRateMode,
       QuantizationMode,
       FineRateControl,
       LosslessCodingMode,
       WB_Configuration,
       Wideband_VQ,
       NB_Configuration,
       NumEnhLayers,
       BandwidthScalabilityMode,
       BWS_configuration,
       0,
       frame_size,           /* in: frame size */
       n_subframes,          /* in: number of subframes */
       sbfrm_size,           /* in: subframe size */
       lpc_order,            /* in: order of LPC */
       num_lpc_indices,      /* in: number of LPC indices */
       num_shape_cbks,       /* in: number of shape codebooks */
       num_gain_cbks,        /* in: number of gain codebooks */
       n_lpc_analysis,       /* in: number of LP analysis per frame */
       window_offsets,       /* out: window size for each LP analysis */
       window_sizes,         /* out: window offset for each LP analysis */
       n_lag_candidates,     /* in: number of pitch candidates */
       min_pitch_frequency,  /* in: minimum pitch frequency */
       max_pitch_frequency,  /* in: maximum pitch frequency */
       org_frame_bit_allocation, /* out: bit number for each index */
       InstanceContextLPCEnc /* in/out: instance context */
     );

     coreBitBuf->numBit = bitstream.valid_bits;
     BsPutBuffer( fixedStream, coreBitBuf );

     celp_decoder (
       &bitstream,        /* in: received bitstream */
       p_out,             /* out: decoded signal (multi-channel) */
       SampleRateMode,              /* In: SampleRate Mode            */
       QuantizationMode,            /* In: Type of Quantization       */
       FineRateControl,             /* In: Fine Rate Control switch   */
       LosslessCodingMode,          /* In: Lossless Coding Mode       */
       WB_Configuration,            /* In: Wideband configuration     */
       Wideband_VQ,                 /* In: Wideband VQ mode           */
       NB_Configuration,            /* In: Narrowband configuration   */
       NumEnhLayers,                /* In: Number of Enhanc. Layers   */
       BandwidthScalabilityMode,    /* In: bandwidth switch           */
       BWS_configuration,           /* In: BWS_configuration          */
       frame_size,        /* in: frame size */
       n_subframes,       /* in: number of subframes */
       sbfrm_size,        /* in: subframe size */
       lpc_order,         /* in: order of LPC */
       num_lpc_indices,   /* in: number of LPC indices */
       num_shape_cbks,    /* in: number of shape codebooks */
       num_gain_cbks,     /* in: number of gain codebooks */
       org_frame_bit_allocation,  /* in: bit number for each index */
       InstanceContextLPCDec /* in/out: instance context */
     );
    }
    break;

   default:
     CommonExit( 1, "Encode scalab.: core coder not yet supported" );
  }

  BsFreeBuffer( coreBitBuf );
}

/********************************************************************************/

/********************************************************************************/

#define FSS_BANDS 16
typedef struct {
  int code[FSS_BANDS];
  int length[FSS_BANDS];
}FSS_CODE;

static FSS_CODE fssCode={
  {0,20,21,22,23,24,25,8,9,26,27,28,29,30,31,1},
  {2, 5, 5, 5, 5, 5, 5,4,4, 5, 5, 5, 5, 5, 5, 2}
};

static void aacEncodeFssData(
  BsBitStream      *fixedStream,
  WINDOW_TYPE      block_type,
  unsigned int     numDiffCtrlBands,
  enum DC_FLAG     FssControl[],
  enum JS_MASK     ms_mask[]
)
{
  int i;

  if( block_type != ONLY_SHORT_WINDOW ) {
    if( !ms_mask ) {
      unsigned int fssGroup;
      unsigned int fssNoGroups = numDiffCtrlBands >> 2 ;
      for( fssGroup=0; fssGroup<fssNoGroups;  fssGroup++ ) {
        unsigned int group = 0;
        for( i=0; i<4; i++ ) {
          group <<= 1;
          if( FssControl[(fssGroup<<2)+i] == DC_SIMUL ) {
            group |= 0x1;
          }
        }
        BsPutBit( fixedStream, fssCode.code[group], fssCode.length[group] ); 
      }
    } else {
      for( i=0; i<numDiffCtrlBands; i++ ) {
        if( ms_mask[i] == JS_MASK_OFF ) {
          BsPutBit( fixedStream, FssControl[i], 1 );
        }
      }
    }
  } else {
    for( i=0; i<8; i++ ) {
      BsPutBit( fixedStream, FssControl[i], 1 ); 
    }
  }
}

/********************************************************************************/

/********************************************************************************/

/* FSS: switch decision */  

static void CalcFssControl(
  double       p_core[],
  double       p_full[],
  double       p_diff[],
  WINDOW_TYPE  blockType,
  enum DC_FLAG FssControl[],
  int          blockSizeSamples,
  int          sfb_width_table[],
  long         samplRate,
  int diffContrSimu
)
{
  int win, no_win, i, offset, sb, no_spec_coeff, *diffBandWidth, numDiffBands;
  int FssBwShort;
  double e_full[SFB_NUM_MAX];
  double e_diff[SFB_NUM_MAX];
#ifdef DEL_ADJ
  static double avg_gain[SFB_NUM_MAX];
  static int _cnt;
#endif

  for (i=0;i<blockSizeSamples ;i++) {  /* for now just always the difference signal */
    p_diff[i] = p_full[i] - p_core[i];
  }

  if( blockType == ONLY_SHORT_WINDOW ) {
    no_win        = 8;
    no_spec_coeff = blockSizeSamples/no_win;
    numDiffBands  = 1;
    diffBandWidth = &FssBwShort;


    switch( samplRate ) {
     case 48000:
     case 44100: 
      FssBwShort = 18; break;
     case 32000: 
      FssBwShort = 28; break;
     case 22050:
     case 24000:
      FssBwShort = 36; break;
     case 16000:
      FssBwShort = 56; break;
    }

    for( i=0; i<8; i++ ) {  /* always diff for short for now */
      if (diffContrSimu){
        FssControl[i] = DC_SIMUL;
      } else {
        FssControl[i] = DC_DIFF;
      }
    }
   } else {
    no_win        = 1;
    no_spec_coeff = blockSizeSamples;
    diffBandWidth = sfb_width_table;

    switch( samplRate ) {
     case 48000 :
     case 44100 : 
      numDiffBands = 20; break;
     case 32000 : 
      numDiffBands = 24; break;
     case 22050 :
     case 24000 :
      numDiffBands = 32; break;
     case 16000 :
      numDiffBands = 32; break;
    default :
      CommonExit(-1,"\nerror in CalcFssControl");
      break;
    }

    for( sb=0; sb<numDiffBands; sb++ ) {
      if (diffContrSimu){
        FssControl[sb] = DC_SIMUL;
      } else {
        FssControl[sb] = DC_DIFF;
      }
    }

    offset = 0;
    for( sb=0; sb<numDiffBands; sb++ ) {
      e_full[sb] = 0;
      e_diff[sb] = 0;

      for( i=0; i<sfb_width_table[sb]; i++ ) {
        e_full[sb] +=  p_full[offset] * p_full[offset];
        e_diff[sb] +=  p_diff[offset] * p_diff[offset];
        offset++;
      }
      if( e_diff[sb] >= e_full[sb] ) {
        FssControl[sb] = DC_SIMUL;
      }
#ifdef DEL_ADJ
      if( log10(e_full[sb] + FLT_MIN) > 0 ) {
        avg_gain[sb] += log10(e_full[sb] + FLT_MIN) - log10(e_diff[sb] + FLT_MIN);
      }
#endif
    }
    
#ifdef DEL_ADJ
    printf( "\nE_full :  " );
    for( sb=0; sb<numDiffBands; sb++ ) {
      printf( "%8.3f", 10*log10(e_full[sb] + FLT_MIN) );
    }
    printf( "\nE_diff :  " );
    for( sb=0; sb<numDiffBands; sb++ ) {
      printf( "%8.3f", 10*log10(e_diff[sb] + FLT_MIN) );
    }
    printf( "\nA_gain :  " );
    for( sb=0; sb<numDiffBands; sb++ ) {
      printf( "%8.3f", 10*avg_gain[sb]/_cnt );
    }
    _cnt++;
    printf( "\n" );
#endif
  }
 
  for( win=0; win<no_win; win++ ) {
    int offset   = win*no_spec_coeff;
    int dcf_offs = win;
    int sum      = 0;
    for( sb=0; sb<numDiffBands; sb++ ) {
      if( FssControl[dcf_offs+sb] == DC_SIMUL ) {
        for( i=0; i<diffBandWidth[sb]; i++ ) {
          p_diff[offset+i] = p_full[offset+i];
        }
      }
      offset += diffBandWidth[sb];
      sum    += diffBandWidth[sb];
    }
    for( i=0; i<(no_spec_coeff-sum); i++ ) {
      p_diff[offset+i] = p_full[offset+i];
    }
  }
}

/********************************************************************************/

/********************************************************************************/

static void aacEncodeScalHeader(
  BsBitStream  *fixed_stream,
  BsBitBuffer  *gcBitBufCh,   /* bit buffer for gain_control_data() */
  WINDOW_TYPE  block_type,
  int          max_sfb,
  int          ch_no_layer,   /* no of channels in the current layer */
  int          ch_no_max,     /* no of channels of the last layer */
  int          ch_no_core,
  long         samplRate,
  enum DC_FLAG FssControl[MAX_TIME_CHANNELS][SFB_NUM_MAX],
  enum JS_MASK ms_mask[],
  int          num_window_groups,
  int          window_group_length[],
  TNS_INFO     *tnsInfo,
  ENC_FRAME_DATA* frameData
)
{
  int ch;
  int reducedInfo=0;

  if ( frameData && (frameData->od->streamCount.value > 1) 
       && (frameData->od->ESDescriptor[0]->DecConfigDescr.audioSpecificConfig.audioDecoderType.value==0) 
       && (frameData->od->ESDescriptor[0]->DecConfigDescr.audioSpecificConfig.specConf.TFSpecificConfig.TFCodingType.value==2) ) {
    /* core is a TwinVQ */
    reducedInfo=1;
  }
  write_ics_info( max_sfb, block_type, 
                  fixed_stream, WS_FHG, 
                  num_window_groups, 
                  window_group_length, 
                  pred_type, 
                  &nok_bwp_status[MONO_CHAN],
                  reducedInfo);

  if( ch_no_layer > 1 ) {
    BsPutBit( fixed_stream, 2, 2 ); /*all bands MS */
  }

  for( ch=0; ch<ch_no_max; ch++ ) {

    /* TNS data */
    if (tnsInfo) {              /* TNS active */
      write_tns_data( tnsInfo, block_type, fixed_stream, 1 );
    } else {                    /* switch it off */
      BsPutBit(fixed_stream,0,1);
    }

    /* write gain_control_data()  TK */
    if( gcBitBufCh && (gcBitBufCh->numBit > 0) ) {		/* gain_control_data() present */
      BsPutBit( fixed_stream, 1, 1 );	       /* switches on the gain control */
      BsPutBuffer( fixed_stream, gcBitBufCh ); /* gain_control_data() */
    } else {
      BsPutBit( fixed_stream,0,1);             /* switches off the gain control */
    }

    /* FSS data */
    if( (ch_no_core > 0) && (ch < ch_no_layer) ) { 
      int fss_bands;

      if( block_type == ONLY_SHORT_WINDOW) {
        fss_bands = 8;
      } else {
        switch (samplRate) {
         case 48000: fss_bands = 20; break;
         case 32000: fss_bands = 24; break;
         case 24000: fss_bands = 32; break;
         case 16000: fss_bands = 32; break;
         default: CommonExit( 1, "scalable encoder doesn't support this sampling rate currently" );
        }
      }
      aacEncodeFssData( fixed_stream, block_type, fss_bands, FssControl[ch], NULL );
    }
  }
}


/********************************************************************************/

/********************************************************************************/

static void aacEncodeLayerHeader(
  BsBitStream  *fixed_stream,
  WINDOW_TYPE  block_type,
  int          max_sfb,
  int          max_sfb_prev_layer,
  enum DC_FLAG msFssControl[MAX_TIME_CHANNELS][SFB_NUM_MAX],
  enum JS_MASK ms_mask[],
  int          mono_stereo_flag,
  int          ch_no_layer,    /* no of channels in the current layer */
  ENC_FRAME_DATA* frameData
)
{
  if( block_type == ONLY_SHORT_WINDOW ){
    BsPutBit( fixed_stream, max_sfb, 4 ) ;/* max_sfb*/
  } else {
    BsPutBit( fixed_stream, max_sfb, 6 ) ;/* max_sfb */
  }

  /* ms mask */
  if( ch_no_layer > 1 ) {
    BsPutBit( fixed_stream, 2, 2 ); /*all bands MS */
  }

  if( mono_stereo_flag ) {
    int ch;
    for( ch=0; ch<2; ch++ ) {
      aacEncodeFssData( fixed_stream, block_type, max_sfb_prev_layer, msFssControl[ch], ms_mask );
    }
  }

}


/********************************************************************************/

/********************************************************************************/

int aacScaleableEncode(
  double      *p_spectrum[MAX_TIME_CHANNELS],
  double      energy[MAX_TIME_CHANNELS][MAX_SCFAC_BANDS],
  double      allowed_dist[MAX_TIME_CHANNELS][MAX_SCFAC_BANDS],
  WINDOW_TYPE  blockType[MAX_TIME_CHANNELS],
  int         sfb_width_table[MAX_TIME_CHANNELS][MAX_SCFAC_BANDS],
  int         nr_of_sfb[MAX_TIME_CHANNELS],
  int         average_block_bits,			
  int         available_bitreservoir_bits,
  int         padding_limit,
  BsBitStream *mainStream,
  BsBitStream *var_stream,
  int         nr_of_chan,
  double      *p_reconstructed_spectrum[MAX_TIME_CHANNELS],
  int         useShortWindows,
  Window_shape     windowShape,      /* offers the possibility to select different window functions */
  int         aacAllowScalefacs,
  int         blockSizeSamples,
  int         frameMaxNumBit,
  float       **timeSig,
  long        bitRate,
  long        samplRate,
  QC_MOD_SELECT qc_select,
  TNS_INFO *tnsInfo[MAX_TIME_CHANNELS],
  ENC_FRAME_DATA* frameData,
  enum CORE_CODEC coreCodecIdx
) 
{
  static int codedFixedBits;
  static BsBitStream *dynpartStream;
  int dynpartBits;
  int i, lay, ch;
  int frameBits, rem_bits;
  OP_MODE_INFO omi;
  enum DC_FLAG FssControl[MAX_TIME_CHANNELS][SFB_NUM_MAX];
  enum DC_FLAG msFssControl[MAX_TIME_CHANNELS][SFB_NUM_MAX];
  BsBitStream *fixedStream;
  enum JS_MASK ms_mask[SFB_NUM_MAX];
  int num_window_groups, window_group_length[8];

  memcpy( &omi, &opm_info[op_mode], sizeof(OP_MODE_INFO) );
  /* intermediate_layers = (op_mode >= 7) ? 1 : 0; */
  omi.tf_layers += intermediate_layers;

  /* start of bitstream composition */
  frameBits = bitRate * blockSizeSamples /samplRate;
  fixedStream = BsOpenBufferWrite(fixedPartBuf[granule]);

  if( granule == 0 ) {
    codedFixedBits = 0;

    dynpartStream = BsOpenBufferWrite( dynpartBuf );
    if (frameData==NULL){
      aacEncodeScalFrameHeader( fixedStream, op_mode, coreCodecIdx, samplRate, bitRate, intermediate_layers, 0 ,frameData);
    }
  }
  
  /* ms matrix */
  if( omi.ch_no_max == 2 ) {  /* always MS for now */
    for( i=0; i<blockSizeSamples; i++ ) {
      double dtmp = p_spectrum[0][i] + p_spectrum[1][i];
      p_spectrum[0][i] = (p_spectrum[0][i] - p_spectrum[1][i]) * 0.5;
      p_spectrum[1][i] = dtmp * 0.5;
    }
    for( i=0; i<SFB_NUM_MAX; i++ ) {
      ms_mask[i] = JS_MASK_MS;
    }
  }

  /* Core Coder */
  if( omi.ch_no_core > 0 ) {
    double coreSpectrum[MAX_TIME_CHANNELS][2048];

    if( omi.ch_no_max > omi.ch_no_core ) {
      for( i=0; i<blockSizeSamples; i++ ) {
        for( ch=1; ch<omi.ch_no_max; ch++ ) {
          timeSig[MONO_CHAN][i] += timeSig[ch][i];
        }
        timeSig[MONO_CHAN][i] *= 0.5;
      }
      for( ch=1; ch<omi.ch_no_max; ch++ ) {   /* copy S-spectrum */
        for( i=0; i<blockSizeSamples; i++ ) {
          diffSpectrum[ch][i] = p_spectrum[ch][i];
        }
      }
    }
    EncodeCore( fixedStream, timeSig[MONO_CHAN], 
                coreDecodedSampleBuf[MONO_CHAN], 
                blockSizeSamples, downsamplFac,
                coreCodecIdx);

    mdct_core( blockType[MONO_CHAN], windowShape, coreDecodedSampleBuf[MONO_CHAN], coreSpectrum[MONO_CHAN], 0, samplRate, blockSizeSamples );

    if (tnsInfo) {

      int sfb, k, sfb_offset[ 100 ];
      
      /* calc. sfb offset table */
      for (sfb=k=0; sfb<nr_of_sfb[MONO_CHAN]; sfb++) {
        sfb_offset[sfb] = k;
        k += sfb_width_table[MONO_CHAN][sfb];
      }
      sfb_offset[sfb] = k;
      
      TnsEncode2(nr_of_sfb[MONO_CHAN],                  /* Number of bands per window */
                 nr_of_sfb[MONO_CHAN],                  /* max_sfb */ 
                 blockType[MONO_CHAN],                  /* block type */
                 sfb_offset,                            /* Scalefactor band offset table */
                 coreSpectrum[MONO_CHAN],               /* Spectral data array */
                 tnsInfo[MONO_CHAN]);                   /* TNS info */
    }

    CalcFssControl( coreSpectrum[MONO_CHAN], p_spectrum[MONO_CHAN], diffSpectrum[MONO_CHAN], blockType[MONO_CHAN],
                    FssControl[MONO_CHAN], blockSizeSamples, sfb_width_table[MONO_CHAN], samplRate ,diffContrSimu);
  } else {
    for( ch=0; ch<omi.ch_no_max; ch++ ) {
      for( i=0; i<blockSizeSamples; i++ ) {
        diffSpectrum[ch][i] = p_spectrum[ch][i];
      }
    }
  }

  /* first T/F layer */
  if (blockType[MONO_CHAN] == ONLY_SHORT_WINDOW) {
    num_window_groups=4;
    window_group_length[0] = 1;
    window_group_length[1] = 2;
    window_group_length[2] = 3;
    window_group_length[3] = 2;
  } else {
    num_window_groups = 1;
    window_group_length[0] = 1;
  }

  aacEncodeScalHeader( fixedStream, NULL, blockType[MONO_CHAN],
                       blockType[MONO_CHAN]==ONLY_SHORT_WINDOW ? nr_of_sfb[MONO_CHAN]*num_window_groups : nr_of_sfb[MONO_CHAN] /*max_sfb*/,
                       omi.ch_no_tf[0], omi.ch_no_max, omi.ch_no_core,
                       samplRate, FssControl, ms_mask, num_window_groups, window_group_length, tnsInfo ? tnsInfo[MONO_CHAN]:NULL ,frameData);

  rem_bits = frameBits - BsCurrentBit(fixedStream) - (7/numGranules+1); /* reserve bits for byte allignment */

  {
    int _nr_of_sfb[MAX_TIME_CHANNELS];
    memcpy( _nr_of_sfb, nr_of_sfb, sizeof(int)*MAX_TIME_CHANNELS );

    rem_bits -= tf_encode_spectrum_aac( diffSpectrum, energy, allowed_dist, blockType,
                                        sfb_width_table, _nr_of_sfb, (rem_bits/omi.tf_layers),
                                        0, padding_limit, dynpartStream, var_stream, NULL,
                                        omi.ch_no_tf[0],
                                        p_reconstructed_spectrum, useShortWindows,
                                        WS_FHG, aacAllowScalefacs, samplRate,
                                        qc_select, pred_type,
                                        nok_lt_status, nok_bwp_status, blockSizeSamples, num_window_groups, window_group_length,
                                        NULL,15000/* bandwidth in Hz */
                                      );
  }

  /* other T/F layers */
  for( lay=1; lay<omi.tf_layers; lay++ ) {
    for( ch=0; ch<omi.ch_no_tf[lay-1]; ch++ ) {
      for( i=0; i<blockSizeSamples; i++ ) {  /* for now just always the difference signal */
        diffSpectrum[ch][i] -= p_reconstructed_spectrum[ch][i];
      }
      for( i=0; i<8; i++ ) {
        msFssControl[ch][i] = DC_DIFF;
      }
    }

   {
    int hbits = -BsCurrentBit( fixedStream );
    aacEncodeLayerHeader( fixedStream, blockType[MONO_CHAN], nr_of_sfb[MONO_CHAN] /* max_sfb */, nr_of_sfb[MONO_CHAN]
                          /* max_sfb_prev_layer */, msFssControl, ms_mask, (omi.ch_no_tf[lay]>omi.ch_no_tf[lay-1]) , omi.ch_no_tf[lay],frameData );
    hbits += BsCurrentBit( fixedStream );
    rem_bits -= hbits;
   }

   {	/* HP 971120 */
    int _nr_of_sfb[MAX_TIME_CHANNELS];
    memcpy( _nr_of_sfb, nr_of_sfb, sizeof(int)*MAX_TIME_CHANNELS );

    rem_bits -= tf_encode_spectrum_aac( diffSpectrum, energy, allowed_dist, blockType,
                                        sfb_width_table, _nr_of_sfb, (rem_bits/(omi.tf_layers-lay)),
                                        0, padding_limit, dynpartStream, var_stream, NULL,
                                        omi.ch_no_tf[lay],
                                        p_reconstructed_spectrum, useShortWindows,
                                        WS_FHG, aacAllowScalefacs, samplRate,
                                        qc_select, pred_type,
                                        nok_lt_status, nok_bwp_status, blockSizeSamples, num_window_groups, window_group_length,
                                        NULL,
                                        15000 /* bandwidth in Hz */
                                      );
   }
  }
 

  dynpartBits = BsCurrentBit( dynpartStream );
  codedFixedBits +=BsCurrentBit( fixedStream );


   
  /* new clean up and write superframe that consists out of 3 granules(=normal frames) */ 

  if( granule == 2 ) { 
    int fillBits;
    int alignBits;

    /* bytaalign bits for fixed stream */
    alignBits = 8 - codedFixedBits%8;
    alignBits = (alignBits == 8) ? 0 : alignBits;
    BsPutBit( fixedStream, 0, alignBits ); 
    codedFixedBits += alignBits;

    /* fillBits for the dynamic part*/
    fillBits = (numGranules*frameBits) - codedFixedBits - dynpartBits;
    if( fillBits < 0 )
      CommonExit(-1,"\n negativ amount of fillbits");
    for( i=0; i<fillBits; i++ ) {
      BsPutBit( dynpartStream, 1, 1 ); 
    }
    dynpartStream->currentBit = 0; /* rewind buffer */
    dynpartStream->write = 0;/* and make it readable */
    for( i=0; i<numGranules; i++ ) {
      BsPutBuffer( mainStream, fixedPartBuf[i] );
      dynpartBits= frameBits *(i+1) - BsCurrentBit(mainStream);
      BsGetBuffer( dynpartStream, tmpBitBuf, dynpartBits );
      BsPutBuffer( mainStream, tmpBitBuf );
    }
  }   

  (granule>=2) ? granule=0 : granule++;

  return( BsCurrentBit(mainStream) );
}

void printOpModeInfo(FILE *fp) {
  int x,y;
  fprintf(fp,"\n-mode <int> : operating modes for scalable  coding");
  for (x=0;x<sizeof(opm_info)/sizeof(OP_MODE_INFO);x++){
    fprintf(fp,"\n mode:  %d  ",x);
    fprintf(fp," ch_no_core: %d  ", opm_info[x].ch_no_core );
    fprintf(fp," ch_no_max : %d  ", opm_info[x].ch_no_max );
    fprintf(fp," tf_layers : %d  \n", opm_info[x].  tf_layers );
    for (y=0;y<    opm_info[x]. tf_layers ;y++){
      fprintf(fp,"  no_channel for tf_layer %d: %d  ", y,opm_info[x].ch_no_tf[y]);      
    }    
  }
}
int aacScaleableFlexMuxEncode(
  double      *p_spectrum[MAX_TIME_CHANNELS],
  double      energy[MAX_TIME_CHANNELS][MAX_SCFAC_BANDS],
  double      allowed_dist[MAX_TIME_CHANNELS][MAX_SCFAC_BANDS],
  WINDOW_TYPE  blockType[MAX_TIME_CHANNELS],
  int         sfb_width_table[MAX_TIME_CHANNELS][MAX_SCFAC_BANDS],
  int         nr_of_sfb[MAX_TIME_CHANNELS],
  int         average_block_bits,			
  int         available_bitreservoir_bits,
  int         padding_limit,
  BsBitStream *mainStream,
  BsBitStream *var_stream,
  int         nr_of_chan,
  double      *p_reconstructed_spectrum[MAX_TIME_CHANNELS],
  int         useShortWindows,
  Window_shape     windowShape,      /* offers the possibility to select different window functions */
  int         aacAllowScalefacs,
  int         blockSizeSamples,
  int         frameMaxNumBit,
  float       **timeSig,
  long        bitRate,
  long        samplRate,
  QC_MOD_SELECT qc_select,
  TNS_INFO    *tnsInfo[MAX_TIME_CHANNELS],
  ENC_FRAME_DATA* frameData,
  enum CORE_CODEC coreCodecIdx,
  int num_window_groups, 
  int window_group_length[8],
  ntt_PARAM *param_ntt


) 
{
  int layerBits;
  int i, lay, ch,tfLayer;
  int frameBits, rem_bits;
  OP_MODE_INFO omi;
  enum DC_FLAG FssControl[MAX_TIME_CHANNELS][SFB_NUM_MAX];
  enum DC_FLAG msFssControl[MAX_TIME_CHANNELS][SFB_NUM_MAX];
  BsBitStream *layerStream;
  enum JS_MASK ms_mask[SFB_NUM_MAX];
  int lastLayer,  flexmuxOverhead;
  int fullBandwidth;
  int core_coder_bits, ubits;

  memcpy( &omi, &opm_info[frameData->opMode], sizeof(OP_MODE_INFO) );
  /* intermediate_layers = (op_mode >= 7) ? 1 : 0; */
  omi.tf_layers += intermediate_layers;

  lastLayer=omi.tf_layers+ ((omi.ch_no_core > 0) ? 1:0);

  /* start of bitstream composition */
/*   frameBits = bitRate * blockSizeSamples /samplRate - bitsPerFrame; *Q&D for TVQ * */
  frameBits = average_block_bits + available_bitreservoir_bits - 150 ;
  layerStream = BsOpenBufferWrite(dynpartBuf);

  
  /* ms matrix */
  if( omi.ch_no_max == 2 ) {  /* always MS for now */
    for( i=0; i<blockSizeSamples; i++ ) {
      double dtmp = p_spectrum[0][i] + p_spectrum[1][i];
      p_spectrum[0][i] = (p_spectrum[0][i] - p_spectrum[1][i]) * 0.5;
      p_spectrum[1][i] = dtmp * 0.5;
    }
    for( i=0; i<SFB_NUM_MAX; i++ ) {
      ms_mask[i] = JS_MASK_MS;
    }
  }

  /* Core Coder */
  lay=0;
  tfLayer=0;
  layerBits=0;
  if( omi.ch_no_core > 0 ) {
    double coreSpectrum[MAX_TIME_CHANNELS][2048];

    if( omi.ch_no_max > omi.ch_no_core ) {
      for( i=0; i<blockSizeSamples; i++ ) {
        for( ch=1; ch<omi.ch_no_max; ch++ ) {
          timeSig[MONO_CHAN][i] += timeSig[ch][i];
        }
        timeSig[MONO_CHAN][i] *= 0.5;
      }
      for( ch=1; ch<omi.ch_no_max; ch++ ) {   /* copy S-spectrum */
        for( i=0; i<blockSizeSamples; i++ ) {
          diffSpectrum[ch][i] = p_spectrum[ch][i];
        }
      }
    }

    switch (coreCodecIdx) {
    case CC_G729:
    case CC_CELP_MPEG4_60:
      EncodeCore( layerStream, timeSig[MONO_CHAN], 
                  coreDecodedSampleBuf[MONO_CHAN], 
                  blockSizeSamples, downsamplFac,
                  coreCodecIdx);

      mdct_core( blockType[MONO_CHAN], windowShape, coreDecodedSampleBuf[MONO_CHAN], coreSpectrum[MONO_CHAN], 0, samplRate, blockSizeSamples );

      break;
    case NTT_TVQ:
      /* assume that NTT_VQ has the same FS as AAC 
         we don't have to apply sampling rate conversion */
      {
        int j;
        double nttTimeSigAr[MAX_TIME_CHANNELS][1024];
        double nttTimeSigInitAr[MAX_TIME_CHANNELS][1024];
        double dlpc_spectrum[ntt_T_FR_MAX];

        double *nttTimeSig[MAX_TIME_CHANNELS];
        double *nttTimeSigInit[MAX_TIME_CHANNELS];        
        double *nttCoreSpectrum[MAX_TIME_CHANNELS];

        for (i=0; i<omi.ch_no_core; i++) {
          /* TVQ don't need the time signal, this is only for the interface */
          nttTimeSigInit[i] = nttTimeSigAr[i];
          nttTimeSig[i] = nttTimeSigAr[i]; 
          nttCoreSpectrum[i] = coreSpectrum[i];

          /* copy time signal */
          for (j=0; j<1024; j++)
            nttTimeSigAr[i][j] = (double)timeSig[i][j];
        }

          ntt_vq_coder(nttTimeSigInit,
                       nttTimeSig,
                       p_spectrum,
                       NULL,
                       NTT_PW_INTERNAL,
                       blockType[MONO_CHAN],
                       &ntt_index,
                       param_ntt,
                       bitsPerFrame-4,
                       dlpc_spectrum,
                       nttCoreSpectrum);

          /* this belongs to ICS info, but has to be written within the first TF layer */
          BsPutBit(layerStream, 0, 1);                           /* ics info reserved bit */
          BsPutBit(layerStream, (int)blockType[MONO_CHAN], 2);   /* window sequence */
          BsPutBit(layerStream, (int)windowShape, 1);            /* window shape */

          /* pack the TVQ layer in the flexmuxstream */
          ntt_BitPack(&ntt_index, layerStream);

          core_coder_bits = BsCurrentBit(layerStream);

          /* write to flexmux PDU */
          BsClose(layerStream);
          writeFlexMuxPDU(lay,mainStream,dynpartBuf);
          layerBits = BsCurrentBit(mainStream);
      
      }
      break;
    default:
      CommonExit( 1, "Encode scalab.: core coder not yet supported" );
    }
    lay++;
    if (tnsInfo[MONO_CHAN]) {
      
      int sfb, k, sfb_offset[ 100 ];
      
      /* calc. sfb offset table */
      for (sfb=k=0; sfb<nr_of_sfb[MONO_CHAN]; sfb++) {
        sfb_offset[sfb] = k;
        k += sfb_width_table[MONO_CHAN][sfb];
      }
      sfb_offset[sfb] = k;
      
      TnsEncode2(nr_of_sfb[MONO_CHAN],                  /* Number of bands per window */
                 nr_of_sfb[MONO_CHAN],                  /* max_sfb */ 
                 blockType[MONO_CHAN],                  /* block type */
                 sfb_offset,                            /* Scalefactor band offset table */
                 coreSpectrum[MONO_CHAN],               /* Spectral data array */
                 tnsInfo[MONO_CHAN]);                   /* TNS info */
    }

    CalcFssControl( coreSpectrum[MONO_CHAN], p_spectrum[MONO_CHAN], diffSpectrum[MONO_CHAN], blockType[MONO_CHAN],
                    FssControl[MONO_CHAN], blockSizeSamples, sfb_width_table[MONO_CHAN], samplRate ,diffContrSimu);
  } else {
    for( ch=0; ch<omi.ch_no_max; ch++ ) {
      for( i=0; i<blockSizeSamples; i++ ) {
        diffSpectrum[ch][i] = p_spectrum[ch][i];
      }
    }
  }

  if (omi.tf_layers > 0) {
    /* first T/F layer */
    frameBits -= layerBits ;
    flexmuxOverhead =  3*8*(1 + (frameBits/2040));
    frameBits -=   flexmuxOverhead;

    layerStream = BsOpenBufferWrite(dynpartBuf);


    if (qc_select == AAC_SYS) {
    aacEncodeScalHeader( layerStream, NULL, blockType[MONO_CHAN],
                         blockType[MONO_CHAN]==ONLY_SHORT_WINDOW ? nr_of_sfb[MONO_CHAN]*num_window_groups : nr_of_sfb[MONO_CHAN] /*max_sfb*/,
                         omi.ch_no_tf[0], omi.ch_no_max, omi.ch_no_core,
                         samplRate, FssControl, ms_mask, num_window_groups, window_group_length ,tnsInfo[MONO_CHAN] ,frameData);
    } else if (qc_select == AAC_SYS_BSAC) {
	  sam_prepare_EncodeScalHeader(FssControl, ms_mask, tnsInfo, core_coder_bits);
      if (omi.ch_no_core > 0)
        frameBits -=   flexmuxOverhead;
      frameBits -=   (flexmuxOverhead * omi.tf_layers-1);
    }

    rem_bits = frameBits - BsCurrentBit(layerStream)  ; /*  */
    fullBandwidth= (int)(  samplRate/2);
    if (fullBandwidth>14000) fullBandwidth=14000;
    {
      int available_bits;
      int limitedBandwidth;
      int _nr_of_sfb[MAX_TIME_CHANNELS];
      memcpy( _nr_of_sfb, nr_of_sfb, sizeof(int)*MAX_TIME_CHANNELS );

      if(qc_select == AAC_SYS_BSAC) {
        available_bits = rem_bits;
        limitedBandwidth = fullBandwidth;
      } else {
        available_bits = rem_bits/omi.tf_layers;
        limitedBandwidth = fullBandwidth/omi.tf_layers;
      }
      ubits = tf_encode_spectrum_aac( diffSpectrum, energy, allowed_dist, blockType,
                                          sfb_width_table, _nr_of_sfb, available_bits,
                                          0, padding_limit, layerStream, var_stream, NULL, /* write to layerStream directly after the header */
                                          omi.ch_no_tf[tfLayer],
                                          p_reconstructed_spectrum, useShortWindows,
                                          WS_FHG, aacAllowScalefacs, samplRate,
                                          qc_select, pred_type,
                                          nok_lt_status, nok_bwp_status, blockSizeSamples, num_window_groups, window_group_length,NULL,
                                          limitedBandwidth

                                          );
      rem_bits -= ubits;
    }
    /* pack 1 aac layer to flexMux packet and write to bitstream */
    BsClose(layerStream);

    /* YB 980504 */
    if(qc_select != AAC_SYS_BSAC) {
      writeFlexMuxPDU(lay,mainStream,dynpartBuf);
    } else {
    /* make bsac_lstep_stream() from dynpartBuf as many as omi.tf_layers and
       pack the bsac_lstep_stream(s) to flexMux packet(s) and
       write to bitstream */
      int read_bits;
      int total_bits = ubits;
      int layer_bits = ubits/omi.tf_layers;
      if(total_bits < 50) layer_bits = total_bits;

      while(layer_bits % 8) layer_bits++;

      layerStream = BsOpenBufferRead(dynpartBuf);

      for(; lay<lastLayer; lay++) {
        tmpBitBuf->numBit = 0;
        read_bits = (total_bits > layer_bits) ? layer_bits : total_bits;
        BsGetBuffer(layerStream, tmpBitBuf, read_bits);
        writeFlexMuxPDU(lay,mainStream,tmpBitBuf);
        total_bits -= layer_bits;
      }
      BsClose(layerStream);
    }
    layerBits = BsCurrentBit(mainStream);
    lay++;
  }
  /* other T/F layers */
  if(qc_select != AAC_SYS_BSAC) {
  for( ; lay<lastLayer; lay++ ) {
    tfLayer++;    
    layerStream = BsOpenBufferWrite(dynpartBuf);

    for( ch=0; ch<omi.ch_no_tf[tfLayer]; ch++ ) {
      for( i=0; i<blockSizeSamples; i++ ) {  /* for now just always the difference signal */
        diffSpectrum[ch][i] -= p_reconstructed_spectrum[ch][i];
      }
      for( i=0; i<8; i++ ) {
        msFssControl[ch][i] = DC_DIFF;
      }
    }

   {
    int hbits = -BsCurrentBit( layerStream );
    aacEncodeLayerHeader( layerStream, blockType[MONO_CHAN], nr_of_sfb[MONO_CHAN] /* max_sfb */, nr_of_sfb[MONO_CHAN]
                          /* max_sfb_prev_layer */, msFssControl, ms_mask, (omi.ch_no_tf[tfLayer]>omi.ch_no_tf[tfLayer-1]) , omi.ch_no_tf[tfLayer],frameData );
    hbits += BsCurrentBit( layerStream );
    rem_bits -= hbits;
   }

   {	/* HP 971120 */
    int _nr_of_sfb[MAX_TIME_CHANNELS];
    memcpy( _nr_of_sfb, nr_of_sfb, sizeof(int)*MAX_TIME_CHANNELS );

    rem_bits -= tf_encode_spectrum_aac( diffSpectrum, energy, allowed_dist, blockType,
                                        sfb_width_table, _nr_of_sfb, (rem_bits/(omi.tf_layers-tfLayer)),
                                        0, padding_limit, layerStream, var_stream, NULL,
                                        omi.ch_no_tf[tfLayer],
                                        p_reconstructed_spectrum, useShortWindows,
                                        WS_FHG, aacAllowScalefacs, samplRate,
                                        qc_select, pred_type,
                                        nok_lt_status, nok_bwp_status, blockSizeSamples, num_window_groups, window_group_length,NULL,
                                        fullBandwidth/(omi.tf_layers-tfLayer)
                                      );
   }

   BsClose(layerStream);
   writeFlexMuxPDU(lay,mainStream,dynpartBuf);
   layerBits = BsCurrentBit(mainStream);
  }
  }
 
  return( BsCurrentBit(mainStream) );
}
