/**********************************************************************
MPEG-4 Audio VM Module
parameter based codec - individual lines: bitstream decoder



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) 1996.



Source file: indilinedec.c

$Id: indilinedec.c,v 1.12 1998/05/06 19:44:03 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 dec_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    decoding of harmonic stuff ...
22-apr-97   HP    noisy stuff ...
23-apr-97   BE    decoding of noise stuff ...
07-may-97   HP    fixed bug calling BsGetBit(lineParaIndex[])
14-may-97   HP    fixed "cont:" debug stuff
23-jun-97   HP    improved env/harm/noise interface
24-jun-97   HP    added IndiLineDecodeHarm()
16-nov-97   HP    harm/indi cont mode
27-nov-97   HP    fixed SGI CC problem (CommonWarning())
16-feb-98   HP    improved noiseFreq
30-mar-98   BE/HP initPrevNumLine
31-mar-98   HP    completed IndiLineDecodeFree()
06-apr-98   HP    ILDconfig
06-may-98   HP    linePhaseValid
**********************************************************************/


#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 "indilinedec.h"	/* indiline bitstream decoder 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 decoder (ILD) */

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

struct ILDstatusStruct		/* ILD status handle struct */
{
  /* general parameters */
  ILQstatus *ILQ;
  ILDconfig *cfg;
  int debugLevel;
  int maxNumLine;
  int maxNumEnv;
  int maxNumHarm;
  int maxNumHarmLine;
  int maxNumNoisePara;
  int maxNumAllLine;
  int numLineNumBit;
  int envNumBit;
  int newLineNumBit;
  int contLineNumBit;
  float fSample;
  int quantMode;
  int contMode;
  int enhaFlag;
  int enhaQuantMode;
  float maxNoiseFreq;

  /* arrays for return values */
  float **envPara;		/* envelope parameters */
  float *lineFreq;		/* line frequencies */
  float *lineAmpl;		/* line amplitudes */
  float *linePhase;		/* line phase values */
  int *linePhaseValid;		/* line phase validity flag */
  int *lineValid;		/* validity flag */
  int *lineEnv;			/* line envelope flags */
  int *linePred;		/* line predecessor indices */
  int *numHarmLine;
  float *harmFreq;
  float *harmFreqStretch;
  int *harmLineIdx;
  int *harmEnv;
  int *harmPred;
  float *noisePara;

  /* pointers to variable content arrays */
  unsigned int *envParaIndex;
  int *lineParaPred;
  int *lineParaEnv;
  unsigned long *lineParaIndex;
  unsigned long *lineParaEnhaIndex;
  int *lineParaNumBit;
  int *lineContFlag;
  float *transAmpl;
  unsigned int *harmFreqIndex;
  unsigned int *harmFreqStretchIndex;
  unsigned int **harmAmplIndex;
  unsigned int *noiseParaIndex;
  unsigned int *harmEnhaIndex;
  unsigned int *harmEnhaNumBit;

  int *prevCont;

  /* variables for frame-to-frame memory */
  int prevNumLine;

  int prevNumIndiLine;
  int prevNumAllLine;
  float *prevLineFreq;
  float *prevLineAmpl;
  int *prevLineValid;		/* validity flag */
  int prevNumHarm;
  int *prevNumHarmLine;
  int *prevHarmLineIdx;

};


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


/* GenILDconfig() */
/* Generate default ILDconfig. */

static ILDconfig *GenILDconfig ()
{
  ILDconfig *cfg;

  if ((cfg = (ILDconfig*)malloc(sizeof(ILDconfig)))==NULL)
    IndiLineExit("GenILDconfig: memory allocation error");
  cfg->contModeTest = -1;
  cfg->bsFormat = 2;
  cfg->noStretch = 0;
  cfg->contdf = 1.05;
  cfg->contda = 4.0;
  return cfg;
}


/* InvTransfHarmAmpl() */
/* Inv. Transform  harm. amplitudes from freq. dependent averaging */

