/**********************************************************************
MPEG-4 Audio VM
Decoder core (parametric)



This software module was originally developed by

Heiko Purnhagen (University of Hannover / Deutsche Telekom Berkom)
Bernd Edler (University of Hannover / Deutsche Telekom Berkom)
Masayuki Nishiguchi, Kazuyuki Iijima, Jun Matsumoto (Sony Corporation)

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: dec_par.c

$Id: dec_par.c,v 1.26 1998/05/06 19:44:02 purnhage Exp $

Required modules:
common.o		common module
cmdline.o		command line module
bitstream.o		bits stream module
indilinedec.o		indiline bitstream decoder module
indilinesyn.o		indiline synthesiser module

Authors:
HP    Heiko Purnhagen, Uni Hannover <purnhage@tnt.uni-hannover.de>
BE    Bernd Edler, Uni Hannover <edler@tnt.uni-hannover.de>
MN    Masayuki Nishiguchi, Sony IPC <nishi@pcrd.sony.co.jp>

Changes:
18-jun-96   HP    first version (dummy)
25-jun-96   HP    implemented "individual spectral lines"
28-jun-96   HP    joined with HVXC code by Sony IPC
01-jul-96   HP    added HVXC header file, included modifications by IPC
15-aug-96   HP    added DecParInfo(), DecParFree()
                  adapted to new dec.h
26-aug-96   HP    CVS
03-sep-96   HP    added speed change & pitch change for "individual lines"
06-sep-96   HP    incorporated changes by Sony IPC for a new HVXC with
                  speed change & pitch change functionality
10-sep-96   BE
12-sep-96   HP    incorporated indiline modules as source code
26-sep-96   HP    adapted to new indiline module interfaces
26-sep-96   HP    incorporated changes by Sony IPC
15-nov-96   HP    adapted to new bitstream module
04-dec-96   HP    fix call to BsGetBitChar(), included ISO copyright
03-feb-97   HP    splitting enc/dec
06-jul-97   HP    switch/mix
17-jul-97   HP    HXVC delayNumSample
23-oct-97   HP    merged IL/HVXC switching
07-nov-97   MN    bug-fixes
11-nov-97   HP    added HVXC variable rate switches
12-nov-97   HP    fixed mixed HVXC/IL mode

VMIL stuff
10-apr-97   HP    harmonic stuff ...
22-apr-97   HP    noisy stuff ...
10-jun-97   HP    added para file support
23-jun-97   HP    ANSI-C para file fixes
24-jun-97   HP    adapted env/harm/noise interface
29-aug-97   HP    added random start phase
13-nov-97   HP    fixed harm speech change
16-nov-97   HP    adapted HILN decoder config header
16-dec-97   HP    noise para factor
30-mar-98   BE/HP initPrevNumLine
06-apr-98   HP    ILD/ILS config
**********************************************************************/

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

#include "common.h"		/* common module */
#include "cmdline.h"		/* command line module */
#include "bitstream.h"		/* bit stream module */

#include "indilinedec.h"	/* indiline bitstream decoder module */
#include "indilinesyn.h"	/* indiline synthesiser module */


#include "dec.h"		/* decoder cores */

#include "mp4_par.h"		/* parametric core common declarations */

#include "hvxc.h"		/* hvxcDec module */
#include "hvxcDec.h"		/* hvxcDec module */


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

#define PROGVER "parametric decoder core V5.0 12-nov-97"

#define SEPACHAR " ,="

#define MAXSAMPLE 32768		/* full scale sample value */

#define STRLEN 255


/* ---------- variables ---------- */

static float DPfSample;
static float DPbitRate;
static float DPspeedFact;
static float DPpitchFact;
static int DPmode;		/* enum MP4ModePar */
static int DPframeMaxNumSample;
static int DPdelayNumSample;

/* indiline handles */
static ILDstatus *ILD;
static ILSstatus *ILS;

/* command line module */

static int DPdelayMode;
static int DPdebugLevel;
static int DPdebugLevelIl;

/* HILN decoder control HP970514 */
static int DPnoIL;
static int DPnoHarm;
static int DPnoNoise;
static float DPnoiseParaFact;
static int DPenhaFlag;
static int DPinitPrevNumLine;

static ILDconfig ILDcfg;
static ILSconfig ILScfg;

static int DPtest;


