/**********************************************************************
MPEG-4 Audio VM Module
parameter based codec - HILN: harmonic/individual lines and noise
                              bitstream encoder



This software module was originally developed by

Heiko Purnhagen (University of Hannover / Deutsche Telekom Berkom)
Bernd Edler (University of Hannover / Deutsche Telekom Berkom)

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.



Source file: indilineenc.c

$Id: indilineenc.c,v 1.6 1998/05/06 19:44:09 purnhage Exp $

Required libraries:
(none)

Required modules:
bitstream.o		bit stream module
indilinecom.o		indiline common module
indilineqnt.o		indiline quantiser module

Authors:
HP    Heiko Purnhagen, Uni Hannover <purnhage@tnt.uni-hannover.de>
BE    Bernd Edler, Uni Hannover <edler@tnt.uni-hannover.de>

Changes:
25-sep-96   HP    first version based on enc_par.c
26-sep-96   HP    new indiline module interfaces
19-nov-96   HP    adapted to new bitstream module
11-apr-97   HP    harmonic stuff ...
16-apr-97   BE    coding of harmonic stuff ...
22-apr-97   HP    noisy stuff ...
22-apr-97   BE    noise para ...
20-jun-97   HP    improved env/harm/noise interface
09-jul-97   HP    improved harmMaxNumBit, noiseMaxNumBit
16-nov-97   HP    harm/indi cont mode
16-feb-98   HP    improved noiseFreq
09-apr-98   HP    ILEconfig
**********************************************************************/


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include "bitstream.h"		/* bit stream module */

#include "indilinecom.h"	/* indiline common module */
#include "indilineqnt.h"	/* indiline quantiser module */
#include "indilineenc.h"	/* indiline bitstream encoder module */


/* units & formats: */
/*  Freq: frequency in Hz */
/*  Ampl: peak amplitude of sine wave */
/*  Phase: phase in rad at frame center */
/*  Index: NumBit LSBs, to be transmitted MSB first */
/*  Pred: line predecessor index: 0=no pred., 1=line[0], 2=line[1], ... */


/* ---------- declarations ---------- */

#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))

#define HARM_PHASE_NUMBIT 5
#define HARM_PHASE_NUMSTEP 32
#define HARM_PHASE_RANGE (2.*M_PI)
#define HARM_MAX_FBASE 4		/* max base for freq enh bit num */
#define HFREQRELSTEP (exp(log(4000./30.)/2048.))

/* ---------- declarations (data structures) ---------- */

/* status variables and arrays for individual line encoder (ILE) */

int freqThrE[HARM_MAX_FBASE] = {1177, 1467, 1757, 2047};
int fEnhaBitsHarm[10] = {0,1,2,2,3,3,3,3,4,4};

struct ILEstatusStruct {
  /* general parameters */
  ILQstatus *ILQ;
  ILEconfig *cfg;
  int debugLevel;
  int maxNumLine;
  int maxNumLineBS;
  int maxNumEnv;
  int maxNumHarm;
  int maxNumHarmLine;
  int maxNumNoisePara;
  int maxNumAllLine;
  int numLineNumBit;
  int quantMode;
  int contMode;
  int enhaFlag;
  int enhaQuantMode;


  /* pointers to variable content arrays */
  int *lineParaEnv;
  int *lineContFlag;
  int *linePredEnc;
  float *transAmpl;
  unsigned int *harmFreqIndex;
  unsigned int *harmFreqStretchIndex;
  unsigned int **harmAmplIndex;
  unsigned int *noiseParaIndex;
  unsigned int *harmEnhaIndex;
  unsigned int *harmEnhaNumBit;

  /* variables for frame-to-frame memory */
  int prevQuantNumLine;
  int prevNumTrans;

};


/* ---------- internal functions ---------- */


/* GenILEconfig() */
/* Generate default ILEconfig. */

static ILEconfig *GenILEconfig ()
{
  ILEconfig *cfg;

  if ((cfg = (ILEconfig*)malloc(sizeof(ILEconfig)))==NULL)
    IndiLineExit("GenILEconfig: memory allocation error");
  cfg->quantMode = -1;
  cfg->enhaQuantMode = -1;
  cfg->contMode = 0;
  cfg->encContMode = 0;
  cfg->bsFormat = 2;
  return cfg;
}


/* SmoothHarmAmpl() */
/* Smoothing of harm. amplitudes by frequency dependent triangular filter */

static void SmoothHarmAmpl (
  float f0,			/* in:  fundamental freq. */
  int numHarm,			/* in:  number of harmonics */
  float *harmAmpl,		/* in:  harm. amplitudes */
  float *smoothAmpl)		/* out: smoothed ampl. */
{
  int i,j,il,ih;
  float f,df,fl,fh,fi,coeff,sumCoeff;

  for(j=0;j<numHarm;j++) {
    f = (float)j*f0;
    df = 20.+f/5.;
    fh = min(f+df/2.,(float)numHarm*f0);
    fl = max(fh-df,f0);
    il = (int)(fl/f0+.999);
    ih = (int)(fh/f0+.001);
    sumCoeff = 1;
    smoothAmpl[j] = harmAmpl[j];
    for(i=il;i<j;i++) {
      fi = (float)i*f0;
      coeff = (fi-fl)/(f-fl);
      smoothAmpl[j] += coeff*harmAmpl[i];
      sumCoeff += coeff;
    }
    for(i=j+1;i<=ih;i++) {
      fi = (float)i*f0;
      coeff = (fh-fi)/(fh-f);
      smoothAmpl[j] += coeff*harmAmpl[i];
      sumCoeff += coeff;
    }
    smoothAmpl[j] /= sumCoeff;
  }
}