static int InvTransfHarmAmpl (
  int numTrans,
  float *transAmpl,
  float *recAmpl)
{
#define MAXGRP 7
#define MAXNUMAMPL 256

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

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


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

/* IndiLineDecodeInit() */
/* Init individual lines bitstream decoder. */

ILDstatus *IndiLineDecodeInit (
  BsBitStream *hdrStream,	/* in: bit stream header */
  float maxLineAmpl,		/* in: max line amplitude */
  int initPrevNumLine,		/* in: number ind. lines in prev. frame */
  ILDconfig *cfg,		/* in: ILD configuration */
				/*     or NULL */
  int debugLevel,		/* in: debug level (0=off) */
  int *maxNumLine,		/* out: max num lines in bitstream */
  int *maxNumEnv,		/* out: max num envelopes */
  int *maxNumHarm,		/* out: max num harmonic tones */
  int *maxNumHarmLine,		/* out: max num lines of harmonic tone */
  int *maxNumNoisePara,		/* out: max num noise parameters */
  int *maxNumAllLine,		/* out: max num harm+indi lines */
  int *enhaFlag,		/* out: enha flag (0=basic 1=enha) */
  int *frameLenQuant,		/* out: samples per frame */
				/*      used for quantiser selection */
  float *fSampleQuant)		/* out: sampling frequency */
				/*      used for quantiser selection */
				/* returns: ILD status handle */
{
  ILDstatus *ILD;
  long hdrFSample;
  int hdrFrameNumSample;
  int hdrFrameLengthBase;
  int hdrFrameLength;
  int i;

  if ((ILD = (ILDstatus*)malloc(sizeof(ILDstatus)))==NULL)
    IndiLineExit("IndiLineDecodeInit: memory allocation error");

  ILD->cfg = GenILDconfig();
  if (cfg != NULL)
    memcpy(ILD->cfg,cfg,sizeof(ILDconfig));

  ILD->debugLevel = debugLevel;

  /* get header info bits from header */
  if (ILD->cfg->bsFormat < 2) {
    /* old header */
    if (BsGetBitInt(hdrStream,(unsigned int*)&ILD->maxNumLine,16) ||
	BsGetBit(hdrStream,(unsigned long*)&hdrFSample,32) ||
	BsGetBitInt(hdrStream,(unsigned int*)&hdrFrameNumSample,16))
      IndiLineExit("IndiLineDecodeInit: error reading bit stream header");
  }
  else {
    /* CD header */
    if (BsGetBitInt(hdrStream,(unsigned int*)&ILD->quantMode,3))
      IndiLineExit("IndiLineDecodeInit: error reading bit stream header");
    if (BsGetBitInt(hdrStream,(unsigned int*)&ILD->maxNumLine,8))
      IndiLineExit("IndiLineDecodeInit: error reading bit stream header");
    if (BsGetBitInt(hdrStream,(unsigned int*)&hdrFrameLengthBase,1))
      IndiLineExit("IndiLineDecodeInit: error reading bit stream header");
    if (BsGetBitInt(hdrStream,(unsigned int*)&hdrFrameLength,12))
      IndiLineExit("IndiLineDecodeInit: error reading bit stream header");
    if (BsGetBitInt(hdrStream,(unsigned int*)&ILD->contMode,2))
      IndiLineExit("IndiLineDecodeInit: error reading bit stream header");
    if (BsGetBitInt(hdrStream,(unsigned int*)&ILD->enhaFlag,1))
      IndiLineExit("IndiLineDecodeInit: error reading bit stream header");
    if (ILD->enhaFlag) {
      if (BsGetBitInt(hdrStream,(unsigned int*)&ILD->enhaQuantMode,2))
	IndiLineExit("IndiLineDecodeInit: error reading bit stream header");
    }
    else
      ILD->enhaQuantMode = 0;
    hdrFSample = hdrFrameLengthBase ? 44100 : 48000;
    hdrFrameNumSample = hdrFrameLength;
  }

  ILD->fSample = hdrFSample;	/* to be used by noise */

  ILD->maxNumEnv = 2;
  ILD->maxNumHarm = 1;
  ILD->maxNumHarmLine = 256;
  ILD->maxNumNoisePara = 256;

  /* calc num bits required for numLine in bitstream */
  ILD->numLineNumBit = 0;
  while (1<<ILD->numLineNumBit <= ILD->maxNumLine)
    ILD->numLineNumBit++;
  
  if (ILD->cfg->contModeTest != -1)
    ILD->contMode = ILD->cfg->contModeTest;

  if (ILD->cfg->bsFormat < 2) {
    if (hdrFSample <= 8000)
      ILD->quantMode = 0;
    else if (hdrFSample <= 16000)
      ILD->quantMode = -1;
    else
      ILD->quantMode = 2;
    ILD->ILQ = IndiLineQuantInit(ILD->quantMode,0,maxLineAmpl,
				 ILD->maxNumLine,0,debugLevel);
  }
  else
    ILD->ILQ = IndiLineQuantInit(ILD->quantMode,ILD->enhaQuantMode,maxLineAmpl,
				 ILD->maxNumLine,0,debugLevel);
  /*
    ILD->ILQ = IndiLineQuantInit(hdrFrameNumSample,(float)hdrFSample,maxLineAmpl,
    ILD->maxNumLine,0,debugLevel);
    */
  switch (ILD->quantMode) {
  case 0:
  case 1:
    ILD->maxNoiseFreq = 4000.;
    break;
  case 2:
  case 3:
    ILD->maxNoiseFreq = 8000.;
    break;
  case 4:
  case 5:
    ILD->maxNoiseFreq = 20000.;
    break;
  }
  
  IndiLineNumBit(ILD->ILQ,&ILD->envNumBit,&ILD->newLineNumBit,
		 &ILD->contLineNumBit);

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

  ILD->maxNumAllLine = ILD->maxNumLine+ILD->maxNumHarm*ILD->maxNumHarmLine;

  if (
      /* return values */
      (ILD->envPara=(float**)malloc(ILD->maxNumEnv*sizeof(float*)))==NULL ||
      (ILD->envPara[0]=(float*)malloc(ILD->maxNumEnv*ENVPARANUM*
				      sizeof(float)))==NULL ||
      (ILD->lineFreq=(float*)malloc(ILD->maxNumAllLine*sizeof(float)))==NULL ||
      (ILD->lineAmpl=(float*)malloc(ILD->maxNumAllLine*sizeof(float)))==NULL ||
      (ILD->lineValid=(int*)malloc(ILD->maxNumAllLine*
				       sizeof(float)))==NULL ||
      (ILD->linePhase=(float*)malloc(ILD->maxNumAllLine*
				     sizeof(float)))==NULL ||
      (ILD->linePhaseValid=(int*)malloc(ILD->maxNumAllLine*
				     sizeof(int)))==NULL ||
      (ILD->lineEnv=(int*)malloc(ILD->maxNumAllLine*sizeof(int)))==NULL ||
      (ILD->linePred=(int*)malloc(ILD->maxNumAllLine*sizeof(int)))==NULL ||
      (ILD->numHarmLine=(int*)malloc(ILD->maxNumHarm*sizeof(int)))==NULL ||
      (ILD->harmFreq=(float*)malloc(ILD->maxNumHarm*sizeof(float)))==NULL ||
      (ILD->harmFreqStretch=(float*)malloc(ILD->maxNumHarm*
					   sizeof(float)))==NULL ||
      (ILD->harmLineIdx=(int*)malloc(ILD->maxNumHarm*sizeof(int)))==NULL ||
      (ILD->harmEnv=(int*)malloc(ILD->maxNumHarm*sizeof(int)))==NULL ||
      (ILD->harmPred=(int*)malloc(ILD->maxNumHarm*sizeof(int)))==NULL ||
      (ILD->noisePara=(float*)malloc(ILD->maxNumNoisePara*
				     sizeof(float)))==NULL ||
      /* variable content arrays */
      (ILD->envParaIndex=(unsigned int*)malloc(ILD->maxNumEnv*
					       sizeof(unsigned int)))==NULL ||
      (ILD->lineParaPred=(int*)malloc(ILD->maxNumLine*sizeof(int)))==NULL ||
      (ILD->lineParaEnv=(int*)malloc(ILD->maxNumLine*sizeof(int)))==NULL ||
      (ILD->lineParaIndex=(unsigned long*)malloc(ILD->maxNumLine*
					       sizeof(unsigned long)))==NULL ||
      (ILD->lineParaEnhaIndex=(unsigned long*)malloc(ILD->maxNumLine*
					       sizeof(unsigned long)))==NULL ||
      (ILD->lineParaNumBit=(int*)malloc(ILD->maxNumLine*sizeof(int)))==NULL ||
      (ILD->lineContFlag=(int*)malloc(ILD->maxNumLine*sizeof(int)))==NULL ||
      (ILD->transAmpl=(float*)malloc(ILD->maxNumHarmLine*
				     sizeof(float)))==NULL ||
      (ILD->harmFreqIndex=(unsigned int*)malloc(ILD->maxNumHarm*
						sizeof(unsigned int)))==NULL ||
      (ILD->harmFreqStretchIndex=(unsigned int*)malloc(ILD->maxNumHarm*
					        sizeof(unsigned int)))==NULL ||
      (ILD->harmAmplIndex=(unsigned int**)malloc(ILD->maxNumHarm*
					       sizeof(unsigned int*)))==NULL ||
      (ILD->harmAmplIndex[0]=(unsigned int*)malloc(ILD->maxNumHarm*
						   ILD->maxNumHarmLine*
						sizeof(unsigned int)))==NULL ||
      (ILD->noiseParaIndex=(unsigned int*)malloc(ILD->maxNumNoisePara*
						sizeof(unsigned int)))==NULL ||
      (ILD->harmEnhaIndex=(unsigned int*)malloc(ILD->maxNumHarmLine*
						sizeof(unsigned int)))==NULL ||
      (ILD->harmEnhaNumBit=(unsigned int*)malloc(ILD->maxNumHarmLine*
						sizeof(unsigned int)))==NULL ||
      (ILD->prevCont=(int*)malloc(ILD->maxNumAllLine*sizeof(int)))==NULL ||
      /* frame-to-frame memory */
      (ILD->prevLineFreq=(float*)malloc(ILD->maxNumAllLine*
					sizeof(float)))==NULL ||
      (ILD->prevLineAmpl=(float*)malloc(ILD->maxNumAllLine*
					sizeof(float)))==NULL ||
      (ILD->prevLineValid=(int*)malloc(ILD->maxNumAllLine*
					sizeof(float)))==NULL ||
      (ILD->prevNumHarmLine=(int*)malloc(ILD->maxNumHarm*
					 sizeof(int)))==NULL ||
      (ILD->prevHarmLineIdx=(int*)malloc(ILD->maxNumHarm*
					 sizeof(int)))==NULL)
    IndiLineExit("IndiLineDecodeInit: memory allocation error");

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

  /* clear frame-to-frame memory */
  ILD->prevNumLine = initPrevNumLine;
  for(i=0;i<initPrevNumLine;i++)
    ILD->prevLineValid[i] = 0;	/* no parameters available for cont. */
  ILD->prevNumIndiLine = 0;
  ILD->prevNumAllLine = 0;
  ILD->prevNumHarm = 0;

  *maxNumLine = ILD->maxNumLine;
  *maxNumEnv = ILD->maxNumEnv;
  *maxNumHarm = ILD->maxNumHarm;
  *maxNumHarmLine = ILD->maxNumHarmLine;
  *maxNumNoisePara = ILD->maxNumNoisePara;
  *maxNumAllLine = ILD->maxNumAllLine;
  *enhaFlag = ILD->enhaFlag;

  *frameLenQuant = hdrFrameNumSample;
  *fSampleQuant = hdrFSample;

  return ILD;
}


/* IndiLineDecodeFrame() */
/* Decode individual lines frame to bitstream. */

void IndiLineDecodeFrame (
  ILDstatus *ILD,		/* in: ILD status handle */
  BsBitStream *stream,		/* in: bit stream */
  BsBitStream *streamEnha,	/* in: enhancement bit stream */
				/*     or NULL for basic mode */
  int *numEnv,			/* out: num envelopes */
  float ***envPara,		/* out: envelope parameters */
				/*      [0..numEnv-1][0..ENVPARANUM-1] */
  int *numLine,			/* out: num lines */
  float **lineFreq,		/* out: line frequencies */
				/*      [0..numLine-1] */
  float **lineAmpl,		/* out: line amplitudes */
				/*      [0..numLine-1] */
  float **linePhase,		/* out: line phases */
				/*      [0..numLine-1] */
				/*      (not used in basic mode) */
  int **linePhaseValid,		/* out: line phases validity flag */
				/*      [0..numLine-1] */
				/*      (not used in basic mode) */
  int **lineEnv,		/* out: line envelope flags */
				/*      [0..numLine-1] */
  int **linePred,		/* out: line predecessor indices */
				/*      [0..numLine-1] */
  int *numHarm,			/* out: num harmonic tones */
  int **numHarmLine,		/* out: num lines of harmonic tone */
				/*      [0..numHarm-1] */
  float **harmFreq,		/* out: harm fundamental frequency [Hz] */
				/*      [0..numHarm-1] */
  float **harmFreqStretch,	/* out: harm freq stretching */
				/*      [0..numHarm-1] */
  int **harmLineIdx,		/* out: harm line para start idx */
				/*      [0..numHarm-1] */
				/*      ampl: lineAmpl[idx] etc. */
				/*      idx=harmLineIdx+ */
				/*          (0..numHarmLine-1) */
  int **harmEnv,		/* out: harm envelope flag/idx */
				/*      [0..numHarm-1] */
  int **harmPred,		/* out: harm tone predecessor idx */
				/*      [0..numHarm-1] */
  int *numNoisePara,		/* out: num noise parameter */
  float *noiseFreq,		/* out: max noise freq (bandwidth) [Hz] */
  float **noisePara,		/* out: noise parameter (DCT) */
				/*      [0..numNoisePara-1] */
  int *noiseEnv)		/* out: noise envelope flag/idx */
{
  int i,il;
  int contNumLine;
  int envParaFlag;
  int envParaNumBit;
  int envParaEnhaNumBit;
  int *lineParaEnhaNumBit;
  unsigned int envParaEnhaIndex;

  float *tmpLineFreq,*tmpLineAmpl;
  float *tmpLineFreqEnha,*tmpLineAmplEnha,*tmpLinePhaseEnha;
  int *tmpLineEnv,*tmpLinePred;
  float *tmpEnvPara,*tmpEnvParaEnha;

  int numTrans,amplInt,addHarmAmplBits,harmAmplMax,harmAmplOff;

  unsigned int noiseNormIndex;
  float noiseNorm;

  int fNumBitE,fNumBitBase,freqNumStepE,fintE,pintE;

  /* get numLine from bitstream */
  if (BsGetBitInt(stream,(unsigned int*)numLine,ILD->numLineNumBit))
    IndiLineExit("IndiLineDecodeFrame: error reading bit stream (numLine)");

  /* get envelope parameters from bitstream */
  if (BsGetBitInt(stream,(unsigned int*)&envParaFlag,1))
    IndiLineExit("IndiLineDecodeFrame: error reading bit stream (envFlag)");
  if (envParaFlag) {
    envParaNumBit = ILD->envNumBit;
    if (BsGetBitInt(stream,&ILD->envParaIndex[0],envParaNumBit))
      IndiLineExit("IndiLineDecodeFrame: error reading bit stream (envPara)");
  }
  else
    envParaNumBit = 0;
  *numEnv = 1;

  if(ILD->prevNumLine != PNL_UNKNOWN) {

    /* get continue bits from bitstream */
    for (il=0; il<ILD->prevNumLine; il++) {
      if (BsGetBitInt(stream,(unsigned int*)&ILD->lineContFlag[il],1))
	IndiLineExit("IndiLineDecodeFrame: error reading bit stream "
		     "(contFlag %d)",il);
    }

    if (ILD->cfg->bsFormat==0) {
      numTrans=0;
      *numHarm=0;
      *numNoisePara=0;
    }
    else {

      /* harmonic stuff */
      if (BsGetBitInt(stream,(unsigned int*)&numTrans,1))
	IndiLineExit("IndiLineDecodeFrame: error reading bit stream (harm)");
      *numHarm = 0;
      if (numTrans) {
	if (BsGetBitInt(stream,(unsigned int*)&numTrans,6))
	  IndiLineExit("IndiLineDecodeFrame: error reading bit stream (harm n)");
	numTrans++;
	if (BsGetBitInt(stream,(unsigned int*)&addHarmAmplBits,1))
	  IndiLineExit("IndiLineDecodeFrame: error reading bit stream (harm add)");
	if (BsGetBitInt(stream,(unsigned int*)&ILD->harmPred[*numHarm],1))
	  IndiLineExit("IndiLineDecodeFrame: error reading bit stream (harm c)");
	if (BsGetBitInt(stream,(unsigned int*)&ILD->harmEnv[*numHarm],1))
	  IndiLineExit("IndiLineDecodeFrame: error reading bit stream (harm e)");
	if (envParaFlag==0 && ILD->harmEnv[*numHarm]==1)
	  IndiLineExit("IndiLineDecodeFrame: harm - no env paras available");
	if (envParaFlag==0 && ILD->harmEnv[*numHarm]==1)
	  harmEnv = 0;
	if (BsGetBitInt(stream,&ILD->harmFreqIndex[*numHarm],11))
	  IndiLineExit("IndiLineDecodeFrame: error reading bit stream (harm f)");
	if (BsGetBitInt(stream,&ILD->harmFreqStretchIndex[*numHarm],5))
	  IndiLineExit("IndiLineDecodeFrame: error reading bit stream (harm fs)");
	if (BsGetBitInt(stream,&ILD->harmAmplIndex[*numHarm][0],6))
	  IndiLineExit("IndiLineDecodeFrame: error reading bit stream (harm ta0)");
	for (il=1; il<numTrans; il++)
	  if (BsGetBitInt(stream,&ILD->harmAmplIndex[*numHarm][il],4+addHarmAmplBits))
	    IndiLineExit("IndiLineDecodeFrame: error reading bit stream (harm ta%d)",il);
	(*numHarm)++;
      }

      /* noise stuff */
      if (BsGetBitInt(stream,(unsigned int*)numNoisePara,1))
	IndiLineExit("IndiLineDecodeFrame: error reading bit stream (noise)");
      if (*numNoisePara) {
	if (BsGetBitInt(stream,(unsigned int*)numNoisePara,2))
	  IndiLineExit("IndiLineDecodeFrame: error reading bit stream (noise n)");
	*numNoisePara += 4;
	if (BsGetBitInt(stream,(unsigned int*)noiseEnv,1))
	  IndiLineExit("IndiLineDecodeFrame: error reading bit stream (noise e)");
	if (BsGetBitInt(stream,&noiseNormIndex,6))
	  IndiLineExit("IndiLineDecodeFrame: error reading bit stream (noise p0)");
	for (i=0; i<*numNoisePara; i++)
	  if (BsGetBitInt(stream,ILD->noiseParaIndex+i,3))
	    IndiLineExit("IndiLineDecodeFrame: error reading bit stream (noise p%d)",i);
	if(*noiseEnv) {
	  if (BsGetBitInt(stream,&ILD->envParaIndex[*numEnv],ILD->envNumBit))
	    IndiLineExit("IndiLineDecodeFrame: error reading bit stream (noise env)",i);
	  (*numEnv)++;
	}
      }
    }

    /* evaluate continue bits */
    contNumLine = 0;
    for (il=0; il<ILD->prevNumLine; il++)
      if (ILD->lineContFlag[il]) {
	ILD->lineValid[contNumLine] = ILD->prevLineValid[il];
	ILD->lineParaPred[contNumLine++] = il+1;
      }
    for (il=contNumLine; il<*numLine; il++) {
      ILD->lineValid[il] = 1;      
      ILD->lineParaPred[il] = 0;
    }

    if (ILD->debugLevel >= 3) {
      printf("cont: ");
      for (il=0; il<ILD->prevNumLine; il++)
	printf("%1d",ILD->lineContFlag[il]);
      printf("\n");
    }

    if (ILD->debugLevel >= 2)
      printf("IndiLineDecodeFrame: "
	     "numLine=%d  contNumLine=%d  envParaFlag=%d\n",
	     *numLine,contNumLine,envParaFlag);

    /* get line parameters from bitstream */
    for (il=0; il<*numLine; il++) {
      if (envParaFlag) {
	if (BsGetBitInt(stream,(unsigned int*)&ILD->lineParaEnv[il],1))
	  IndiLineExit("IndiLineDecodeFrame: error reading bit stream "
		       "(lineEnv %d)",il);
      }
      else
	ILD->lineParaEnv[il] = 0;
      if (ILD->lineParaPred[il])
	ILD->lineParaNumBit[il] = ILD->contLineNumBit;
      else
	ILD->lineParaNumBit[il] = ILD->newLineNumBit;
      if (BsGetBit(stream,&ILD->lineParaIndex[il],ILD->lineParaNumBit[il]))
	IndiLineExit("IndiLineDecodeFrame: error reading bit stream "
		     "(linePara %d)",il);
    }

    /* get enhancement parameters from bit stream */
    if (streamEnha) {
      IndiLineEnhaNumBit(ILD->ILQ,
			 envParaFlag,ILD->envParaIndex[0],envParaNumBit,
			 *numLine,NULL,ILD->lineParaPred,
			 (unsigned int*)ILD->lineParaIndex,ILD->lineParaNumBit,
			 &envParaEnhaNumBit,&lineParaEnhaNumBit);
      /* envelope */
      if (envParaFlag)
	if (BsGetBitInt(streamEnha,&envParaEnhaIndex,envParaEnhaNumBit))
	  IndiLineExit("IndiLineDecodeFrame: error reading bit stream "
		       "(envParaEnha)");
      /* harm */

      fNumBitBase = 0;
      while (numTrans && fNumBitBase<HARM_MAX_FBASE &&
	     ILD->harmFreqIndex[0]>freqThrE[fNumBitBase])
	fNumBitBase++;
      if (fNumBitBase==HARM_MAX_FBASE)
	IndiLineExit("IndiLineDecodeFrame: fnumbite error, harmFreqIndex=%d",
		     ILD->harmFreqIndex[0]);
      fNumBitBase += max(0,min(3,ILD->enhaQuantMode))-3;
      for(i=0;i<min(10,numTrans);i++) {
	fNumBitE = max(0,fNumBitBase+fEnhaBitsHarm[i]);
	ILD->harmEnhaNumBit[i] = HARM_PHASE_NUMBIT+fNumBitE;
	if (BsGetBitInt(streamEnha,&ILD->harmEnhaIndex[i],
			ILD->harmEnhaNumBit[i]))
	  IndiLineExit("IndiLineDecodeFrame: error reading bit stream "
		       "(HarmEnha%d)",i);
      }

      /* indi lines */
      for (il=0; il<*numLine; il++)
	if (BsGetBit(streamEnha,&ILD->lineParaEnhaIndex[il],
		     lineParaEnhaNumBit[il]))
	  IndiLineExit("IndiLineDecodeFrame: error reading bit stream "
		       "(lineParaEnha %d)",il);
    }

    /* dequantise noise */
    if (*numNoisePara) {
      *noiseFreq = ILD->maxNoiseFreq;

      noiseNorm = exp((float)(noiseNormIndex+1)*log(2.)/2.)/8.;
      ILD->noisePara[0] = ((float)ILD->noiseParaIndex[0]+.5)*noiseNorm;
      if(ILD->debugLevel >= 2)
	printf("numNoisePara=%2d, env=%1d, Para=%6.1f",*numNoisePara,*noiseEnv,
	       ILD->noisePara[0]);
      for(i=1;i<*numNoisePara;i++) {
	ILD->noisePara[i] = ((float)ILD->noiseParaIndex[i]-4.+.5)*noiseNorm*2.;
	if(ILD->debugLevel >= 2)
	  printf("%6.1f",ILD->noisePara[i]);
      }
      if(ILD->debugLevel >= 2)
	printf("\n");
    
      /* dequantise noise envelope parameters */
      IndiLineEnvDequant(ILD->ILQ,*noiseEnv,ILD->envParaIndex[1],
			 ILD->envNumBit,0,0,&tmpEnvPara,NULL);
      for (i=0;i<ENVPARANUM;i++)
	ILD->envPara[1][i] = tmpEnvPara[i];
    }

    /* dequantise envelope parameters */
    /* !!! must come after dequant of noise env !!! */
    /* !!! must come directly before IndiLineDequant() !!! */
    IndiLineEnvDequant(ILD->ILQ,envParaFlag,ILD->envParaIndex[0],envParaNumBit,
		       (streamEnha)?envParaEnhaIndex:0,
		       (streamEnha)?envParaEnhaNumBit:0,
		       &tmpEnvPara,(streamEnha)?&tmpEnvParaEnha:NULL);
    for (i=0;i<ENVPARANUM;i++)
      ILD->envPara[0][i] = (streamEnha)?tmpEnvParaEnha[i]:tmpEnvPara[i];

    /* dequantise line parameters */
    IndiLineDequant(ILD->ILQ,*numLine,NULL,
		    ILD->lineParaPred,ILD->lineValid,ILD->lineParaEnv,
		    (unsigned int*)ILD->lineParaIndex,ILD->lineParaNumBit,
		    (streamEnha)?(unsigned int*)ILD->lineParaEnhaIndex:NULL,
		    (streamEnha)?lineParaEnhaNumBit:NULL,
		    &tmpLineFreq,&tmpLineAmpl,&tmpLineEnv,&tmpLinePred,
		    (streamEnha)?&tmpLineFreqEnha:NULL,
		    (streamEnha)?&tmpLineAmplEnha:NULL,
		    (streamEnha)?&tmpLinePhaseEnha:NULL);

    for (il=0;il<*numLine;il++) {
      ILD->lineFreq[il] = (streamEnha)?tmpLineFreqEnha[il]:tmpLineFreq[il];
      ILD->lineAmpl[il] = (streamEnha)?tmpLineAmplEnha[il]:tmpLineAmpl[il];
      if (streamEnha) {
	ILD->linePhase[il] = tmpLinePhaseEnha[il];
	ILD->linePhaseValid[il] = 1;
      }
      ILD->lineEnv[il] = tmpLineEnv[il];
      ILD->linePred[il] = tmpLinePred[il];
    }

    /* dequantise harm */
    if(numTrans) {

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

      ILD->harmFreq[0] = exp((ILD->harmFreqIndex[0]+.5)/2048.*log(4000./30.))*30.;
      ILD->harmFreqStretch[0] = (ILD->harmFreqStretchIndex[0]/32.-.5)*0.002;

      amplInt = ILD->harmAmplIndex[0][0];
      ILD->transAmpl[0] = ((float)amplInt+.5)/3.;
      for(i=1;i<numTrans;i++) {
	amplInt += ILD->harmAmplIndex[0][i]-harmAmplOff;
	ILD->transAmpl[i] = ((float)amplInt+.5)/3.;
      }

      for (i=0; i<numTrans; i++) {
	ILD->transAmpl[i] = exp(ILD->transAmpl[i]*log(2.));
      }
      ILD->harmLineIdx[0] = *numLine;
      ILD->numHarmLine[0] = InvTransfHarmAmpl(numTrans,ILD->transAmpl,
					      &ILD->lineAmpl[ILD->harmLineIdx[0]]);

      /* harm enhancement */
      if (streamEnha && linePhase) {
	for(i=0;i<min(10,numTrans);i++) {
	  fNumBitE = ILD->harmEnhaNumBit[i]-HARM_PHASE_NUMBIT;
	  if(fNumBitE>0) {
	    freqNumStepE = 1<<fNumBitE;
	    fintE = (ILD->harmEnhaIndex[i]>>HARM_PHASE_NUMBIT)
	      & (freqNumStepE-1);
	    ILD->lineFreq[ILD->harmLineIdx[0]+i] =
	      1+((fintE+.5)/freqNumStepE-.5)*(HFREQRELSTEP-1);
	  }
	  else
	    ILD->lineFreq[ILD->harmLineIdx[0]+i] = 1;

	  pintE = ILD->harmEnhaIndex[i] & (HARM_PHASE_NUMSTEP-1);
	  ILD->linePhase[ILD->harmLineIdx[0]+i] =
			((pintE+.5)/HARM_PHASE_NUMSTEP-.5)*HARM_PHASE_RANGE;
	  ILD->linePhaseValid[ILD->harmLineIdx[0]+i] = 1;
	  ILD->lineEnv[ILD->harmLineIdx[0]+i] = 0;
	  ILD->linePred[ILD->harmLineIdx[0]+i] = 0;
	}
	for(i=ILD->harmLineIdx[0]+min(10,numTrans);
	    i<ILD->harmLineIdx[0]+ILD->numHarmLine[0];i++) {
	  ILD->lineFreq[i] = 1;
	  ILD->linePhase[i] = 0;
	  ILD->linePhaseValid[i] = 0;
	  ILD->lineEnv[i] = 0;
	  ILD->linePred[i] = 0;
	  /* ILD->lineAmpl[i] = 0; */
	}
      }
      else {  
	/* HP 970709 */
	for (i=ILD->harmLineIdx[0];
	     i<ILD->harmLineIdx[0]+ILD->numHarmLine[0]; i++) {
	  ILD->lineFreq[i] = 0;
	  ILD->linePhase[i] = 0;
	  ILD->linePhaseValid[i] = 0;
	  ILD->lineEnv[i] = 0;
	  ILD->linePred[i] = 0;
	}
      }

      if (ILD->debugLevel >= 2)
	printf("numTrans=%2d, numHarmLine=%3d\n",numTrans,ILD->numHarmLine[0]);

      if (ILD->debugLevel >= 2)
	printf("ILDecodeFrame: "
	       "harm n=%d  c=%d  f=%7.1f  fs=%8.1e  a1=%7.1f  a2=%7.1f\n",
	       ILD->numHarmLine[0],ILD->harmPred[0],ILD->harmFreq[0],
	       ILD->harmFreqStretch[0],
	       ILD->lineAmpl[ILD->harmLineIdx[0]],
	       ILD->lineAmpl[ILD->harmLineIdx[0]+1]);

    }
    else {
      ILD->numHarmLine[0] = 0;

      if(ILD->debugLevel>=2)
	printf("numTrans=0\n");
    }

    /* copy parameters into frame-to-frame memory */

    ILD->prevNumLine = *numLine;
    for(i=0;i<*numLine;i++)
      ILD->prevLineValid[i] = ILD->lineValid[i];
  }				/* if(ILD->prevNumLine != PNL_UNKNOWN) { */

  else {
    ILD->prevNumLine = *numLine;
    for(i=0;i<*numLine;i++)
      ILD->prevLineValid[i] = 0;
    *numLine = 0;
    *numHarm = 0;
    *numNoisePara = 0;
  }

  /* set pointers to arrays with return values */
  *envPara = ILD->envPara;
  *lineFreq = ILD->lineFreq;
  *lineAmpl = ILD->lineAmpl;
  if (linePhase) {
    *linePhase = ILD->linePhase;
    *linePhaseValid = ILD->linePhaseValid;
  }
  *lineEnv = ILD->lineEnv;
  *linePred = ILD->linePred;
  *numHarmLine = ILD->numHarmLine;
  *harmFreq = ILD->harmFreq;
  *harmFreqStretch = ILD->harmFreqStretch;
  *harmLineIdx = ILD->harmLineIdx;
  *harmEnv = ILD->harmEnv;
  *harmPred = ILD->harmPred;
  *noisePara = ILD->noisePara;
}


/* IndiLineDecodeHarm() */
/* Append harmonic lines and join with individual lines. */

void IndiLineDecodeHarm (
  ILDstatus *ILD,		/* in: ILD status handle */
  int numLine,			/* in: num lines */
  float *lineFreq,		/* in: line frequency */
				/*     [0..numLine-1] */
				/*     Note: values are MODIFIED !!! */
  float *lineAmpl,		/* in: line amplitude */
				/*     [0..numLine-1] */
				/*     Note: values are MODIFIED !!! */
  float *linePhase,		/* in: line phase */
				/*     [0..numLine-1] */
				/*     (required in enha mode) */
				/*     (NULL in basic mode) */
				/*     Note: values are MODIFIED !!! */
  int *linePhaseValid,		/* in: line phase validity flag */
				/*     [0..numLine-1] */
				/*     (required in enha mode) */
				/*     Note: values are MODIFIED !!! */
  int *lineEnv,			/* in: line envelope flag */
				/*     [0..numLine-1] */
				/*     Note: values are MODIFIED !!! */
  int *linePred,		/* in: line predecessor idx */
				/*     in prev frame */
				/*     [0..numLine-1] */
				/*     Note: values are MODIFIED !!! */
  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) */
				/*     Note: values are MODIFIED !!! */
  int *harmEnv,			/* in: harm envelope flag/idx */
				/*     [0..numHarm-1] */
  int *harmPred,		/* in: harm tone predecessor idx */
				/*     [0..numHarm-1] */
  int *numAllLine)		/* out: num harm+indi lines */
{
  int i,ih,il;
  int lineIdx;
  int optp;
  float df,da,q,optq;
  int numCont;
  int numHL;

  /* append harm to indilines */
  il = numLine;
  for (ih=0; ih<numHarm; ih++) {
    if (harmLineIdx[ih] < il)
      IndiLineExit("IndiLineDecodeHarm: harmLineIdx %d error",ih);
    lineIdx = il;
    numHL = numHarmLine[ih];
    if (linePhase)		/* enha mode */
      numHL = min(10,numHL);	/* !!!!! */
    for (i=0; i<numHarmLine[ih]; i++) {

      if (linePhase && ILD->debugLevel>=4 && i<min(numHarmLine[ih],10))
	printf("HarmEnha: fq=%7.2f, fe=%7.2f, pq=%5.2f\n",
	       harmFreq[ih]*(i+1)*
	       (1+(1-ILD->cfg->noStretch)*harmFreqStretch[ih]*(i+1)),
	       lineFreq[harmLineIdx[ih]+i]*harmFreq[ih]*(i+1)*
	       (1+(1-ILD->cfg->noStretch)*harmFreqStretch[ih]*(i+1)),
	       linePhase[harmLineIdx[ih]+i]);

      if(!linePhase)
	lineFreq[il] = harmFreq[ih]*(i+1)*
	  (1+(1-ILD->cfg->noStretch)*harmFreqStretch[ih]*(i+1));
      else
	lineFreq[il] = lineFreq[harmLineIdx[ih]+i]*harmFreq[ih]*(i+1)*
	  (1+(1-ILD->cfg->noStretch)*harmFreqStretch[ih]*(i+1));

      lineAmpl[il] = lineAmpl[harmLineIdx[ih]+i];
      if (linePhase) {
	linePhase[il] = linePhase[harmLineIdx[ih]+i];
	linePhaseValid[il] = linePhaseValid[harmLineIdx[ih]+i];
      }

      lineEnv[il] = harmEnv[ih];
      linePred[il] = 0;
      if (harmPred[ih] && harmPred[ih]-1<ILD->prevNumHarm &&
	  i<ILD->prevNumHarmLine[harmPred[ih]-1])
	linePred[il] = ILD->prevHarmLineIdx[harmPred[ih]-1]+i+1;
      il++;
    }
    harmLineIdx[ih] = lineIdx;
  }
  *numAllLine = il;

  numCont = 0;
  /* continue harm <-> indi lines */
  if (ILD->cfg->contda>1 && ILD->cfg->contdf>1) {
    for (i=0; i<ILD->prevNumAllLine; i++)
      ILD->prevCont[i] = 0;
    for (il=0; il<*numAllLine; il++)
      if (linePred[il])
	ILD->prevCont[linePred[il]-1] = 1;
    for (il=0; il<*numAllLine; il++)
      if (!linePred[il]) {
	optp = 0;
	optq = 0;
	for (i=0; i<ILD->prevNumAllLine; i++)
	  if (!ILD->prevCont[i] && (ILD->contMode ||
				    i>=ILD->prevNumIndiLine ||
				    il>=numLine)) {
	    da = lineAmpl[il]/ILD->prevLineAmpl[i];
	    df = lineFreq[il]/ILD->prevLineFreq[i];
	    da = max(da,1/da);
	    df = max(df,1/df);
	    q = (1.-(df-1.)/(ILD->cfg->contdf-1.))*
	      (1.-(da-1.)/(ILD->cfg->contda-1.));
	    if (da < ILD->cfg->contda && df < ILD->cfg->contdf && q > optq) {
	      optq = q;
	      optp = i+1;
	    }
	  }
	if (optp) {
	  linePred[il] = optp;
	  ILD->prevCont[optp-1] = 1;
	  numCont++;
	  if (ILD->debugLevel >= 3)
	    printf("add cont %2d -> %2d (optq=%9.3e)\n",
		   optp-1,il,optq);
	}
      }
  }
  if (ILD->debugLevel >= 1)
    printf("IndiLineDecodeHarm: numCont=%d\n",numCont);

  ILD->prevNumIndiLine = numLine;
  ILD->prevNumAllLine = *numAllLine;
  for (il=0; il<*numAllLine; il++) {
    ILD->prevLineFreq[il] = lineFreq[il];
    ILD->prevLineAmpl[il] = lineAmpl[il];
  }
  ILD->prevNumHarm = numHarm;
  for (i=0; i<numHarm; i++) {
    ILD->prevNumHarmLine[i] = numHarmLine[i];
    ILD->prevHarmLineIdx[i] = harmLineIdx[i];
  }
}