static CmdLineSwitch switchList[] = {
  {"h",NULL,NULL,NULL,NULL,"print help"},
  {"dm",&DPdelayMode,"%i","0",NULL,"HVXC delay mode (0=short 1=long)"},
  {"dl",&DPdebugLevel,"%i","0",NULL,"debug level"},
  {"dli",&DPdebugLevelIl,"%i","0",NULL,"debug level individual lines"},
  {"noi",&DPnoIL,NULL,NULL,NULL,"disable indiline synthesis"},
  {"noh",&DPnoHarm,NULL,NULL,NULL,"disable harm synthesis"},
  {"non",&DPnoNoise,NULL,NULL,NULL,"disable noise synthesis"},
  {"npf",&DPnoiseParaFact,"%f","1.0",NULL,"noise para factor"},
  {"hie",&DPenhaFlag,"%d","0",NULL,
   "harm/indi enha flag\n"
   "(0=basic 1=enha 2=no-scalable-enha)"},
  {"pnl",&DPinitPrevNumLine,"%d","0",NULL,"initial number of prev. indilines\n"
  "(-1=unknown for start at arbitrary frame)"},
  {"hicm",&ILDcfg.contModeTest,"%d","-1",NULL,
   "harm/indi continue mode\n"
   "(-1=bitstream 0=hi, 1=hi&ii)"},
  {"bsf",&ILDcfg.bsFormat,"%d","2",NULL,
   "HILN bitstream format (0=VM 1=9705 2=CD)"},
  {"nos",&ILDcfg.noStretch,NULL,NULL,NULL,"disable stretching"},
  {"cdf",&ILDcfg.contdf,"%f","1.05",NULL,"line continuation df"},
  {"cda",&ILDcfg.contda,"%f","4.0",NULL,"line continuation da"},
  {"rsp",&ILScfg.rndPhase,"%d","1",NULL,
   "random startphase (0=sin(0) 1=sin(rnd))"},
  {"test",&DPtest,"%i","0",NULL,"for test only (1=hvxc 2=il)"},
  {NULL,NULL,NULL,NULL,NULL,NULL}
};

/* variables for HVXC */
int ipc_decMode = DEC4K;
int ipc_bitstreamMode = BM_CONSTANT;
int ipc_rateMode = 2;

/* switch/mix stuff */
static float *tmpSampleBuf;
static float *mixSampleBuf;
static int mixSampleBufSize = 0;
static BsBitBuffer *dmyBuf;
static int ILdelayNumSample = 0;
static int HVXdelayNumSample = 0;
static BsBitBuffer *tmpBSbuf;
static BsBitStream *tmpBSstream;

int ipc_decDelayMode = DM_SHORT;

/* HP/MN 971111   for pan_lspdec.c */
extern int ipc_lpc_DEC0K;



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


/* DecParInitIl() */
/* Init: individual lines */

static void DecParInitIl (
  BsBitStream *hdrStream)	/* in: header for bit stream */
{
  int frameLenQuant;
  float fSampleQuant;
  int maxNumLine;
  int maxNumEnv;
  int maxNumHarm;
  int maxNumHarmLine;
  int maxNumNoisePara;
  int maxNumAllLine;
  int enhaFlag;
  int i;
  BsBitStream *dmyStream;


  /* init modules */
  ILD = IndiLineDecodeInit(hdrStream,MAXSAMPLE,DPinitPrevNumLine,
			   &ILDcfg,DPdebugLevelIl,
			   &maxNumLine,&maxNumEnv,&maxNumHarm,
			   &maxNumHarmLine,&maxNumNoisePara,&maxNumAllLine,
			   &enhaFlag,&frameLenQuant,&fSampleQuant);

  DPframeMaxNumSample = (int)(frameLenQuant*DPfSample/fSampleQuant/
			      DPspeedFact+0.5);
  DPdelayNumSample = DPframeMaxNumSample/2;

  if (DPenhaFlag && !enhaFlag) {
    CommonWarning("DecParInitIl: no enhancement bitstream available");
    DPenhaFlag = 0;
  }

  ILS = IndiLineSynthInit(DPframeMaxNumSample,DPfSample,
			  maxNumAllLine,maxNumEnv,maxNumNoisePara,
			  &ILScfg,DPdebugLevelIl);


  if (DPdebugLevel >= 1) {
    printf("DecParInitIl: dbgLvlIl=%d\n",
	   DPdebugLevelIl);
    printf("DecParInitIl: maxNumLine=%d\n",
	   maxNumLine);
    printf("DecParInitIl: fSampleQuant=%f  frameLenQuant=%d\n",
	   fSampleQuant,frameLenQuant);
    printf("DecParInitIl: frmNumSmp=%d  dlyNumSmp=%d\n",
	   DPframeMaxNumSample,DPdelayNumSample);
  }
  dmyBuf=BsAllocBuffer(200);
  dmyStream=BsOpenBufferWrite(dmyBuf);
  for (i=0; i<200; i++)		/* make "silenence" bitstream */
    BsPutBit(dmyStream,0,1);
  BsClose(dmyStream);
}


