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



This software module was originally developed by

Bernhard Grill (University of Erlangen)

and edited by

Bodo Teichmann (Fhg)

in the course of development of the MPEG-2 NBC/MPEG-4 Audio standard
ISO/IEC 13818-7, 14496-1,2 and 3. This software module is an
implementation of a part of one or more MPEG-2 NBC/MPEG-4 Audio tools
as specified by the MPEG-2 NBC/MPEG-4 Audio standard. ISO/IEC gives
users of the MPEG-2 NBC/MPEG-4 Audio standards free license to this
software module or modifications thereof for use in hardware or
software products claiming conformance to the MPEG-2 NBC/ MPEG-4 Audio
standards. Those intending to use this software module in hardware or
software products are advised that this use may infringe existing
patents. The original developer of this software module and his/her
company, the subsequent editors and their companies, and ISO/IEC have
no liability for use of this software module or modifications thereof
in an implementation. Copyright is not released for non MPEG-2
NBC/MPEG-4 Audio conforming products. The original developer retains
full right to use the code for his/her own purpose, assign or donate
the code to a third party and to inhibit third party from using the
code for non MPEG-2 NBC/MPEG-4 Audio conforming products. This
copyright notice must be included in all copies or derivative works.

Copyright (c) 1997.

*/

#include "dec.h"
#include "bitstream.h"
#include "common.h"

#include "aac.h"
#include "util.h"
#include "scal_dec.h"
#include "celp_decoder.h"

#ifndef max
#define max(a,b)    (((a) > (b)) ? (a) : (b))   /* Makros, sonst in stdlib.h */
#endif

#ifndef min
#define min(a,b)    (((a) < (b)) ? (a) : (b))
#endif 

#define MOD_BUFF_ADD(x,s1,s2,len)\
  x = (s1) + (s2);\
  while( (x) < 0 )      x += (len);\
  while( (x) >= (len) ) x -= (len);


enum CCB_TYPE { CCBT_FRAME_BITS, CCBT_GRAN_BITS };

static BsBitBuffer *coreBitBuf;

typedef struct {
  int  sr_ratio;
  long bitrate_core;
  long sampling_rate_core;

  int ll_bits[6];                /* bits decoded in one granule */

  int samples_lsf;
  int samples_hsf;

  int samples_lsf_tf;

  int lsr_last_samp_decoded;

  enum CORE_CODEC coreCodecIdx;
} LL_DEC_STATUS;


/* variables reqired for the 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 long SampleRateMode     = fs8kHz;  /* Default: 8 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 BsBitStream *p_CoreBs;

static	void *InstanceContext;	/* one instance context */



static void fvcopy( float src[], float dest[], int inc_src, int inc_dest, int vlen )
{
  int i;

  for( i=0; i<vlen-1; i++ ) {
    *dest = *src;
    dest += inc_dest;
    src  += inc_src;
  }
  if (vlen) /* just for bounds-checkers sake */
    *dest = *src;

}

static void calc_core_codec_bits( 
  enum CCB_TYPE ccb_type,
  int cc_bits[],
  LL_DEC_STATUS *p_lds,
  long sampling_rate_tf,
  int granules
)
{
  int bit_frame_core  = p_lds->samples_lsf * p_lds->bitrate_core / p_lds->sampling_rate_core;  /* bits per core coder frame */
  int itmp2           = 960                * p_lds->bitrate_core / sampling_rate_tf;           /* bits per TF coder frame */
  int lsr_samp_tf ,core_samples,gr;

  switch( ccb_type ) {
   case CCBT_GRAN_BITS :
    lsr_samp_tf =  960/p_lds->sr_ratio;
     core_samples=0;
     for( gr=0; gr<granules; gr++ ){
       cc_bits[gr]=0;
       while( core_samples < lsr_samp_tf ) {
         core_samples += p_lds->samples_lsf;
         cc_bits[gr]+=bit_frame_core ;
       }
       
       lsr_samp_tf+= 960/p_lds->sr_ratio;
     }
     break;
   case CCBT_FRAME_BITS :
     cc_bits[0] = itmp2 * granules;
     break;
   default :
     CommonExit( -1, "unknown mode in calc_core_codec_bits" );
  }

  return;
}

static int  postProcMode;

static LL_DEC_STATUS CoreDecStatus[2];