/* IndiLineDecodeFree() */
/* Free memory allocated by IndiLineDecodeInit(). */

void IndiLineDecodeFree (
  ILDstatus *ILD)		/* in: ILD status handle */
{
  IndiLineQuantFree(ILD->ILQ);

  free(ILD->envPara[0]);
  free(ILD->envPara);
  free(ILD->lineFreq);
  free(ILD->lineAmpl);
  free(ILD->lineValid);
  free(ILD->linePhase);
  free(ILD->linePhaseValid);
  free(ILD->lineEnv);
  free(ILD->linePred);
  free(ILD->numHarmLine);
  free(ILD->harmFreq);
  free(ILD->harmFreqStretch);
  free(ILD->harmLineIdx);
  free(ILD->harmEnv);
  free(ILD->harmPred);
  free(ILD->noisePara);
  free(ILD->envParaIndex);
  free(ILD->lineParaPred);
  free(ILD->lineParaEnv);
  free(ILD->lineParaIndex);
  free(ILD->lineParaEnhaIndex);
  free(ILD->lineParaNumBit);
  free(ILD->lineContFlag);
  free(ILD->transAmpl);
  free(ILD->harmFreqIndex);
  free(ILD->harmFreqStretchIndex);
  free(ILD->harmAmplIndex[0]);
  free(ILD->harmAmplIndex);
  free(ILD->noiseParaIndex);
  free(ILD->prevCont);
  free(ILD->prevLineFreq);
  free(ILD->prevLineAmpl);
  free(ILD->prevLineValid);
  free(ILD->prevNumHarmLine);
  free(ILD->prevHarmLineIdx);

  free(ILD);
}


/* end of indilinedec.c */