/* DecParInitHvx() */
/* Init: harmonic vector exitation */

static void DecParInitHvx (
  BsBitStream *hdrStream)	/* in: header for bit stream */
{
  if (BsGetBitInt(hdrStream,(unsigned int*)&ipc_bitstreamMode,1))
    CommonExit(1,"DecParInitHvx: error reading bit stream header");
  if (BsGetBitInt(hdrStream,(unsigned int*)&ipc_rateMode,2))
    CommonExit(1,"DecParInitHvx: error reading bit stream header");

  DPframeMaxNumSample = 160 * (int) ceil(1.0 / DPspeedFact);
  if (ipc_decDelayMode == DM_LONG)	/* HP 971023 */
    DPdelayNumSample = 80;	/* 10 ms */
  else
    DPdelayNumSample = 60;	/* 7.5 ms */
  IPC_HVXCInitDec();
}


/* DecParFrameIl() */
/* Decode frame: individual lines */

void DecParFrameIl (
  BsBitStream *stream,		/* in: bit stream */
  float *sampleBuf,		/* out: frameNumSample audio samples */
  int *frameBufNumSample)	/* out: num samples in sampleBuf[] */
{
  int numEnv;
  float **envPara;
  int numLine;
  float *lineFreq;
  float *lineAmpl;
  float *linePhase;
  int *linePhaseValid;
  int *lineEnv;
  int *linePred;
  int numHarm;
  int *numHarmLine;
  float *harmFreq;
  float *harmFreqStretch;
  int *harmLineIdx;
  int *harmEnv;
  int *harmPred;
  int numNoisePara;
  float noiseFreq;
  float *noisePara;
  int noiseEnv;
  int numAllLine;

  int i,il;
  BsBitStream *dmyStream;

  /* call IndiLineDecodeFrame() to update internal frame-to-frame memory */
  dmyStream = BsOpenBufferRead(dmyBuf);
  IndiLineDecodeFrame(ILD,(stream)?stream:dmyStream,
		      (stream && DPenhaFlag)?stream:NULL,
		      &numEnv,&envPara,&numLine,&lineFreq,
		      &lineAmpl,(stream && DPenhaFlag)?&linePhase:NULL,
		      (stream && DPenhaFlag)?&linePhaseValid:NULL,
		      &lineEnv,&linePred,
		      &numHarm,&numHarmLine,&harmFreq,&harmFreqStretch,
		      &harmLineIdx,&harmEnv,&harmPred,
		      &numNoisePara,&noiseFreq,&noisePara,&noiseEnv);
  BsClose(dmyStream);


  if (DPdebugLevel >= 3) {
    printf("dequan\n");
    for (i=0; i<numEnv; i++)
      printf("env %d: tm=%7.5f atk=%7.5f dec=%7.5f\n",
	     i,envPara[i][0],envPara[i][1],envPara[i][2]);
    for(il=0; il<numLine; il++)
      printf("%2d: f=%7.1f a=%7.1f p=%5.2f e=%1d c=%2d\n",
	     il,lineFreq[il],lineAmpl[il],(DPenhaFlag)?linePhase[il]:0.0,
	     lineEnv[il],linePred[il]);
    for (i=0; i<numHarm; i++) {
      printf("harm %d: n=%2d f=%7.1f fs=%10e e=%1d c=%1d\n",
	     i,numHarmLine[i],harmFreq[i],harmFreqStretch[i],
	     harmEnv[i],harmPred[i]);
      for(il=harmLineIdx[i]; il<harmLineIdx[i]+numHarmLine[i]; il++)
	printf("h %2d: a=%7.1f\n",il-harmLineIdx[i]+1,lineAmpl[il]);
    }
    if (numNoisePara) {
      printf("noise: n=%d f=%7.1f e=%1d\n",
	     numNoisePara,noiseFreq,noiseEnv);
      for (i=0; i<numNoisePara; i++)
	printf("noise %d: p=%10e\n",i,noisePara[i]);
    }
  }

  if (DPnoIL)
    numLine = 0;
  if (DPnoHarm)
    numHarm = 0;
  if (DPnoNoise)
    numNoisePara = 0;

  /* enhanced mode synthesiser control */
  if (DPenhaFlag==1) {
    numNoisePara = 0;
    if (numHarm)
      numHarmLine[0] = min(numHarmLine[0],10);
  }

  /* append harm lines and join with individual lines */
  IndiLineDecodeHarm(ILD,numLine,lineFreq,lineAmpl,
		     (DPenhaFlag)?linePhase:NULL,
		     (DPenhaFlag)?linePhaseValid:NULL,
		     lineEnv,linePred,
		     numHarm,numHarmLine,harmFreq,harmFreqStretch,
		     harmLineIdx,harmEnv,harmPred,
		     &numAllLine);


  /* modify frequency if pitch change (only basic mode) */
  for (il=0; il<numAllLine; il++) {
    lineFreq[il] *= DPpitchFact;
    lineAmpl[il] *= 1;
  }
  if (numNoisePara)
    noiseFreq *= DPpitchFact;

  for (i=0; i<numNoisePara; i++)
    noisePara[i] *= DPnoiseParaFact;

  /* enhanced mode synthesiser control */
  if (DPenhaFlag==1)
    for (i=0; i<numAllLine; i++)
      linePred[i] = 0;

  /* synthesise using quantised parameters */
  IndiLineSynth(ILS,(DPenhaFlag)?1:0,
		DPframeMaxNumSample,
		numEnv,envPara,
		numAllLine,lineFreq,lineAmpl,
		(DPenhaFlag)?linePhase:NULL,
		(DPenhaFlag)?linePhaseValid:NULL,
		NULL,lineEnv,linePred,
		numNoisePara,noiseFreq,noisePara,noiseEnv,
		sampleBuf);

  *frameBufNumSample = DPframeMaxNumSample;
}