void CoreDecoderInit( 
  long SamplingRate,
  enum CORE_CODEC coreCodecIdx,
  int  granules,
  int  chan,
  int output_select
)
{
  int  dummy;
  char g723_init_string[255];

  LL_DEC_STATUS *p_lds = &CoreDecStatus[chan];

  int sr_ratio;

  if( output_select== 0  ) {
    postProcMode=0; /* if only the core output is used , use the original postpocessing filter of g729 */
    sprintf( g723_init_string, " " );
  } else {
    postProcMode=1; /* dont use the original postpocessing filter of g729 if signal is added to high layer signal */  
    sprintf( g723_init_string, "-Noh -Nop" );
  }
  coreBitBuf = BsAllocBuffer( 4000 );      /* just some large number. For G729 required: 160 */

  switch( SamplingRate ) {
   case 96000:
   case 48000:
   case 32000:
   case 24000:
   case 16000:
   case 8000:
     p_lds->sampling_rate_core = 8000;
     break;
   case 44100:
   case 22050:
     p_lds->sampling_rate_core = 44100/6;
     break;
   case 12000:
     p_lds->sampling_rate_core = 12000;
     break;
   case 11025:
     p_lds->sampling_rate_core = 11025;
     break;
  }

  p_lds->sr_ratio           = SamplingRate/p_lds->sampling_rate_core;
  p_lds->coreCodecIdx       = coreCodecIdx;
  sr_ratio = p_lds->sr_ratio;

  switch( coreCodecIdx ) {
   case CC_G723_63:
     p_lds->bitrate_core = 6400;
     DecG723Init( 1, p_lds->sampling_rate_core, p_lds->bitrate_core, g723_init_string, NULL, &p_lds->samples_lsf, &dummy );
     break;

   case CC_G723_53:
     p_lds->bitrate_core = 5334;
     DecG723Init( 1, p_lds->sampling_rate_core, p_lds->bitrate_core, g723_init_string, NULL, &p_lds->samples_lsf, &dummy );
     break;

   case CC_G729:
     p_lds->bitrate_core = 8000;
     DecG729Init( 1, p_lds->sampling_rate_core, p_lds->bitrate_core, "-Noh -Nop", NULL, &p_lds->samples_lsf, &dummy );
     break;

     /*
   case CC_CELP_MPEG4_49:
     p_lds->bitrate_core = 4900;
     break;                                           
     */
                                                      
   case CC_CELP_MPEG4_60:
    {
     BITSTREAM *p_bitstream;
     int i=0;

     p_CoreBs = BsOpenFileWrite( "aac_scal_core.clp", NULL, NULL );

     /* simulate mpeg4 header */
     coreBitBuf->data[i++] = 0x2e;  /* . */
     coreBitBuf->data[i++] = 0x6d;  /* m */
     coreBitBuf->data[i++] = 0x70;  /* p */
     coreBitBuf->data[i++] = 0x34;  /* 4 */
     coreBitBuf->data[i++] = 0x0a;  /*   */
     coreBitBuf->data[i++] = 0x00;
     coreBitBuf->data[i++] = 0x40;
     coreBitBuf->data[i++] = 0x03;
     coreBitBuf->data[i++] = 0x01;
     coreBitBuf->data[i++] = 0x00;
     coreBitBuf->data[i++] = 0x00;
     coreBitBuf->data[i++] = 0x1f;
     coreBitBuf->data[i++] = 0x40;
     coreBitBuf->data[i++] = 0x00;
     coreBitBuf->data[i++] = 0x00;
     coreBitBuf->data[i++] = 0x17;
     coreBitBuf->data[i++] = 0x70;
     coreBitBuf->data[i++] = 0x00;
     coreBitBuf->data[i++] = 0x78;
     coreBitBuf->data[i++] = 0x00;
     coreBitBuf->data[i++] = 0x78;
     coreBitBuf->data[i++] = 0x00;
     coreBitBuf->data[i++] = 0x00;
     coreBitBuf->data[i++] = 0x00;
     coreBitBuf->data[i++] = 0x00;
     coreBitBuf->data[i++] = 0x02;
     coreBitBuf->data[i++] = 0x00;
     coreBitBuf->data[i++] = 0x0b;
     coreBitBuf->numBit  = i*8;
     BsPutBuffer( p_CoreBs, coreBitBuf );


     p_lds->samples_lsf = 160;
     bit_rate = p_lds->bitrate_core = 6000;
     sampling_frequency = p_lds->sampling_rate_core;

     if((p_bitstream=(BITSTREAM *)malloc(sizeof(BITSTREAM)))==NULL) {
       CommonExit(1, "Memory allocation error for dec_lpc init in core_dec.c");
     }
     
     p_bitstream->p_bitstream_buffer_start = coreBitBuf->data;
     p_bitstream->buffer_length            = ((coreBitBuf->size)+7)/8;
     p_bitstream->valid_bits               = coreBitBuf->numBit;
     
     /* simulate NB celp VQ mode for 6 kbps */


     coreBitBuf->data[0] = 0x47;
     coreBitBuf->data[1] = 0x0;
     coreBitBuf->numBit  = 11;

     p_bitstream->start_offset             = 0;
     p_bitstream->valid_bits               = 11;

     celp_initialisation_decoder (
       p_bitstream,
       bit_rate,		 /* in: bit rate */
       0,                   /* In: complexity level decoder*/
       0,                   /* In: reduced order decoder   */
       0,                   /* DecEnhStage */
       0,                   /* DecBwsMode */
       !postProcMode,       /* disable the postfilter if not the core output is selected */
       &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              */
       &InstanceContext		   /* Out: instance context */
     );

     free(p_bitstream);

     BsPutBuffer( p_CoreBs, coreBitBuf );

    }
     break;                                           

     /*                                                      
   case CC_CELP_MPEG4_77:                             
     p_lds->bitrate_core = 7700;                      
     break;                                           
                                                      
   case CC_CELP_MPEG4_99:                             
     p_lds->bitrate_core = 9900;                      
     break;
     */

   default:
     CommonExit(-1,"coreCodecIdx %d not yet supported",coreCodecIdx);
  }

  /* samples corresponding to core coder frame length (TF-Coder: iblen, or iblen/sr_ratio, respectively */
  p_lds->samples_hsf    = p_lds->samples_lsf * sr_ratio;
  p_lds->samples_lsf_tf = 960 / sr_ratio;

  calc_core_codec_bits( CCBT_GRAN_BITS, p_lds->ll_bits, p_lds, SamplingRate, granules );

  p_lds->lsr_last_samp_decoded = 0;
}