/* TransfHarmAmpl() */
/* Transform  harm. amplitudes by freq. dependent averaging */

static int TransfHarmAmpl (
  int numAmpl,
  float *Ampl,
  float *transAmpl)
{
#define MAXGRP 7

  int i,j,igrp,il,numTrans;
  int numGrp[MAXGRP] = {10,6,5,4,3,2,1};	/* 10 groups of 1 line ... */
  float sumAmpl;

  il = igrp = i = numTrans = 0;
  while(il<numAmpl) {
    sumAmpl = 0;
    for(j=il;j<min(il+igrp+1,numAmpl);j++)
      sumAmpl += Ampl[j];
    transAmpl[numTrans++] = sumAmpl/sqrt((float)(igrp+1));
    il = min(il+igrp+1,numAmpl);
    i++;
    if(i>=numGrp[igrp]) {
      i = 0;
      igrp++;
    }
  }
  return(numTrans);
}



/* ---------- functions ---------- */

/* IndiLineEncodeInit() */
/* Init individual lines bitstream encoder. */

ILEstatus *IndiLineEncodeInit (
  int frameLenQuant,		/* in: samples per frame */
				/*     used for quantiser selection */
  float fSampleQuant,		/* in: sampling frequency */
				/*     used for quantiser selection */
  float maxLineAmpl,		/* in: max line amplitude */
  int enhaFlag,			/* in: enha flag (0=basic 1=enha) */
  int frameMaxNumBit,		/* in: max num bits per frame */
  int maxNumLine,		/* in: max num lines */
				/*     if maxNumLine < 0 use maxNumLineBS */
				/*     calculated from frameMaxNumBit */
  int maxNumEnv,		/* in: max num envelopes */
  int maxNumHarm,		/* in: max num harmonic tones */
  int maxNumHarmLine,		/* in: max num lines of harmonic tone */
  int maxNumNoisePara,		/* in: max num noise parameters */
  ILEconfig *cfg,		/* in: ILE configuration */
				/*     or NULL */
  int debugLevel,		/* in: debug level (0=off) */
  BsBitStream *hdrStream,	/* out: bit stream header */
  int *maxNumLineBS,		/* out: max num lines in bitstream */
  float *maxNoiseFreq)		/* out: max noise freq */
				/* returns: ILE status handle */
{
  ILEstatus *ILE;
  int envNumBit,newLineNumBit,contLineNumBit;
  int i;
  int hdrFrameLengthBase;
  int hdrFrameLength;


  if ((ILE = (ILEstatus*)malloc(sizeof(ILEstatus)))==NULL)
    IndiLineExit("IndiLineEncodeInit: memory allocation error");

  ILE->cfg = GenILEconfig();
  if (cfg != NULL)
    memcpy(ILE->cfg,cfg,sizeof(ILEconfig));

  ILE->debugLevel = debugLevel;
  ILE->maxNumLine = maxNumLine;
  ILE->maxNumEnv = maxNumEnv;
  ILE->maxNumHarm = maxNumHarm;
  ILE->maxNumHarmLine = maxNumHarmLine;
  ILE->maxNumNoisePara = maxNumNoisePara;
  ILE->maxNumAllLine = maxNumLine+maxNumHarm*maxNumHarmLine;

  if (ILE->cfg->quantMode < 0) {
    /* HP 980216 */
    if (fSampleQuant <= 8000.5)
      ILE->quantMode = 0;
    else if (fSampleQuant <= 16000.5)
      ILE->quantMode = 2;
    else
      ILE->quantMode = 4;
  }
  else
    ILE->quantMode = ILE->cfg->quantMode;
  switch (ILE->quantMode) {
  case 0:
  case 1:
    *maxNoiseFreq = 4000.;
    break;
  case 2:
  case 3:
    *maxNoiseFreq = 8000.;
    break;
  case 4:
  case 5:
    *maxNoiseFreq = 20000.;
    break;
  }

  ILE->contMode = ILE->cfg->contMode;
  ILE->enhaFlag = enhaFlag;
  if (ILE->enhaFlag) {
    if (ILE->cfg->enhaQuantMode < 0) {
      if (ILE->quantMode <= 1)
	ILE->enhaQuantMode = 2;
      else
	ILE->enhaQuantMode = 1;
    }
    else
      ILE->enhaQuantMode = ILE->cfg->enhaQuantMode;
  }
  else
    ILE->enhaQuantMode = 0;

  hdrFrameLengthBase = ((int)(fSampleQuant+.5)%11025 == 0) ? 1 : 0;
  hdrFrameLength = (int)(frameLenQuant/fSampleQuant*
			 (hdrFrameLengthBase ? 44100.0 : 48000.0));

  /* first calculation with minimum number of bits */
  IndiLineNumBit(NULL,&envNumBit,&newLineNumBit,&contLineNumBit);
  ILE->maxNumLineBS = (frameMaxNumBit-1)/(contLineNumBit+1)+1;
  if (maxNumLine >= 0)
    ILE->maxNumLineBS = min(maxNumLine,ILE->maxNumLineBS);

  ILE->ILQ = IndiLineQuantInit(ILE->quantMode,ILE->enhaQuantMode,maxLineAmpl,
			       ILE->maxNumLineBS,0,debugLevel);

  IndiLineNumBit(ILE->ILQ,&envNumBit,&newLineNumBit,&contLineNumBit);
  ILE->maxNumLine = (frameMaxNumBit-1)/(contLineNumBit+1)+1;
  if (maxNumLine >= 0)
    ILE->maxNumLineBS = min(maxNumLine,ILE->maxNumLineBS);

  *maxNumLineBS = ILE->maxNumLineBS;

  /* calc num bits required for numLine in bitstream */
  ILE->numLineNumBit = 0;
  while (1<<ILE->numLineNumBit <= ILE->maxNumLineBS)
    ILE->numLineNumBit++;

  /* put header info bits to header */
  if (ILE->cfg->bsFormat < 2) {
    /* old header */
    if (BsPutBit(hdrStream,ILE->maxNumLineBS,16) ||
	BsPutBit(hdrStream,(long)(fSampleQuant+.5),32) ||
	BsPutBit(hdrStream,frameLenQuant,16))
      IndiLineExit("IndiLineEncodeInit: error generating bit stream header");
  }
  else {
    if (BsPutBit(hdrStream,ILE->quantMode,3))
      IndiLineExit("IndiLineEncodeInit: error generating bit stream header");
    if (BsPutBit(hdrStream,ILE->maxNumLineBS,8))
      IndiLineExit("IndiLineEncodeInit: error generating bit stream header");
    if (BsPutBit(hdrStream,hdrFrameLengthBase,1))
      IndiLineExit("IndiLineEncodeInit: error generating bit stream header");
    if (BsPutBit(hdrStream,hdrFrameLength,12))
      IndiLineExit("IndiLineEncodeInit: error generating bit stream header");
    if (BsPutBit(hdrStream,ILE->contMode,2))
      IndiLineExit("IndiLineEncodeInit: error generating bit stream header");
    if (BsPutBit(hdrStream,ILE->enhaFlag,1))
      IndiLineExit("IndiLineEncodeInit: error generating bit stream header");
    if (ILE->enhaFlag) {
      if (BsPutBit(hdrStream,ILE->enhaQuantMode,2))
	IndiLineExit("IndiLineEncodeInit: error generating bit stream header");
    }
  }

  if (
      /* variable content arrays and arrays for frame-to-frame memory */
      (ILE->lineParaEnv=(int*)malloc(ILE->maxNumLine*sizeof(int)))==NULL ||
      (ILE->lineContFlag=(int*)malloc(ILE->maxNumLine*sizeof(int)))==NULL ||
      (ILE->linePredEnc=(int*)malloc(ILE->maxNumLine*sizeof(int)))==NULL ||
      (ILE->transAmpl=(float*)malloc(ILE->maxNumHarmLine*
				     sizeof(float)))==NULL ||
      (ILE->harmFreqIndex=(unsigned int*)malloc(ILE->maxNumHarm*
						sizeof(unsigned int)))==NULL ||
      (ILE->harmFreqStretchIndex=(unsigned int*)malloc(ILE->maxNumHarm*
					        sizeof(unsigned int)))==NULL ||
      (ILE->harmAmplIndex=(unsigned int**)malloc(ILE->maxNumHarm*
					       sizeof(unsigned int*)))==NULL ||
      (ILE->harmAmplIndex[0]=(unsigned int*)malloc(ILE->maxNumHarm*
						   ILE->maxNumHarmLine*
						sizeof(unsigned int)))==NULL ||
      (ILE->noiseParaIndex=(unsigned int*)malloc(ILE->maxNumNoisePara*
						sizeof(unsigned int)))==NULL ||
      (ILE->harmEnhaIndex=(unsigned int*)malloc(ILE->maxNumHarmLine*
					       sizeof(unsigned int)))==NULL ||
      (ILE->harmEnhaNumBit=(unsigned int*)malloc(ILE->maxNumHarmLine*
					       sizeof(unsigned int)))==NULL)
    IndiLineExit("IndiLineEncodeInit: memory allocation error");

  for (i=1;i<ILE->maxNumHarm;i++) {
    ILE->harmAmplIndex[i] = ILE->harmAmplIndex[0]+i*ILE->maxNumHarmLine;
  }

  /* clear frame-to-frame memory */
  ILE->prevQuantNumLine = 0;
  ILE->prevNumTrans = 0;


  if (debugLevel >= 1) {
    printf("IndiLineEncodeInit: envNumBit=%d  newLineNumBit=%d\n"
	   "                    contLineNumBit=%d\n"
	   "                    maxNumLineBS=%d  numLineNumBit=%d\n",
	   envNumBit,newLineNumBit,contLineNumBit,
	   ILE->maxNumLine,ILE->numLineNumBit);
    printf("IndiLineEncodeInit: frmLenBase=%d  frmLen=%d  (%8.6f)\n",
	   hdrFrameLengthBase,hdrFrameLength,
	   hdrFrameLength/(hdrFrameLengthBase ? 44100.0 : 48000.0));
    printf("IndiLineEncodeInit: quantMode=%d  contMode=%d  "
	   "enhaFlag=%d  enhaQuantMode=%d\n",
	   ILE->quantMode,ILE->contMode,ILE->enhaFlag,ILE->enhaQuantMode);
  }

  return ILE;
}