/* DecParFrameHvx() */
/* Decode frame: harmonic vector exitation */

void DecParFrameHvx (
  BsBitStream *stream,		/* in: bit stream */
  float *sampleBuf,		/* out: frameNumSample audio samples */
  int *frameBufNumSample)	/* out: num samples in sampleBuf[] */
{
    int	i, j;

    short	frmBuf[FRM];
    int		idVUV;
    float	mfdpch = 0.0;

    float	qLsp[LPCORDER];
    float	am[SAMPLE/2][3];
    float	qRes[FRM];

    int		dcfrm;

    static int		idVUV2[2];
    static int		bgnFlag2[2];
    static float	pch2[2], am2[2][SAMPLE / 2][3];
    static float	qLsp2[2][LPCORDER];
    static float	qRes2[2][FRM];

    static int		nbs = 0;
    static int		frm = 0;
    static int		fr0 = 0;

    static float	ratio = 1.0;
    static IdCelp	idCelp2[2] = {0, 0, 0, 0, 0, 0, 0, 0};
    static float	qLspQueue[4][LPCORDER];
    static float	targetP = 0.0;
    unsigned char	encBit[10];

    unsigned char	tmpIdVUV;
    unsigned char	tmpEncBit;

    /* HP 970706 970708 970709 */
    if (!stream){
      ipc_decMode = DEC0K; 
    }
    else if (!BsEof(stream,80-1)){  /* MN 971107 */
      ipc_decMode = DEC4K; 
    }
    else if (!BsEof(stream,80-6-1)){ /* MN 971107 */
      ipc_decMode = DEC3K;
    }
    else{
      ipc_decMode = DEC2K;
    }

    /* HP/MN 971111   for pan_lspdec.c */
    ipc_lpc_DEC0K = (ipc_decMode == DEC0K) ? 1 : 0;

    if (DPdebugLevel >= 2) {
      printf("DecParFrameHvx: stream=%s\n",stream?"valid":"NULL");
      printf("DecParFrameHvx: decMode=");
      switch (ipc_decMode) {
      case DEC0K : printf("DEC0K\n"); break;
      case DEC2K : printf("DEC2K\n"); break;
      case DEC3K : printf("DEC3K\n"); break;
      case DEC4K : printf("DEC4K\n"); break;
      default : printf("ERROR!!!\n");
      }
    }
    
    if(nbs == 0)
    {
	idVUV2[0] = idVUV2[1] = 0;
	bgnFlag2[0] = bgnFlag2[1] = 0;
	pch2[0] = pch2[1] = 0.0;
	
	
	for(i = 0; i < 4; i++)
	{
	    for(j = 0; j < P; j++)
	    {
		qLspQueue[i][j] = 0.5 / 11.0 * (j + 1);
	    }
	}
    }


    if(ipc_decMode == DEC4K || ipc_decMode == DEC3K)
	/* Modified on 07/04/97 by Y.Maeda */
    {
      for(j = 0; j < 9; j++)
        if(BsGetBitChar(stream, &encBit[j], 8))
	  CommonExit(1,"DecParFrameHvx: error reading bit stream");
      if (ipc_decMode == DEC4K) {
	if(BsGetBitChar(stream, &encBit[9], 8)) /* MN 971106 */
	  CommonExit(1,"DecParFrameHvx: error reading bit stream");
      }
      else {
	/* MN 971107 */
	if(BsGetBitChar(stream, &tmpEncBit, 8-6))
	  CommonExit(1,"DecParFrameHvx: error reading bit stream");
	encBit[9] = (tmpEncBit & 0x3) << 6;
      }
    }
    else if(ipc_decMode == DEC2K)
    {
      if(ipc_bitstreamMode == BM_VARIABLE)
      {
        if(BsGetBitChar(stream, &tmpIdVUV, 2))
          CommonExit(1,"DecParFrameHvx: error reading bit stream");

	encBit[0] = (tmpIdVUV << 6) & 0xc0;

	/* HP 971111 */
	if (DPdebugLevel >= 2)
	  printf("DecParFrameHVXC: tmpIdVUV=%d\n",
		 tmpIdVUV);

	switch(tmpIdVUV)
        {
        case 0:
	  if(BsGetBitChar(stream, &tmpEncBit, 6))
            CommonExit(1,"DecParFrameHvx: error reading bit stream");
	  encBit[0] |= (tmpEncBit & 0x3f);

          for(j = 1; j < 3; j++)
            if(BsGetBitChar(stream, &encBit[j], 8))
	      CommonExit(1,"DecParFrameHvx: error reading bit stream");

	  if(BsGetBitChar(stream, &tmpEncBit, 4))
            CommonExit(1,"DecParFrameHvx: error reading bit stream");
	  encBit[3] = (tmpEncBit & 0xf) << 4;
	  break;
	case 1:
	  /* no more */
	  break;
	case 2:
	case 3:
	  if(BsGetBitChar(stream, &tmpEncBit, 6))
            CommonExit(1,"DecParFrameHvx: error reading bit stream");
	  encBit[0] |= (tmpEncBit & 0x3f);

          for(j = 1; j < 5; j++)
            if(BsGetBitChar(stream, &encBit[j], 8))
	      CommonExit(1,"DecParFrameHvx: error reading bit stream");
	  break;
	}
      }
      else
      {
        for(j = 0; j < 5; j++)
          if(BsGetBitChar(stream, &encBit[j], 8))
	    CommonExit(1,"DecParFrameHvx: error reading bit stream");
      }
    }

    dcfrm = 0;

    if(ipc_bitstreamMode == BM_VARIABLE)
    {
         IPC_DecParams1stVR(encBit, 1.0 / DPpitchFact, idVUV2, bgnFlag2,
                            qLspQueue, pch2, am2, idCelp2);
    }
    else
    {
        IPC_DecParams1st(encBit, 1.0 / DPpitchFact, idVUV2, qLspQueue,
                         pch2, am2, idCelp2);
    }
/*
    IPC_DecParams1st(encBit, 1.0 / DPpitchFact, idVUV2, qLspQueue, pch2,
		     am2, idCelp2);
*/
    while(nbs == fr0)
    {
        if(ipc_bitstreamMode == BM_VARIABLE)
        {
            IPC_DecParams2ndVR(fr0 - 1, idVUV2, bgnFlag2, qLspQueue, idCelp2,
                               qLsp2, qRes2);
        }
        else
        {
            IPC_DecParams2nd(fr0 - 1, idVUV2, qLspQueue, idCelp2,
                             qLsp2, qRes2);
        }

/*
	IPC_DecParams2nd(fr0 - 1, idVUV2, qLspQueue, idCelp2, qLsp2,
			 qRes2);
*/

	IPC_InterpolateParams(ratio,
			      idVUV2,
			      qLsp2,
			      pch2,
			      am2,
			      qRes2,

			      &idVUV,
			      qLsp,
			      &mfdpch,
			      am,
			      qRes);
	    
	IPC_SynthSC(idVUV, qLsp, mfdpch, am, qRes, frmBuf);
	    
	for(i = 0; i < FRM; i++)
	{
	    sampleBuf[i + FRM * dcfrm] = (float) frmBuf[i];
	}
	frm++;
	targetP = (float) frm * DPspeedFact;
	fr0 = (int) ceil(targetP);
	ratio = targetP - (float) fr0 + 1;
	dcfrm++;
    }
    nbs++;

    *frameBufNumSample = dcfrm * FRM;
}