int CoreDecoder(
  BsBitStream   *fixed_stream,
  float         ll_core_buffer[], /* only core signal (modulo buffer) */
  int           ll_core_buff_len,
  int           ll_core_buff_pos,
  int           ch_select,
  int           gr
)
{
  LL_DEC_STATUS *p_lds = &CoreDecStatus[ch_select];

  float  core_lsr_buffer[2*960];
  float  *p_core_out[2];

  int lsr_samp_decoded, coreNumBit, itmp, bits_decodod;

  p_core_out[0] = core_lsr_buffer;

  /* advance to next read position for the core coder */
  MOD_BUFF_ADD( ll_core_buff_pos, ll_core_buff_pos, p_lds->lsr_last_samp_decoded+(gr*p_lds->samples_lsf_tf), ll_core_buff_len )

  lsr_samp_decoded = 0;
  bits_decodod     = 0;
  while( lsr_samp_decoded < (p_lds->samples_lsf_tf-p_lds->lsr_last_samp_decoded) )  {
    switch( p_lds->coreCodecIdx ) {
      case CC_G723_53:
        if (BsGetBuffer(fixed_stream,coreBitBuf,160))
          CommonExit(-11,"Decode core bitstream : error get buffer");
        DecG723Frame( coreBitBuf, p_core_out, &coreNumBit ); 
        break;
      case CC_G723_63:
        if (BsGetBuffer(fixed_stream,coreBitBuf,192))
          CommonExit(-11,"Decode core bitstream : error get buffer");
        DecG723Frame( coreBitBuf, p_core_out, &coreNumBit ); 
        break;
      case CC_G729:
        if (BsGetBuffer(fixed_stream,coreBitBuf,160))
          CommonExit(-11,"Decode core bitstream : error get buffer");
        DecG729Frame ( coreBitBuf, p_core_out , &coreNumBit , postProcMode );
        break;

        /*
      case CC_CELP_MPEG4_38:
      case CC_CELP_MPEG4_49:
        */
      case CC_CELP_MPEG4_60:
       {
        BITSTREAM *p_bitstream;

        if((p_bitstream=(BITSTREAM *)malloc(sizeof(BITSTREAM)))==NULL) {
          CommonExit(1, "Memory allocation error for dec_lpc in core_dec.c");
        }

        if (BsGetBuffer( fixed_stream, coreBitBuf, 120) )
          CommonExit(-11,"Decode core bitstream : error get buffer");

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

        coreNumBit = 120;  /* only ok for 6 kbps */

        celp_decoder (
          p_bitstream,      /* in: received bitstream */
          p_core_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 */
          InstanceContext		   /* in/Out: instance context */
        );

        BsPutBuffer( p_CoreBs, coreBitBuf );

        free(p_bitstream);
       }
        break;

        /*
      case CC_CELP_MPEG4_77:
      case CC_CELP_MPEG4_99:
      */
        /*
        celp_mp4_decoder(  );
        */
      default:
        CommonExit(-1,"coreCodecIdx %d not yet supported",p_lds->coreCodecIdx);
    }
    bits_decodod += coreNumBit;

    /* modulo buffer handling */
    itmp = min( p_lds->samples_lsf, ll_core_buff_len-ll_core_buff_pos );
    fvcopy( &core_lsr_buffer[0],    &ll_core_buffer[ll_core_buff_pos], 1 ,1, itmp );
    fvcopy( &core_lsr_buffer[itmp], &ll_core_buffer[0],                1 ,1, p_lds->samples_lsf-itmp );

    /* advance to next read position for the core coder */
    MOD_BUFF_ADD( ll_core_buff_pos, ll_core_buff_pos, p_lds->samples_lsf, ll_core_buff_len )

    lsr_samp_decoded += p_lds->samples_lsf;
  }

  p_lds->lsr_last_samp_decoded += (lsr_samp_decoded - p_lds->samples_lsf_tf);

  return( bits_decodod );
}

void CloseCoreDecoder( void )
{
  if( p_CoreBs ) {
    BsClose ( p_CoreBs );
  }
}
