/**********************************************************************
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 "aac_qc.h"
#include "util.h"
#include "fir_filt.h"
#include "scaleable.h"
#include "dec.h"
#include "enc.h"
#include "bitmux.h"

#include "celp_encoder.h"
#include "celp_decoder.h"

#define MAX_TF_LAYERS 5

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 enum CORE_CODEC coreCodecIdx = CC_G729;
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; 



static long samplRateCore;

int aacScaleEncInit( 
  BsBitBuffer *bitHeader,
  char        *encPara,		 /* in: encoder parameter string */
  int         numChannel,
  int         frameNumSample,
  long        samplRate
)
{
  int frameNumSampleCore, delayNumSampleCore;
  
  int tmp, ch, i, core_delay;
  char *pc;

  if( (pc=strstr( encPara, "-aac_sca_mode" )) ) {
    sscanf( pc+14, "%1d", &op_mode );
  }
  if( (pc=strstr( encPara, "-aac_sca_core" )) ) {
    sscanf( pc+14, "%1d", &coreCodecIdx );
  }

  switch( op_mode ) {
    case 1:
    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");
      }
  }

  /* 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;
  }

  lowpassFilt = initFirLowPass( samplRate/4000, 120 );
  downsamplFac = samplRate/samplRateCore;

  switch( coreCodecIdx ) {
   case CC_G729:
    EncG729Init( 1 /* numChannel */, (float)samplRateCore, 8000.0, encPara, &frameNumSampleCore, &delayNumSampleCore, bitHeader );
    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;

     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,
       bit_rate,		    /* in: bit rate */
       samplRateCore,               /* in: sampling frequency */
       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,                 /* Out: Wideband VQ mode             */
       &NB_Configuration,           /* Out: Narrowband configuration     */
       NumEnhLayers,                /* In: Number of Enhancement Layers  */
       BandwidthScalabilityMode,    /* In: bandwidth switch              */
       &BWS_configuration,          /* Out: BWS_configuration            */
       BWS_nb_bitrate,              /* In: narrowband bitrate for BWS    */
       &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 */
       &n_lpc_analysis,    /* out: 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,	/* out: number of pitch candidates */
       &min_pitch_frequency,    /* out: minimum pitch frequency */
       &max_pitch_frequency,    /* out: maximum pitch frequency */
       &org_frame_bit_allocation /* out: bit number for each index */
     );

     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              */
     );

     core_delay = 660;

     free(p_bitstream);
     BsFreeBuffer( coreBitBuf );
    }
    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 ();

  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
)
{
  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
)
{
  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 */
     );

     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 */
     );
    }
    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,
  int              numDiffCtrlBands,
  enum DC_FLAG     FssControl[],
  enum JS_MASK     ms_mask[]
)
{
  int i;

  if( block_type != ONLY_SHORT_WINDOW ) {
    if( !ms_mask ) {
      int fssGroup;
      int fssNoGroups = numDiffCtrlBands >> 2 ;
      for( fssGroup=0; fssGroup<fssNoGroups;  fssGroup++ ) {
        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
)
{
  register 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 = 120;
    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 */
      FssControl[i] = DC_DIFF;
    }
  } else {
    no_win        = 1;
    no_spec_coeff = 960;
    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;
    }

    for( sb=0; sb<numDiffBands; sb++ ) {
      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[]
)
{
  int ch;

  write_ics_info( max_sfb, block_type, fixed_stream, WS_FHG, num_window_groups, window_group_length );

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

  for( ch=0; ch<ch_no_max; ch++ ) {
    /* TNS data */
    BsPutBit( fixed_stream, 1, 1 ); /* switches on TNS for long blocks */
    if (block_type == ONLY_SHORT_WINDOW) {
      BsPutBit( fixed_stream, 0, 8 ); /* n_filt[] = 0 */
    } else  { /* block_type is either long, start, or stop */
      BsPutBit( fixed_stream, 0, 2 ); /* n_filt[] = 0 */
    } 
    
    /* 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 */
)
{
  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      *PsySigMaskRatio[MAX_TIME_CHANNELS],
  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
) 
{
  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 );

    aacEncodeScalFrameHeader( fixedStream, op_mode, coreCodecIdx, samplRate, bitRate, intermediate_layers, 0 );
  }
  
  /* 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 );

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

    CalcFssControl( coreSpectrum[MONO_CHAN], p_spectrum[MONO_CHAN], diffSpectrum[MONO_CHAN], blockType[MONO_CHAN],
                    FssControl[MONO_CHAN], blockSizeSamples, sfb_width_table[MONO_CHAN], samplRate );
  } 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 );

  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, PsySigMaskRatio, 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
                                      );
  }

  /* 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] );
    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, PsySigMaskRatio, 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
                                      );
   }
  }
 

  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) );
}