/* DecParFreeIl() */
/* Free memory: individual lines */

void DecParFreeIl ()
{
  IndiLineDecodeFree(ILD);
  IndiLineSynthFree(ILS);
}

/* DecParFreeHvx() */
/* Free memory: harmonic vector exitation */

void DecParFreeHvx ()
{
}


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


char *DecParInfo (
  FILE *helpStream)		/* in: print decPara help text to helpStream */
				/*     if helpStream not NULL */
				/* returns: core version string */
{
  if (helpStream != NULL) {
    fprintf(helpStream,
	    PROGVER "\n"
	    "decoder parameter string format:\n"
	    "  list of tokens (tokens separated by characters in \"%s\")\n",
	    SEPACHAR);
    CmdLineHelp(NULL,NULL,switchList,helpStream);
  }
  return PROGVER;
}


/* DecParInit() */
/* Init parametric decoder core. */

void DecParInit (
  int numChannel,		/* in: num audio channels */
  float fSample,		/* in: sampling frequency [Hz] */
  float bitRate,		/* in: total bit rate [bit/sec] */
  float speedFact,		/* in: speed change factor */
  float pitchFact,		/* in: pitch change factor */
  char *decPara,		/* in: decoder parameter string */
  BsBitBuffer *bitHeader,	/* in: header from bit stream */
  int *frameMaxNumSample,	/* out: max num samples per frame */
  int *delayNumSample)		/* out: decoder delay (num samples) */
{
  int parac;
  char **parav;
  int result;
  BsBitStream *hdrStream;
  char *paraMode;
  int i;

  /* evalute decoder parameter string */
  parav = CmdLineParseString(decPara,SEPACHAR,&parac);
  result = CmdLineEval(parac,parav,NULL,switchList,1,NULL);
  if (result) {
    if (result==1) {
      DecParInfo(stdout);
      exit (1);
    }
    else
      CommonExit(1,"decoder parameter string error");
  }


  if (DPdelayMode)
    ipc_decDelayMode = DM_LONG;
  else
    ipc_decDelayMode = DM_SHORT;

  if (DPdebugLevel >= 1) {
    printf("DecParInit: numChannel=%d  fSample=%f  bitRate=%f\n",
	   numChannel,fSample,bitRate);
    printf("DecParInit: speedFact=%f  pitchFact=%f\n",
	   speedFact,pitchFact);
    printf("DecParInit: decPara=\"%s\"\n",
	   decPara);
    printf("DecParInit: debugLevel=%d\n",
	   DPdebugLevel);
  }

  if (numChannel != 1)
    CommonExit(1,"DecParInit: audio data has more the one channel (%d)",
	       numChannel);

  CmdLineParseFree(parav);

  DPfSample = fSample;
  DPbitRate = bitRate;
  DPspeedFact = speedFact;
  DPpitchFact = pitchFact;

  hdrStream = BsOpenBufferRead(bitHeader);
  if (BsGetBitInt(hdrStream,(unsigned int*)&DPmode,2))
    CommonExit(1,"DecParInit: error reading bit stream header");

  if (DPmode<0 || DPmode>MODEPAR_NUM)
    CommonExit(1,"DecParInit: unknown parametric codec mode %d",DPmode);
  paraMode = MP4ModeParName[DPmode];

  if (DPdebugLevel >= 1)
    printf("DecParInit: modeInt=%d  mode=\"%s\"\n",DPmode,paraMode);

  switch (DPmode) {
  case MODEPAR_HVX:
    DecParInitHvx(hdrStream);
    break;
  case MODEPAR_IL:
    DecParInitIl(hdrStream);
    break;
  case MODEPAR_SWIT:
  case MODEPAR_MIX:
    if (speedFact != 1)
      CommonExit(-1,"DecParInit: "
		 "speed change in switch/mix mode not yet implemented");
    DecParInitHvx(hdrStream);
    HVXdelayNumSample = DPdelayNumSample;
    DecParInitIl(hdrStream);
    ILdelayNumSample = DPdelayNumSample;
    DPframeMaxNumSample = 320; /* 40 ms */
    DPdelayNumSample = max(HVXdelayNumSample,ILdelayNumSample);
    tmpBSbuf = BsAllocBuffer(80);
    break;
  }
  BsClose(hdrStream);

  *frameMaxNumSample = DPframeMaxNumSample;
  *delayNumSample = DPdelayNumSample;
  mixSampleBufSize = DPframeMaxNumSample+
    max(DPdelayNumSample-ILdelayNumSample,DPdelayNumSample-HVXdelayNumSample);

  if (CommonFreeAlloc((void**)&tmpSampleBuf,
		      *frameMaxNumSample*sizeof(float)) == NULL)
    CommonExit(1,"DecParInit: memory allocation error");
  if (CommonFreeAlloc((void**)&mixSampleBuf,
		      mixSampleBufSize*sizeof(float)) == NULL)
    CommonExit(1,"DecParInit: memory allocation error");
  for (i=0; i<mixSampleBufSize; i++)
    mixSampleBuf[i] = 0;

  if (DPdebugLevel >= 1) {
    printf("DecParInit: encDlyMode=%d  vrMode=%d  rateMode=%d\n",
	   ipc_decDelayMode,ipc_bitstreamMode,ipc_rateMode);
    printf("DecParInit: dly=%d  frm=%d  mixBuf=%d  ILdly=%d  HVXdly=%d\n",
	   DPframeMaxNumSample,DPdelayNumSample,
	   mixSampleBufSize,ILdelayNumSample,HVXdelayNumSample);
  }
}