/* IndiLineEncodeFrame() */
/* Encode individual lines frame to bitstream. */

void IndiLineEncodeFrame (
  ILEstatus *ILE,		/* in: ILE status handle */
  int numEnv,			/* in: num envelopes */
  float **envPara,		/* in: envelope parameters */
				/*     [0..numEnv-1][0..ENVPARANUM-1] */
  int numLine,			/* in: num lines */
  float *lineFreq,		/* in: line frequency */
				/*     [0..numLine-1] */
  float *lineAmpl,		/* in: line amplitude */
				/*     [0..numLine-1] */
  float *linePhase,		/* in: line phase */
				/*     [0..numLine-1] */
  int *lineEnv,			/* in: line envelope flag/idx */
				/*     [0..numLine-1] */
  int *linePred,		/* in: line predecessor idx */
				/*     [0..numLine-1] */
  int numHarm,			/* in: num harmonic tones */
  int *numHarmLine,		/* in: num lines of harmonic tone */
				/*     [0..numHarm-1] */
  float *harmFreq,		/* in: harm fundamental frequency [Hz] */
				/*     [0..numHarm-1] */
  float *harmFreqStretch,	/* in: harm freq stretch ratio */
				/*     [0..numHarm-1] */
  int *harmLineIdx,		/* in: harm line para start idx */
				/*     [0..numHarm-1] */
				/*     ampl: lineAmpl[idx] etc. */
				/*     idx=harmLineIdx+(0..numHarmLine-1) */
  int *harmEnv,			/* in: harm envelope flag/idx */
				/*     [0..numHarm-1] */
  int *harmPred,		/* in: harm tone predecessor idx */
				/*     [0..numHarm-1] */
  float *harmRate,		/* in: bitrate for harm data (0..1) */
				/*     [0..numHarm-1] */
  int numNoisePara,		/* in: num noise parameter */
  float noiseFreq,		/* in: max noise freq (bandwidth) [Hz] */
  float *noisePara,		/* in: noise parameter (DCT) */
				/*     [0..numNoisePara-1] */
  int noiseEnv,			/* in: noise envelope flag/idx */
  float noiseRate,		/* in: bitrate for noise data (0..1) */
  int frameAvailNumBit,		/* in: total num bits available for */
				/*     this frame (incl. bit reservoir) */
  int frameNumBit,		/* in: average num bits per frame */
  int frameMaxNumBit,		/* in: max num bits per frame */
  BsBitStream *stream,		/* out: bit stream */
  BsBitStream *streamEnha)	/* out: enhancement bit stream */
				/*      or NULL for basic mode */
{
  int i,il,ilTrans,j;
  int firstEnvLine;
  int basicMaxNumBit,basicNumBit,chkNumBit;
  int quantNumLine;
  float *quantEnvPara;
  float *quantEnvParaEnha;
  int envParaFlag,quantEnvParaFlag;
  int envParaNumBit,envParaEnhaNumBit;
  unsigned int envParaIndex,envParaEnhaIndex;
  float *quantLineFreq;
  float *quantLineAmpl;
  int *quantLineEnv;
  int *quantLinePred;
  float *quantLineFreqEnha;
  float *quantLineAmplEnha;
  float *quantLinePhase;
  int *lineSeq;
  int *lineParaPred;
  int *lineParaNumBit;
  unsigned int *lineParaIndex;
  int *lineParaEnhaNumBit;
  unsigned int *lineParaEnhaIndex;

  int harmMaxNumBit,harmNumBit;
  int quantNumHarm;
  float quantHarmFreq,quantHarmFreqStretch,quantHarmAmpl;
  int harmAmplInt,harmAmplIntOverl,prevAmplInt;
  int addHarmAmplBits,harmAmplMax,harmAmplOff;

  int numTrans,numTransDesired;

  int noiseMaxNumBit,noiseNumBit;
  int quantNumNoise;
  unsigned int noiseNormIndex;
  float noiseNorm;
  unsigned int noiseEnvParaIndex;
  int noiseEnvParaFlag,noiseEnvParaNumBit,noiseEnvParaEnhaNumBit;
  unsigned int noiseEnvParaEnhaIndex;
  int xint;

  int fhint,fNumBitBase,fNumBitE,freqNumStepE,fintE,pintE;
  float fq;

  /* indiline continuation parameters */
  for (i=0; i<numLine; i++)
    ILE->linePredEnc[i] = linePred[i];

  if (ILE->cfg->encContMode)
    /* no continued individual lines */
    for (i=0; i<numLine; i++)
      ILE->linePredEnc[i] = 0;


  /* quantise envelope parameters if required */
  firstEnvLine = -1;
  for (il=0; il<numLine; il++)
    if (lineEnv[il] && firstEnvLine<0)
      firstEnvLine = il;
  if (firstEnvLine >= 0 || numHarm && numHarmLine[0] && harmEnv[0])
    IndiLineEnvQuant(ILE->ILQ,envPara[0],&envParaFlag,
		     &envParaIndex,&envParaNumBit,
		     &envParaEnhaIndex,&envParaEnhaNumBit);
  else
    envParaFlag = 0;
  if (envParaFlag && numHarm && harmEnv)
    firstEnvLine = -1;	/* force env para coding */
  for (il=0; il<numLine; il++)
    ILE->lineParaEnv[il] = lineEnv[il] && envParaFlag;
  harmEnv[0] = harmEnv[0] && envParaFlag;

  /* dequantise envelope parameters */
  IndiLineEnvDequant(ILE->ILQ,envParaFlag,envParaIndex,envParaNumBit,
		     envParaEnhaIndex,0,
		     &quantEnvPara,&quantEnvParaEnha);

  /* quantise line parameters */
  IndiLineQuant(ILE->ILQ,numLine,lineFreq,lineAmpl,linePhase,
		ILE->lineParaEnv,
		ILE->linePredEnc,
		&lineParaPred,&lineParaIndex,&lineParaNumBit,
		&lineParaEnhaIndex,&lineParaEnhaNumBit);
  
  /* determine number of bits to be used for this frame */
  /* (to be replaced by bit reservoir control) */
  basicMaxNumBit = frameAvailNumBit;


  /* noise stuff */

  quantNumNoise = 0;
  if(noiseRate>.01)
    quantNumNoise = 4;
  if(noiseRate>.03)
    quantNumNoise = 5;
  if(noiseRate>.1)
    quantNumNoise = 6;
  if(noiseRate>.3)
    quantNumNoise = 7;
  quantNumNoise = min(ILE->maxNumNoisePara,quantNumNoise);

  /* HP 970709 */
  noiseMaxNumBit = (int)((frameAvailNumBit-ILE->numLineNumBit
			  -1-ILE->prevQuantNumLine
			  -envParaFlag*envParaNumBit)
			 *(1.0+noiseRate)/(1.0+1.0)*0.5);
  quantNumNoise = min(quantNumNoise,(noiseMaxNumBit-1-2-1-6)/3);
  if (quantNumNoise < 4)
    quantNumNoise = 0;

  noiseNumBit = 1;
  if(quantNumNoise) {
    noiseNumBit += 2;			/* quantNumNoise */
    noiseNumBit += 1;			/* noiseEnv */
    noiseNumBit += 6;			/* noiseNormIndex */
    noiseNumBit += quantNumNoise*3;	/* noiseParaIndex[0] ... */

    if(noiseEnv) {
      IndiLineEnvQuant(ILE->ILQ,envPara[noiseEnv-1],&noiseEnvParaFlag
		       ,&noiseEnvParaIndex,&noiseEnvParaNumBit
		       ,&noiseEnvParaEnhaIndex,&noiseEnvParaEnhaNumBit);
    }
    else
      noiseEnvParaFlag = 0;
    if(noiseEnvParaFlag)
      noiseNumBit += noiseEnvParaNumBit;
  }
  if(quantNumNoise) {
    noiseNorm = 1;
    for(i=0;i<quantNumNoise;i++)
      noiseNorm = max(noiseNorm,fabs(noisePara[i]));
    noiseNormIndex = min((int)(2.*log(max(noiseNorm,1))/log(2.)),63);
    noiseNorm = exp((float)(noiseNormIndex+1)*log(2.)/2.)/8.;
    ILE->noiseParaIndex[0] = min(max((int)(noisePara[0]/noiseNorm),0),7);
    for(i=1;i<quantNumNoise;i++)
      ILE->noiseParaIndex[i] = min(max((int)(noisePara[i]/noiseNorm/2.+4.),0),7);

    if(ILE->debugLevel>=2) {
      printf("numNoise=%2d, noiseNumBit=%3d, noiseNormIndex=%2d\n"
	     ,quantNumNoise,noiseNumBit,noiseNormIndex);
      printf("noiseIndex: %3d",(int)(noisePara[0]/noiseNorm));
      for(i=1;i<quantNumNoise;i++)
	printf("%3d",(int)(noisePara[i]/noiseNorm/2.+8.));
      printf("\n");
    }

  }

  /* harmonic stuff */
  if (numHarm) {
    if (numHarmLine[0]==1)
      IndiLineExit("IndiLineEncodeFrame: harm. with 1 line not supported!");

    numTransDesired = numTrans =
      TransfHarmAmpl(numHarmLine[0],lineAmpl+harmLineIdx[0],ILE->transAmpl);
  }
  else
    numTrans = 0;

  for(i=0;i<numTrans;i++) {
    ILE->transAmpl[i] = log(max(ILE->transAmpl[i],1.))/log(2.);
  }

  /* HP 970709   ILE->numLineNumBit was neglected ... */
  /*  harmMaxNumBit = min((int)(frameAvailNumBit*.75), */  /* 75% for harm */
  harmMaxNumBit = (int)((frameAvailNumBit-ILE->numLineNumBit
			 -1-ILE->prevQuantNumLine
			 -envParaFlag*envParaNumBit-noiseNumBit)
			*(0.5+harmRate[0])/(0.5+1.0));
  harmNumBit = 1;	/* harm flag */
  if (numTrans) {
    harmNumBit += 6;	/* numTrans */
    harmNumBit += 1;	/* add. ampl bits */
    harmNumBit += 1;	/* cont */
    harmNumBit += 1;	/* env */
    harmNumBit += 11;	/* f */
    harmNumBit += 5;	/* fs */
    harmNumBit += 6;	/* transAmpl0 */

    if(numTrans<=16)
      addHarmAmplBits = 1;
    else
      addHarmAmplBits = 0;

    numTrans = min(numTrans,(harmMaxNumBit-harmNumBit)/(4+addHarmAmplBits)+1);

    numTrans = max(0,min(64,numTrans));		/* BE/HP 971115 */

    harmNumBit += (4+addHarmAmplBits)*(numTrans-1);	/* transAmpl1... */

    if(ILE->debugLevel>=2)
      printf("numTrans=%2d, harmNumBit=%3d\n",numTrans,harmNumBit);
    if(ILE->debugLevel>=2 && numTrans<numTransDesired)
      printf("numTransDesired=%2d, numTrans=%2d\n",numTransDesired,numTrans);

    /* quantise harm */
    harmAmplMax = 16*(1+addHarmAmplBits)-1;
    harmAmplOff = harmAmplMax/3;

    fhint = (int)(log(harmFreq[0]/30.)/log(4000./30.)*2048.);
    ILE->harmFreqIndex[0] = max(0,min(2047,fhint));
    quantHarmFreq = exp((ILE->harmFreqIndex[0]+.5)/2048.*log(4000./30.))*30.;
    xint = (int)((harmFreqStretch[0]/0.002+0.5)*32.+.5);
    ILE->harmFreqStretchIndex[0] = max(0,min(31,xint));
    quantHarmFreqStretch = (ILE->harmFreqStretchIndex[0]/32.-.5)*0.002;
    harmAmplInt = (int)(ILE->transAmpl[0]*3.);
    prevAmplInt = ILE->harmAmplIndex[0][0] = max(0,min(63,harmAmplInt));
    for(i=1;i<numTrans;i++) {
      harmAmplInt = (int)(ILE->transAmpl[i]*3.);
      ILE->harmAmplIndex[0][i] = max(0,harmAmplInt-prevAmplInt+harmAmplOff);
      prevAmplInt += ILE->harmAmplIndex[0][i]-harmAmplOff;
      harmAmplIntOverl = ILE->harmAmplIndex[0][i]-harmAmplMax;
      j = i;
      while(harmAmplIntOverl>0 && j>0) {

	if(ILE->debugLevel>=2 && harmAmplIntOverl>0)
	  printf("harm ampl overload correction: line# %2d (%2d), index %2d\n",
		 j,i,ILE->harmAmplIndex[0][j]);

	ILE->harmAmplIndex[0][j] = harmAmplMax;
	ILE->harmAmplIndex[0][j-1] += harmAmplIntOverl;
	harmAmplIntOverl = ILE->harmAmplIndex[0][j-1]-harmAmplMax;
	j--;
      }
    }

    /* quantise harm enhancement */

    fNumBitBase = 0;
    while (fNumBitBase<HARM_MAX_FBASE && fhint>freqThrE[fNumBitBase])
      fNumBitBase++;
    if (fNumBitBase==HARM_MAX_FBASE)
      IndiLineExit("IndiLineEncodeFrame: fnumbite error");
    fNumBitBase += max(0,min(3,ILE->enhaQuantMode))-3;

    for(i=0;i<min(10,numTrans);i++) {

      if(ILE->debugLevel>=4)
	printf("harmEnh: ");

      fNumBitE = max(0,fNumBitBase+fEnhaBitsHarm[i]);
      if(fNumBitE>0) {
	freqNumStepE = 1<<fNumBitE;
	fq = quantHarmFreq*(i+1)*(1+quantHarmFreqStretch*(i+1));

	fintE = (int)(((lineFreq[harmLineIdx[0]+i]/fq-1)/(HFREQRELSTEP-1)+.5)*
		    freqNumStepE);
	fintE = max(min(fintE,freqNumStepE-1),0);
      }
      pintE = (int)((linePhase[harmLineIdx[0]+i]/HARM_PHASE_RANGE+.5)
		   *HARM_PHASE_NUMSTEP);
      pintE = max(min(pintE,HARM_PHASE_NUMSTEP-1),0);

      if(ILE->debugLevel>=4) {
 	if(fNumBitE>0)
	  printf("f=%7.2f, fq=%7.2f, fe=%7.2f, ",
		 lineFreq[harmLineIdx[0]+i],fq,
		 fq*(1+((fintE+.5)/freqNumStepE-.5)*(HFREQRELSTEP-1)));
	else
	  printf("f=%7.2f, fq=%7.2f, fe=%7.2f, ",
		 lineFreq[harmLineIdx[0]+i],
		 quantHarmFreq*(i+1)*(1+quantHarmFreqStretch*(i+1)),
		 quantHarmFreq*(i+1)*(1+quantHarmFreqStretch*(i+1)));

	printf("p=%5.2f, pq=%5.2f\n",linePhase[harmLineIdx[0]+i],
	       ((pintE+.5)/HARM_PHASE_NUMSTEP-.5)*HARM_PHASE_RANGE);
      }

      ILE->harmEnhaIndex[i] = 0;
      ILE->harmEnhaNumBit[i] = 0;
      if (fNumBitE > 0) {	
	ILE->harmEnhaIndex[i] = ILE->harmEnhaIndex[i]<<fNumBitE | fintE;
	ILE->harmEnhaNumBit[i] += fNumBitE;
      }
      ILE->harmEnhaIndex[i] =  ILE->harmEnhaIndex[i]<<HARM_PHASE_NUMBIT
				| pintE;
      ILE->harmEnhaNumBit[i] += HARM_PHASE_NUMBIT;
    }
  }
  /* determine number of lines which can be transmitted with basicMaxNumBit */
  basicNumBit = ILE->numLineNumBit;	/* numLine bits */
  basicNumBit += 1+ILE->prevQuantNumLine;	/* env flag and continue bits */

  basicNumBit += harmNumBit;
  basicNumBit += noiseNumBit;


  for (il=0; il<numLine; il++) {
    if (envParaFlag && il>=firstEnvLine)
      /* number of bits if envelope is needed */
      chkNumBit = basicNumBit+envParaNumBit+(il+1)+lineParaNumBit[il];
    else
      /* number of bits if envelope is not needed */
      chkNumBit = basicNumBit+lineParaNumBit[il];
    if (chkNumBit > basicMaxNumBit)
      break;
    basicNumBit += lineParaNumBit[il];	/* line para bits */
  }
  quantNumLine = il;

  /* determine if envelope parameters are transmitted */
  quantEnvParaFlag = envParaFlag && quantNumLine>firstEnvLine;
  if (quantEnvParaFlag)
    basicNumBit += envParaNumBit+quantNumLine;	/* env para bits and */
						/* line env flags */

  if (ILE->debugLevel >= 2) {
    printf("IndiLineEncodeFrame: "
	   "quantNumLine=%d  basicMaxNumBit=%d  basicNumBit=%d\n",
	   quantNumLine,basicMaxNumBit,basicNumBit);
    printf("IndiLineEncodeFrame: "
	   "numHarm=%d  numHarmLine=%d  numTrans=%d  harmNumBit=%d\n",
	   numHarm,numHarmLine[0],numTrans,harmNumBit);
    printf("IndiLineEncodeFrame: "
	   "envParaFlag=%d  quantEnvParaFlag=%d  firstEnvLine=%d\n",
	   envParaFlag,quantEnvParaFlag,firstEnvLine);
  }

  /* determine line transmission sequence */
  IndiLineSequence(ILE->ILQ,quantNumLine,lineParaPred,&lineSeq);

  /* determine continue bits for all lines transmitted in the previous frame */
  for (il=0; il<ILE->prevQuantNumLine; il++)
    ILE->lineContFlag[il] = 0;
  for (il=0; il<quantNumLine; il++)
    if (lineParaPred[il])
      ILE->lineContFlag[lineParaPred[il]-1] = 1;

  /* put quantNumLine to bitstream */
  if (BsPutBit(stream,quantNumLine,ILE->numLineNumBit))
    IndiLineExit("IndiLineEncodeFrame: error generating bit stream (numLine)");

  /* put envelope parameters to bitstream */
  if (BsPutBit(stream,quantEnvParaFlag,1))
    IndiLineExit("IndiLineEncodeFrame: error generating bit stream (envFlag)");
  if (quantEnvParaFlag)
    if (BsPutBit(stream,envParaIndex,envParaNumBit))
      IndiLineExit("IndiLineEncodeFrame: error generating bit stream (envPara)");

  /* put continue bits to bitstream */
  for (il=0; il<ILE->prevQuantNumLine; il++)
    if (BsPutBit(stream,ILE->lineContFlag[il],1))
      IndiLineExit("IndiLineEncodeFrame: error generating bit stream (contFlag %d)",il);

  if (ILE->cfg->bsFormat!=0) {
    /* harmonic stuff */
    if (BsPutBit(stream,numTrans?1:0,1))
      IndiLineExit("IndiLineEncodeFrame: error generating bit stream (harm)");
    if (numTrans) {
      if (BsPutBit(stream,numTrans-1,6))
	IndiLineExit("IndiLineEncodeFrame: error generating bit stream (harm n)");
      if (BsPutBit(stream,addHarmAmplBits,1))
	IndiLineExit("IndiLineEncodeFrame: error generating bit stream (harm add)");
      if (BsPutBit(stream,(harmPred[0]>0 && ILE->prevNumTrans>0)?1:0,1))
	IndiLineExit("IndiLineEncodeFrame: error generating bit stream (harm c)");
      if (BsPutBit(stream,(unsigned int)harmEnv[0],1))
	IndiLineExit("IndiLineEncodeFrame: error generating bit stream (harm e)");
      if (BsPutBit(stream,ILE->harmFreqIndex[0],11))
	IndiLineExit("IndiLineEncodeFrame: error generating bit stream (harm f)");
      if (BsPutBit(stream,ILE->harmFreqStretchIndex[0],5))
	IndiLineExit("IndiLineEncodeFrame: error generating bit stream (harm fs)");
      if (BsPutBit(stream,ILE->harmAmplIndex[0][0],6))
	IndiLineExit("IndiLineEncodeFrame: error generating bit stream (harm ta0)");
      for (il=1; il<numTrans; il++)
	if (BsPutBit(stream,ILE->harmAmplIndex[0][il],4+addHarmAmplBits))
	  IndiLineExit("IndiLineEncodeFrame: error generating bit stream (harm ta%d)",il);
    }
    
    /* noise stuff */
    if (BsPutBit(stream,quantNumNoise?1:0,1))
      IndiLineExit("IndiLineEncodeFrame: error generating bit stream (noise)");
    if (quantNumNoise) {
      if (BsPutBit(stream,quantNumNoise-4,2))
	IndiLineExit("IndiLineEncodeFrame: error generating bit stream (noise n)");
      if (BsPutBit(stream,noiseEnvParaFlag,1))
	IndiLineExit("IndiLineEncodeFrame: error generating bit stream (noise e)");
      if (BsPutBit(stream,noiseNormIndex,6))
	IndiLineExit("IndiLineEncodeFrame: error generating bit stream (noise p0)");
      for (i=0; i<quantNumNoise; i++)
	if (BsPutBit(stream,ILE->noiseParaIndex[i],3))
	  IndiLineExit("IndiLineEncodeFrame: error generating bit stream (noise p%d)",i);
      if (noiseEnvParaFlag)
      if (BsPutBit(stream,noiseEnvParaIndex,noiseEnvParaNumBit))
	IndiLineExit("IndiLineEncodeFrame: error generating bit stream (noise env)");
    }
  }    

  /* put line parameters to bitstream */
  for (ilTrans=0; ilTrans<quantNumLine; ilTrans++) {
    il = lineSeq[ilTrans];
    if (quantEnvParaFlag)
      if (BsPutBit(stream,ILE->lineParaEnv[il],1))
	IndiLineExit("IndiLineEncodeFrame: error generating bit stream (lineEnv %d)",il);
    if (BsPutBit(stream,lineParaIndex[il],lineParaNumBit[il]))
      IndiLineExit("IndiLineEncodeFrame: error generating bit stream (linePara %d)",il);
  }

  /* put enhancement parameters to bitstream */
  if (streamEnha) {
    /* envelope */
    if (quantEnvParaFlag)
      if (BsPutBit(streamEnha,envParaEnhaIndex,envParaEnhaNumBit))
	IndiLineExit("IndiLineEncodeFrame: error generating bit stream (envParaEnha)");
    /* harm */
    if(numTrans)
      for (il=0; il<min(10,numTrans); il++)
	if (BsPutBit(streamEnha,ILE->harmEnhaIndex[il],
		     ILE->harmEnhaNumBit[il]))
	  IndiLineExit("IndiLineEncodeFrame: error generating bit stream (harm enha%d)",il);

    /* indi lines */
    for (ilTrans=0; ilTrans<quantNumLine; ilTrans++) {
      il = lineSeq[ilTrans];
      if (BsPutBit(streamEnha,lineParaEnhaIndex[il],lineParaEnhaNumBit[il]))
	IndiLineExit("IndiLineEncodeFrame: error generating bit stream (lineParaEnha %d)",il);
    }
  }



  /* dequantise line parameters */
  IndiLineDequant(ILE->ILQ,quantNumLine,
		  lineSeq,lineParaPred,NULL,
		  ILE->lineParaEnv,lineParaIndex,lineParaNumBit,
		  lineParaEnhaIndex,
		  /*$NULL,$*/
		  lineParaEnhaNumBit,
		  &quantLineFreq,&quantLineAmpl,&quantLineEnv,&quantLinePred,
		  &quantLineFreqEnha,&quantLineAmplEnha,&quantLinePhase);
  
  if (ILE->debugLevel >= 3) {
    printf("dequan\n");
    printf("env: tm=%7.5f atk=%7.5f dec=%7.5f\n",
	   quantEnvPara[0],quantEnvPara[1],quantEnvPara[2]);
    printf("cont: ");
    for (il=0; il<ILE->prevQuantNumLine; il++)
      printf("%1d",ILE->lineContFlag[il]);
    printf("\n");
    for (il=0; il<quantNumLine; il++)
      printf("%2d: f=%7.1f fe=%7.1f a=%7.1f p=%5.2f e=%1d c=%2d s=%2d\n",
	     il,quantLineFreq[il],quantLineFreqEnha[il],
	     quantLineAmpl[il],quantLinePhase[il],
	     quantLineEnv[il],quantLinePred[il],lineSeq[il]);
  }

  /* save parameters in frame-to-frame memory */
  ILE->prevQuantNumLine = quantNumLine;
  ILE->prevNumTrans = numTrans;

}


/* IndiLineEncodeFree() */
/* Free memory allocated by IndiLineEncodeInit(). */

void IndiLineEncodeFree (
  ILEstatus *ILE)		/* in: ILE status handle */
{
  IndiLineQuantFree(ILE->ILQ);
  free(ILE->lineParaEnv);
  free(ILE->lineContFlag);
  free(ILE->linePredEnc);
  free(ILE->transAmpl);
  free(ILE->harmFreqIndex);
  free(ILE->harmFreqStretchIndex);
  free(ILE->harmAmplIndex[0]);
  free(ILE->harmAmplIndex);
  free(ILE->noiseParaIndex);
  free(ILE);
}



/* end of indilineenc.c */