/* DecParFrame() */
/* Decode one bit stream frame into one audio frame with */
/* parametric decoder core. */

void DecParFrame (
  BsBitBuffer *bitBuf,		/* in: bit stream frame */
  float **sampleBuf,		/* out: audio frame samples */
				/*     sampleBuf[numChannel][frameNumSample] */
  int *usedNumBit,		/* out: num bits used for this frame */
  int *frameBufNumSample)	/* out: num samples in sampleBuf[][] */
{
  BsBitStream *stream;
  unsigned int il_hvxc;
  int i;
  int hvxcFrame1;

  if (DPdebugLevel >= 1)
    printf("DecParFrame: availNum=%ld\n",BsBufferNumBit(bitBuf));

  stream = BsOpenBufferRead(bitBuf);
  switch (DPmode) {
  case MODEPAR_HVX:
    DecParFrameHvx(stream,sampleBuf[0],frameBufNumSample);
    break;
  case MODEPAR_IL:
    DecParFrameIl(stream,sampleBuf[0],frameBufNumSample);
    break;
  case MODEPAR_SWIT:
    BsGetBitInt(stream,&il_hvxc,1);
    if (DPdebugLevel >= 1)
      printf("switch: %s\n",(il_hvxc)?"il":"hvxc");
    if (il_hvxc) {
      /* HP 971023   swit mode: 2 HVXC frames / 40 ms */
      DecParFrameHvx(NULL,tmpSampleBuf,frameBufNumSample);
      DecParFrameHvx(NULL,tmpSampleBuf+160,frameBufNumSample);
      for (i=0; i<*frameBufNumSample*2; i++)
	mixSampleBuf[DPdelayNumSample-HVXdelayNumSample+i] += tmpSampleBuf[i];
      DecParFrameIl((DPtest==1)?NULL:stream,tmpSampleBuf,frameBufNumSample);
      for (i=0; i<*frameBufNumSample; i++)
	mixSampleBuf[DPdelayNumSample-ILdelayNumSample+i] += tmpSampleBuf[i];
    }
    else {
      /* HP 971023   swit mode: 2 HVXC frames / 40 ms */
      if (!BsEof(stream,40+80-1))
	hvxcFrame1 = 80;
      else
	hvxcFrame1 = 40;
      if (BsGetBuffer(stream,tmpBSbuf,hvxcFrame1))
	CommonExit(-1,"DecParInit: switch: hvxc 1st frame: bits missing");
      tmpBSstream = BsOpenBufferRead(tmpBSbuf);
      DecParFrameHvx((DPtest==2)?NULL:tmpBSstream,
		     tmpSampleBuf,frameBufNumSample);
      BsClose(tmpBSstream);
      DecParFrameHvx((DPtest==2)?NULL:stream,
		     tmpSampleBuf+160,frameBufNumSample);
      for (i=0; i<*frameBufNumSample*2; i++)
	mixSampleBuf[DPdelayNumSample-HVXdelayNumSample+i] += tmpSampleBuf[i];
      DecParFrameIl(NULL,tmpSampleBuf,frameBufNumSample);
      for (i=0; i<*frameBufNumSample; i++)
	mixSampleBuf[DPdelayNumSample-ILdelayNumSample+i] += tmpSampleBuf[i];
    }
    for (i=0; i<*frameBufNumSample; i++)
      sampleBuf[0][i] = mixSampleBuf[i];
    for (i=0; i<mixSampleBufSize-*frameBufNumSample; i++)
      mixSampleBuf[i] = mixSampleBuf[i+*frameBufNumSample];
    for (i=0; i<*frameBufNumSample; i++)
      mixSampleBuf[i+mixSampleBufSize-*frameBufNumSample] = 0;
    break;
  case MODEPAR_MIX:
    BsGetBitInt(stream,&il_hvxc,2);
    if (DPdebugLevel >= 1)
      switch (il_hvxc) {
      case 0: printf("mix: hvxc\n"); break;
      case 1: printf("mix: hvxc2 + il\n"); break;
      case 2: printf("mix: hvxc4 + il\n"); break;
      case 3: printf("mix: il\n"); break;
      }
    switch (il_hvxc) {
    case 0:
      if (!BsEof(stream,40+80-1))
	hvxcFrame1 = 80;
      else
	hvxcFrame1 = 40;
      if (BsGetBuffer(stream,tmpBSbuf,hvxcFrame1))
	CommonExit(-1,"DecParInit: mix: hvxc 1st frame: bits missing");
      tmpBSstream = BsOpenBufferRead(tmpBSbuf);
      DecParFrameHvx((DPtest==2)?NULL:tmpBSstream,
		     tmpSampleBuf,frameBufNumSample);
      BsClose(tmpBSstream);
      DecParFrameHvx((DPtest==2)?NULL:stream,
		     tmpSampleBuf+160,frameBufNumSample);
      for (i=0; i<*frameBufNumSample*2; i++)
	mixSampleBuf[DPdelayNumSample-HVXdelayNumSample+i] += tmpSampleBuf[i];
      break;
    case 1:
      if (BsGetBuffer(stream,tmpBSbuf,40))
	CommonExit(-1,"DecParInit: mix: hvxc 1st frame: bits missing");
      tmpBSstream = BsOpenBufferRead(tmpBSbuf);
      DecParFrameHvx((DPtest==2)?NULL:tmpBSstream,
		     tmpSampleBuf,frameBufNumSample);
      BsClose(tmpBSstream);
      if (BsGetBuffer(stream,tmpBSbuf,40))
	CommonExit(-1,"DecParInit: mix: hvxc 2st frame: bits missing");
      tmpBSstream = BsOpenBufferRead(tmpBSbuf);
      DecParFrameHvx((DPtest==2)?NULL:tmpBSstream,
		     tmpSampleBuf+160,frameBufNumSample);
      BsClose(tmpBSstream);
      for (i=0; i<*frameBufNumSample*2; i++)
	mixSampleBuf[DPdelayNumSample-HVXdelayNumSample+i] += tmpSampleBuf[i];
      break;
    case 2:
      if (BsGetBuffer(stream,tmpBSbuf,80))
	CommonExit(-1,"DecParInit: mix: hvxc 1st frame: bits missing");
      tmpBSstream = BsOpenBufferRead(tmpBSbuf);
      DecParFrameHvx((DPtest==2)?NULL:tmpBSstream,
		     tmpSampleBuf,frameBufNumSample);
      BsClose(tmpBSstream);
      if (BsGetBuffer(stream,tmpBSbuf,80))
	CommonExit(-1,"DecParInit: mix: hvxc 2st frame: bits missing");
      tmpBSstream = BsOpenBufferRead(tmpBSbuf);
      DecParFrameHvx((DPtest==2)?NULL:tmpBSstream,
		     tmpSampleBuf+160,frameBufNumSample);
      BsClose(tmpBSstream);
      for (i=0; i<*frameBufNumSample*2; i++)
	mixSampleBuf[DPdelayNumSample-HVXdelayNumSample+i] += tmpSampleBuf[i];
      break;
    case 3:
      DecParFrameHvx(NULL,tmpSampleBuf,frameBufNumSample);
      DecParFrameHvx(NULL,tmpSampleBuf+160,frameBufNumSample);
      for (i=0; i<*frameBufNumSample*2; i++)
	mixSampleBuf[DPdelayNumSample-HVXdelayNumSample+i] += tmpSampleBuf[i];
      break;
    }
    if (il_hvxc != 0) {
      DecParFrameIl((DPtest==1)?NULL:stream,tmpSampleBuf,frameBufNumSample);
      for (i=0; i<*frameBufNumSample; i++)
	mixSampleBuf[DPdelayNumSample-ILdelayNumSample+i] += tmpSampleBuf[i];
    }
    else {
      DecParFrameIl(NULL,tmpSampleBuf,frameBufNumSample);
      for (i=0; i<*frameBufNumSample; i++)
	mixSampleBuf[DPdelayNumSample-ILdelayNumSample+i] += tmpSampleBuf[i];
    }
    for (i=0; i<*frameBufNumSample; i++)
      sampleBuf[0][i] = mixSampleBuf[i];
    for (i=0; i<mixSampleBufSize-*frameBufNumSample; i++)
      mixSampleBuf[i] = mixSampleBuf[i+*frameBufNumSample];
    for (i=0; i<*frameBufNumSample; i++)
      mixSampleBuf[i+mixSampleBufSize-*frameBufNumSample] = 0;
    break;
  }
  *usedNumBit = BsCurrentBit(stream);
  BsClose(stream);

  if (DPdebugLevel >= 1)
    printf("DecParFrame: numBit=%d  numSample=%d\n",
	   *usedNumBit,*frameBufNumSample);

}


/* DecParFree() */
/* Free memory allocated by parametric decoder core. */

void DecParFree ()
{
  if (DPdebugLevel >= 1)
    printf("DecParFree: ...\n");

  if (DPmode != MODEPAR_IL)
    DecParFreeHvx();
  if (DPmode != MODEPAR_HVX)
    DecParFreeIl();
}


/* end of dec_par.c */

