/**********************************************************************
MPEG-4 Audio VM
Decoder frame work



This software module was originally developed by

Heiko Purnhagen (University of Hannover / ACTS-MoMuSys)

and edited by

Naoya Tanaka (Matsushita Communication Industrial Co., Ltd.)

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

$Id: mp4dec.c,v 1.27 1997/11/13 12:51:46 purnhage Exp $

Required modules:
common.o		common module
cmdline.o		command line module
bitstream.o		bit stream module
audio.o			audio i/o module
dec_par.o		decoder core (parametric)
dec_lpc.o		decoder core (CELP)
dec_tf.o		decoder core (T/F)
dec_g729.o		decoder core (G729)
dec_g723.o		decoder core (G723)

Authors:
HP    Heiko Purnhagen, Uni Hannover <purnhage@tnt.uni-hannover.de>
NT    Naoya Tanaka, Panasonic <natanaka@telecom.mci.mei.co.jp>
BT    Bodo Teichmann, FhG/IIS <tmn@iis.fhg.de>
CCETT N.N., CCETT <@ccett.fr>

Changes:
18-jun-96   HP    first version
19-jun-96   HP    added .wav format / using new ComposeFileName()
26-jun-96   HP    improved handling of switch -o
04-jul-96   HP    joined with t/f code by BG
09-aug-96   HP    adapted to new cmdline module, added mp4.h
16-aug-96   HP    adapted to new dec.h
                  added multichannel signal handling
                  added cmdline parameters for numChannel, fSample
26-aug-96   HP    CVS
03-sep-96   HP    added speed change & pitch change for parametric core
30-oct-96   HP    additional frame work options
15-nov-96   HP    adapted to new bitstream module
18-nov-96   HP    changed int to long where required
                  added bit stream header options
10-dec-96   HP    added variable bit rate
10-jan-97   HP    using BsGetSkip()
23-jan-97   HP    added audio i/o module
03-feb-97   HP    audio module bug fix
07-feb-97   NT    added PICOLA speed control
14-mar-97   HP    merged FhG AAC code
21-mar-97   BT    various changes (t/f, AAC)
04-apr-97   HP    new option -r for scalable decoder
26-mar-97   CCETT added G729 decoder
07-apr-97   HP    i/o filename handling improved / "-" supported
05-nov-97   HP    update by FhG/UER
**********************************************************************/

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

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

#include "mp4.h"	/* frame work common declarations */
#include "dec.h"	/* decoder cores */

#include "pan_picola.h"	/* for speed control (PICOLA) */


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

#define PROGVER "MPEG-4 Audio VM Decoder V5.0 11-nov-97"
#define CVSID "$Id: mp4dec.c,v 1.27 1997/11/13 12:51:46 purnhage Exp $"


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

/* command line module */

static float decBitRate;
static int decBitRateUsed;
static int numChannelOut;
static float fSampleOut;
static float speedFact,pitchFact;
static float regionDurat;
static int regionDuratUsed;
static char *decPara;
static char *outFileName;
static int outFileNameUsed;
static char *bitPath,*decPath;
static int bitPathUsed,decPathUsed;
static char *bitExt,*decExt;
static int decExtUsed;
static int testBitStream;
static int mainDebugLevel,audioDebugLevel,bitDebugLevel,cmdDebugLevel;
static char* aacDebugString; /* Debug options for aac */
static int *varArgIdx;

#ifdef DEBUGPLOT
int frame; /* global for debugging purposes */
#else
static int frame;
#endif

/* for speed control (PICOLA) */
static int SpeedControlMode;

static CmdLinePara paraList[] = {
  {&varArgIdx,NULL,"<bit stream file(s)>"},
  {NULL,NULL,NULL}
};

static CmdLineSwitch switchList[] = {
  {"h",NULL,NULL,NULL,NULL,"print help"},
  {"r",&decBitRate,"%f",NULL,&decBitRateUsed,
   "decoder bit rate for scalability [bit/s]\n"
   "(dflt: encoder bit rate)"},
  {"n",&numChannelOut,"%d","0",NULL,"number of audio channels "
   "(0=as original)"},
  {"s",&fSampleOut,"%f","0",NULL,"sampling frequency [Hz] "
   "(0=as original)"},
  {"sf",&speedFact,"%f","1",NULL,"speed change factor"},
  {"pf",&pitchFact,"%f","1",NULL,"pitch change factor"},
  {"c",&decPara,"%s","",NULL,
   "decoder parameter string (\"-c h\" for help)"},
  {"td",&regionDurat,"%f",NULL,&regionDuratUsed,
   "duration of decoded region [sec]\n"
   "(dflt: until end of bit stream)"},
  {"o",&outFileName,"%s",NULL,&outFileNameUsed,"output file name"},
  {"pb",&bitPath,"%s",NULL,&bitPathUsed,
   "default path bit stream files (dflt: $" MP4_BIT_PATH_ENV ")"},
  {"pd",&decPath,"%s",NULL,&decPathUsed,
   "default path decoded audio files (dflt: $" MP4_DEC_PATH_ENV ")"},
  {"eb",&bitExt,"%s",MP4_BIT_EXT,NULL,"bit stream file extension"},
  {"ed",&decExt,"%s",NULL,&decExtUsed,
   "decoded audio file extension\n"
   "supported file formats: .au, .snd, .wav, .aif, .raw\n"
   "(dflt: $" MP4_DEC_FMT_ENV " / " MP4_DEC_EXT ")\n"
   "(raw format: integer16, native)"},
  {"t",&testBitStream,NULL,NULL,NULL,"test bit stream (decoder disabled)"},
  {"d",&mainDebugLevel,"%i","0",NULL,"main debug level"},
  {"da",&audioDebugLevel,"%i","0",NULL,"audio file debug level"},
  {"db",&bitDebugLevel,"%i","0",NULL,"bit stream debug level"},
  {"dc",&cmdDebugLevel,"%i","0",NULL,"cmd line debug level"},
  {"daac",&aacDebugString,"%s","",NULL,"[a-Z] Debug Optons for aac-Decoder"},
  {"picola", &SpeedControlMode, NULL, NULL, NULL, "speed control by PICOLA"},
  {NULL,NULL,NULL,NULL,NULL,NULL}
};


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

/* Decode() */
/* Decode bit stream and generate audio file. */
/* (This function evaluates the global xxxDebugLevel variables !!!) */

static int Decode (
  char *bitFileName,		/* in: bit stream file name */
  char *audioFileName,		/* in: audio file name */
  char *audioFileFormat,	/* in: audio file format */
				/*     (au, wav, aif, raw) */
  float decBitRate,		/* in: decoder bit rate (0=as encoder) */
  int testBitStream,		/* in: 0=normal decoding */
				/*     1=test bit stream (disable decoder) */
  int numChannelOut,		/* in: num audio channels */
  float fSampleOut,		/* in: sampling frequency [Hz] */
  float speedFact,		/* in: speed change factor */
  float pitchFact,		/* in: pitch change factor */
  char *decPara,		/* in: decoder parameter string */
  float regionDurat)		/* in: duration of region */
				/* returns: 0=OK  1=error */
{
  int mode;			/* enum MP4Mode */
  float fSample,fSampleOri,bitRate;
  long totNumSample;
  int numChannel,numChannelOri;
  int frameMaxNumSample,frameBufNumSample,delayNumSample;
  int frameMinNumBit,frameMaxNumBit;
  long fSampleLong,bitRateLong;
  char *info;
  char *codecMode;
  int bitReservSize;
  int bitReservInit;
  int bitHeaderNumBit;
  BsBitBuffer *bitBuf;
  float **sampleBuf;
  BsBitStream *bitStream;
  AudioFile *audioFile;
  BsBitBuffer *bitHeader;
  int numSample;
  int frameNumBit,frameAvailNumBit,usedNumBit;
  int frameDecNumBit;
  int headerNumBit;
  int padNumBit;
  long totDataNumBit,totPadNumBit;
  int ch;
  int bsVersion;
  int decNumFrame;

  /* for speed control (PICOLA) */
  float **PicolaBuffer;
  static int PicolaDecodeFlag = 1;
  static int PicolaOutputFlag = 1;
  long PicolaNumSample;
  int PicolaNumInputSample;

  /* init */
  if (mainDebugLevel >= 3) {
    printf("Decode:\n");
    printf("bitFileName=\"%s\"\n",bitFileName);
    printf("audioFileName=\"%s\"\n",audioFileName);
    printf("audioFileFormat=\"%s\"\n",audioFileFormat);
    printf("decBitRate=%.3f\n",decBitRate);
    printf("testBitStream=%d\n",testBitStream);
    printf("decPara=\"%s\"\n",decPara?decPara:"(NULL)");
    printf("regionDurat=%.6f\n",regionDurat);
  }

  BsInit(MAXREADAHEAD,bitDebugLevel);
  AudioInit(NULL,audioDebugLevel);
  info = NULL;
  /* open bit stream file */
  if ((strstr(decPara, "-aac_raw") != NULL) ||
      (strstr(decPara, "-aac_sca") != NULL))
    bitStream = BsOpenFileRead(bitFileName,NULL,&info);
  else
    bitStream = BsOpenFileRead(bitFileName,MP4_MAGIC,&info);
  
  if (bitStream==NULL) {
    CommonWarning("Decode: error opening bit stream file %s",bitFileName);
    return 1;
  }

  if ((mainDebugLevel >= 3) && (info != NULL))
    printf("info=\"%s\"\n",info);

  /* read bit stream header */
  bitHeader = BsAllocBuffer(BITHEADERBUFSIZE);


  if (!((strstr(decPara, "-aac_raw") != NULL) ||
	(strstr(decPara, "-aac_sca") != NULL))) {
    /* for qc_aac we read */
    if (BsGetBitInt(bitStream,(unsigned int*)&bsVersion,16) ||
	BsGetBitInt(bitStream,(unsigned int*)&numChannelOri,8) ||
	BsGetBit(bitStream,(unsigned long*)&fSampleLong,32) ||
	BsGetBit(bitStream,(unsigned long*)&bitRateLong,32) ||
	BsGetBitInt(bitStream,(unsigned int*)&frameNumBit,16) ||
	BsGetBitInt(bitStream,(unsigned int*)&frameMinNumBit,16) ||
	BsGetBitInt(bitStream,(unsigned int*)&bitReservSize,16) ||
        BsGetBitInt(bitStream,(unsigned int*)&bitReservInit,16) ||
        BsGetBitInt(bitStream,(unsigned int*)&mode,8) ||
        BsGetBitInt(bitStream,(unsigned int*)&bitHeaderNumBit,16))
      CommonExit(1,"Decode: error reading bit stream header (frame)");
    
    if (bsVersion != MP4_BS_VERSION) {
      CommonWarning("Decode: wrong bitstream version "
                    "(found 0x%4x, need 0x%4x)",bsVersion,MP4_BS_VERSION);
      return 1;
    }
    
    if (bitHeaderNumBit > BITHEADERBUFSIZE)
      CommonExit(1,"Decode: bit stream header too long");
    if (BsGetBuffer(bitStream,bitHeader,bitHeaderNumBit))
      CommonExit(1,"Decode: error reading bit stream header (core)");
  } 
  else{
    /* raw data */
    numChannelOri=1;
    fSampleLong=fSampleOut;
    if (fSampleLong < 8000 ){
      CommonExit(-1,"\n wrong sample rate %d \n",fSampleLong);
    }
    bitRateLong=128000;
    frameNumBit= 1024 * bitRateLong / fSampleLong; 
    if (strstr(decPara, "-qc_aac_960") != NULL)
      frameNumBit = 960*bitRateLong/fSampleLong ;
    if (strstr(decPara, "-aac_sca") != NULL)
      frameNumBit = 960*bitRateLong/fSampleLong ;
    frameMinNumBit=0;
    bitReservSize= 6000;	/* 6144-1366; */
    bitReservInit= 6000;	/* BT 971105 */  
    bitHeaderNumBit=0;
    mode = MODE_TF;
  }


  /* --- Set debugging options for aac_decoder --- */
  /*
    if (strstr(decPara, "-qc_aac") != NULL){
    extern int     aacSamplingRate;
    aacSamplingRate = (int)fSampleLong;
    } 
  */ 
/*   if (aacDebugString != NULL){ */
/*     aacDebugString	 */
/*   } */

  headerNumBit = BsCurrentBit(bitStream);

  frameMaxNumBit = frameNumBit+bitReservSize;
  fSampleOri = fSampleLong;
  bitRate = bitRateLong;
  if (decBitRate == 0) {
    decBitRate = bitRate;
    frameDecNumBit = 0;
  }
  else {
    if (decBitRate > bitRate) {
      CommonWarning("Decode: decBitRate > bitRate, using bitRate");
      decBitRate = bitRate;
    }
    if (frameMinNumBit < frameNumBit)
      CommonExit(1,"Decode: scalability not possible for variable bit rate");
    if (bitReservSize != 0)
      CommonExit(1,"Decode: scalability not possible for bit reservoir");
    frameDecNumBit  = (int)(frameNumBit/bitRate*decBitRate+.5);
  }

  if (regionDurat < 0)
    decNumFrame = -1;
  else
    decNumFrame = max(0,(int)(regionDurat*bitRate/frameNumBit));

  numChannel = (numChannelOut != 0) ? numChannelOut : numChannelOri;
  fSample = (fSampleOut != 0) ? fSampleOut : fSampleOri;

  if(SpeedControlMode) {
    if(numChannel>1) {
      CommonWarning("Decode: "
		    "numChannel>1 : PICOLA speed control is disabled\n");
      SpeedControlMode = 0;
    }
  }
  PicolaNumSample = 0;

  if (mainDebugLevel >= 3) {
    printf("mode=%d\n",mode);
    printf("numChannelOri=%d\n",numChannelOri);
    printf("fSampleOri=%.3f Hz  (int=%ld)\n",fSampleOri,fSampleLong);
    printf("numChannel=%d\n",numChannel);
    printf("fSample=%.3f Hz\n",fSample);
    printf("speedFact=%.3f",speedFact);
    if(SpeedControlMode) {
      printf(" :picola\n");
    }else {
      printf("\n");
    }
    printf("pitchFact=%.3f\n",pitchFact);
    printf("bitRate=%.3f bit/sec  (int=%ld)\n",bitRate,bitRateLong);
    printf("bitReservSize=%d bit  (%.6f sec)\n",
	   bitReservSize,bitReservSize/bitRate);
    printf("bitReservInit=%d bit\n",bitReservInit);
    printf("frameNumBit=%d  (%.6f sec)\n",frameNumBit,frameNumBit/bitRate);
    printf("frameDecNumBit=%d\n",frameDecNumBit);
    printf("frameMinNumBit=%d\n",frameMinNumBit);
    printf("frameMaxNumBit=%d\n",frameMaxNumBit);
    printf("bitHeaderNumBit=%d\n",bitHeaderNumBit);
    printf("headerNumBit=%d\n",headerNumBit);
    printf("decNumFrame=%d\n",decNumFrame);
  }

  if (testBitStream && frameNumBit != frameMinNumBit)
    CommonExit(1,"Decode: variable bit rate, bit stream test NOT possible!");

  if (frameMaxNumBit > MAXREADAHEAD)
    CommonExit(1,"Decode: max bit stream frame size too long");

  if (mode<=0 || mode>=MODE_NUM)
    CommonExit(1,"Decode: unknown codec mode %d",mode);
  codecMode = MP4ModeName[mode];

  if (mainDebugLevel >= 3)
    printf("codecMode=\"%s\"\n",codecMode);

  if (!testBitStream) {
    switch (mode) {
    case MODE_PAR:
      if(SpeedControlMode) {
        DecParInit(numChannel,fSample,decBitRate,1,pitchFact,decPara,
		   bitHeader,&frameMaxNumSample,&delayNumSample);
      }else {
	DecParInit(numChannel,fSample,decBitRate,speedFact,pitchFact,decPara,
		   bitHeader,&frameMaxNumSample,&delayNumSample);
      }
      break;
    case MODE_LPC:
      DecLpcInit(numChannel,fSample,decBitRate,decPara,
		 bitHeader,&frameMaxNumSample,&delayNumSample);
      break;
    case MODE_G729:
      DecG729Init(numChannel,fSample,decBitRate,decPara,
		 bitHeader,&frameMaxNumSample,&delayNumSample);
      break;
    case MODE_G723:
      DecG723Init(numChannel,fSample,decBitRate,decPara,
		 bitHeader,&frameMaxNumSample,&delayNumSample);
      break;
    case MODE_TF:
      DecTfInit(numChannel,fSample,decBitRate,decPara,
		bitHeader,&frameMaxNumSample,&delayNumSample,aacDebugString);
      break;
    }
  }	/* if (!testBitStream) */
#pragma warning "patch just for testing"
/*   fSample = 8000; */

  /* speed control initialization */
  if(SpeedControlMode)
    PicolaInit(frameMaxNumSample, fSample, speedFact);

  BsFreeBuffer(bitHeader);

  if (!testBitStream) {
    if (mainDebugLevel >= 3) {
      printf("frameMaxNumSample=%d  (%.6f sec/frame)\n",
	     frameMaxNumSample,frameMaxNumSample/fSample);
      printf("delayNumSample=%d  (%.6f sec)\n",
	     delayNumSample,delayNumSample/fSample);
    }

    /* allocate buffers */
    bitBuf = BsAllocBuffer(frameMaxNumBit);
    if ((sampleBuf=(float**)malloc(numChannel*sizeof(float*)))==NULL)
      CommonExit(1,"Decode: memory allocation error");
    for (ch=0; ch<numChannel; ch++)
      if ((sampleBuf[ch]=(float*)malloc(frameMaxNumSample*sizeof(float)))
	  ==NULL)
	CommonExit(1,"Decode: memory allocation error");

    /* for speed control (PICOLA) */
    if(NULL==(PicolaBuffer=(float **)calloc(numChannel, sizeof(float)))) {
      CommonExit(1, "Decode: memory allocation error");
    }
    for(ch=0;ch<numChannel;ch++) {
      if(NULL==(*(PicolaBuffer+ch)=(float *)calloc(frameMaxNumSample, 
						   sizeof(float)))) {
        CommonExit(1, "Decode: memory allocation error");
      }
    }

    /* open audio file */
    /* (sample format: 16 bit twos complement, uniform quantisation) */
    audioFile = AudioOpenWrite(audioFileName,audioFileFormat,
			       numChannel,fSample);
    if (audioFile==NULL)
      CommonExit(1,"Decode: error opening audio file %s "
		 "(maybe unknown format \"%s\")",
		 audioFileName,audioFileFormat);

    /* seek to beginning of first frame (with delay compensation) */
    AudioSeek(audioFile,-delayNumSample);

  }	/* if (!testBitStream) */

  /* process bit stream frame by frame */
  frame = 0;
  totNumSample = 0;
  totPadNumBit = 0;
  frameAvailNumBit = frameNumBit+bitReservInit;

  while (!BsEof(bitStream,frameAvailNumBit-1) &&
	 (decNumFrame < 0 || frame < decNumFrame)) {

    if (mainDebugLevel >= 1 && mainDebugLevel <= 3) {
      printf("\rframe %4d ",frame);
      fflush(stdout);
    }
    if (mainDebugLevel > 3)
      printf("frame %4d\n",frame);
    if (mainDebugLevel >= 5)
      printf("frameAvailNumBit=%d\n",frameAvailNumBit);


    if (!testBitStream) {

      /* read bit stream */
      if (BsGetBufferAhead(bitStream,bitBuf,
			   frameDecNumBit ? frameDecNumBit : frameAvailNumBit))
	CommonExit(1,"Decode: error reading bit stream data");

      /* decode one frame */
      switch (mode) {
      case MODE_PAR:
	DecParFrame(bitBuf,sampleBuf,&usedNumBit,&frameBufNumSample);
	break;
      case MODE_LPC:
	DecLpcFrame(bitBuf,sampleBuf,&usedNumBit);
	frameBufNumSample = frameMaxNumSample;
	break;
      case MODE_G729:
	DecG729Frame(bitBuf,sampleBuf,&usedNumBit,0);
	frameBufNumSample = frameMaxNumSample;
	break;
      case MODE_G723:
	DecG723Frame(bitBuf,sampleBuf,&usedNumBit);
	frameBufNumSample = frameMaxNumSample;
	break;
      case MODE_TF:
	DecTfFrame(bitBuf,sampleBuf,&usedNumBit,numChannel);
	frameBufNumSample = frameMaxNumSample;
	break;
      }
    }
    else	/* if (!testBitStream) */
      usedNumBit = frameNumBit;

    if (mainDebugLevel >= 5) {
      if (!testBitStream)
	printf("frameBufNumSample=%d\n",frameBufNumSample);
      printf("usedNumBit=%d\n",usedNumBit);
    }

    if (usedNumBit > frameAvailNumBit)
      CommonExit(1,"Decode: more bits used than available in frame+buffer");

    /* check for padding bits */
    if (frameAvailNumBit-usedNumBit-frameNumBit+frameMinNumBit
	> bitReservSize) {
      padNumBit = frameAvailNumBit-usedNumBit-frameNumBit+frameMinNumBit
	-bitReservSize;

      if (mainDebugLevel >= 5)
	printf("padNumBit=%d\n",padNumBit);

      usedNumBit += padNumBit;
      totPadNumBit += padNumBit;
    }

    /* advance in bit stream */
    if (frameDecNumBit)
      usedNumBit = frameNumBit;
    if (BsGetSkip(bitStream,usedNumBit))
      CommonExit(1,"Decode: error advancing in bit stream data");
    frameAvailNumBit -= usedNumBit;

#ifdef ENABLE_PATCH_KEMAL
    /* HP 970404 */
    /* disabled this path since it confuses framework bitstream handling */
    /* if necessary for AAC, use variable rate (i.e. increased frameNumBit) */

    /* === PATCH: KEMAL === */
    /* We want the bitbuffer keep filled */
#pragma warning ***** PATCH (KEMAL): KEEP THE BITBUFFER ALWAYS MAXIMUM-FILLED *****
    frameAvailNumBit += bitReservSize;
    /* === PATCH: KEMAL === */
#endif

    /* variable bit rate: don't exceed bit reservoir size */
    if (frameAvailNumBit > bitReservSize)
      frameAvailNumBit = bitReservSize;

    frameAvailNumBit += frameNumBit;

    if (!testBitStream) {
      if(SpeedControlMode) {
        PicolaDecodeFlag = 0;
        PicolaNumInputSample = frameBufNumSample;
        totNumSample += frameBufNumSample;
	
        while(0==PicolaDecodeFlag) {
          mod_picola(sampleBuf[0], PicolaNumInputSample, 
		     PicolaBuffer[0], speedFact, 
		     &PicolaDecodeFlag, &PicolaOutputFlag);
          PicolaNumInputSample = 0;
          if(PicolaOutputFlag) {
            /* write audio file */
            numSample = frameMaxNumSample;
            AudioWriteData(audioFile,PicolaBuffer,numSample);
            PicolaNumSample += numSample;
          }
        }

      }else {
	/* write audio file */
	AudioWriteData(audioFile,sampleBuf,frameBufNumSample);
	totNumSample += frameBufNumSample;
      }
    }	 /* if (!testBitStream) */

    frame++;
  }	/* while (!BsEof(...)) */

  if (mainDebugLevel >= 1 && mainDebugLevel <= 3)
    printf(" \n");

  totDataNumBit = BsCurrentBit(bitStream)-headerNumBit-totPadNumBit;

  frameAvailNumBit -= frameNumBit;

  if (mainDebugLevel >= 3) {
    printf("totNumFrame=%d\n",frame);
    printf("totNumBit=%ld\n",BsCurrentBit(bitStream));
    if (!testBitStream) {
      printf("totDataNumBit=%ld  (%.3f bit/frame)\n",
	     totDataNumBit,totDataNumBit/(float)frame);
      printf("bitRate=%.3f bit/sec  (%.6f sec/frame)\n",
	     bitRate,totDataNumBit/(float)frame/bitRate);
      printf("totPadNumBit=%ld\n",totPadNumBit);
      printf("frameRemainNumBit=%d\n",frameAvailNumBit);
      if(SpeedControlMode) {
        printf("totNumSample=%ld  (%.3f sec)\n",
	     PicolaNumSample,PicolaNumSample/fSample);
        printf("Speed Control Ratio: Target=%.3f, Result=%.3f\n", 
            speedFact, totNumSample/(float)PicolaNumSample);
      }else {
        printf("totNumSample=%ld  (%.3f sec)\n",
	     totNumSample,totNumSample/fSample);
      }
      printf("delayNumSample=%d  (%.3f sec)\n",
	     delayNumSample,delayNumSample/fSample);
      printf("fileNumSample=%ld  (%.3f sec)\n",
	     totNumSample-delayNumSample,
	     (totNumSample-delayNumSample)/fSample);
      printf("frameAvgNumSample=%.3f  (%.6f sec/frame)\n",
	     totNumSample/(float)frame,
	     totNumSample/(float)frame/fSample);
    }
  }

  /* free decoder memory */
  switch (mode) {
  case MODE_PAR:
    DecParFree();
    break;
  case MODE_LPC:
    DecLpcFree();
    break;
  case MODE_G729:
    printf("DecG729Free to be defined.\n");
    break;
  case MODE_G723:
    printf("DecG723Free to be defined.\n");
    break;
  case MODE_TF:
    DecTfFree();
    break;
  }

  if(SpeedControlMode)
    PicolaFree();

  /* close bit stream file */
  if (BsClose(bitStream))
    CommonExit(1,"Decode: error closing bit stream file");

  if (!testBitStream) {
    /* close audio file */
    AudioClose(audioFile);
  
    /* free buffers */
    if (numChannel>1)
      for (ch=0; ch<numChannel; ch++)
	free(sampleBuf[ch]);
    free(sampleBuf);
    BsFreeBuffer(bitBuf);

    /* for speed control (PICOLA) */
    if (numChannel>1)
      for (ch=0; ch<numChannel; ch++)
	free(*(PicolaBuffer+ch));
    free(PicolaBuffer);
  }	/* if (!testBitStream) */

  return 0;
}



/* ---------- main ---------- */

int main (int argc, char *argv[])
{
  char *progName = "<no program name>";
  int result;
  char bitFileName[STRLEN],decFileName[STRLEN];
  char *decFormat;
  int fileIdx;

  /* evaluate command line  */
  CmdLineInit(0);
  result = CmdLineEval(argc,argv,paraList,switchList,1,&progName);
  if (result) {
    if (result==1) {
      printf("%s: %s\n",progName,PROGVER);
      CmdLineHelp(progName,paraList,switchList,stdout);
      DecParInfo(stdout);
      DecLpcInfo(stdout);
      DecTfInfo(stdout);
      DecG729Info(stdout);
      DecG723Info(stdout);
      exit (1);
    }
    else
      CommonExit(1,"command line error (\"-h\" for help)");
  }

  if (mainDebugLevel >= 1)
    printf("%s: %s\n",progName,PROGVER);
  if (mainDebugLevel >= 2) {
    printf("CVS Id: %s\n",CVSID);
    printf("%s\n",DecParInfo(NULL));
    printf("%s\n",DecLpcInfo(NULL));
    printf("%s\n",DecTfInfo(NULL));
    printf("%s\n",DecG723Info(NULL));   
    printf("%s\n",DecG729Info(NULL));
  }

  CmdLineInit(cmdDebugLevel);

  /* calc variable default values */
  if (!decBitRateUsed)
    decBitRate = 0;
  if (!regionDuratUsed)
    regionDurat = -1;
  if (!bitPathUsed)
    bitPath = getenv(MP4_BIT_PATH_ENV);
  if (!decPathUsed)
    decPath = getenv(MP4_DEC_PATH_ENV);
  if (!decExtUsed)
    decExt = getenv(MP4_DEC_FMT_ENV);
  if (decExt==NULL)
    decExt = MP4_DEC_EXT;

  /* check command line options */
  if (decBitRate < 0)
    CommonExit(1,"decoder bit rate < 0");
  if (numChannelOut < 0)
    CommonExit(1,"number of audio channels < 0");
  if (fSampleOut < 0)
    CommonExit(1,"sampling frequency < 0");
  if (speedFact <= 0)
    CommonExit(1,"speech change factor <= 0");
  if (pitchFact <= 0)
    CommonExit(1,"pitch change factor <= 0");
  if (regionDuratUsed && regionDurat < 0)
    CommonExit(1,"duration of region < 0");
  if (outFileNameUsed && varArgIdx[0]>=0 && varArgIdx[1]>=0)
    CommonExit(1,"only one input file allowed when using -o");
  if (varArgIdx[0]<0)
    CommonExit(1,"no input file specified");
  
  /* process all files on command line */
  fileIdx = 0;
  while (varArgIdx[fileIdx] >= 0) {

    /* compose file names */
    if (ComposeFileName(argv[varArgIdx[fileIdx]],0,bitPath,bitExt,bitFileName,
			STRLEN))
      CommonExit(1,"composed file name too long");
    if (outFileNameUsed) {
      if (ComposeFileName(outFileName,0,decPath,decExt,decFileName,
			  STRLEN))
	CommonExit(1,"composed file name too long");
    }
    else
      if (ComposeFileName(argv[varArgIdx[fileIdx]],1,decPath,decExt,
			  decFileName,STRLEN))
	CommonExit(1,"composed file name too long");

    /* extract file format (extension) */
    if (strcmp(decFileName,"-") == 0)
      decFormat = decExt;
    else {
      decFormat = decFileName+strlen(decFileName);
      do
	decFormat--;
      while (decFormat>decFileName && *decFormat!='.');
    }

    /* decode file */
    if (mainDebugLevel >= 1)
      printf("decoding %s -> %s\n",bitFileName,decFileName);

    if (Decode(bitFileName,decFileName,decFormat,decBitRate,testBitStream,
	       numChannelOut,fSampleOut,speedFact,pitchFact,decPara,
	       regionDurat))
      CommonWarning("error decoding audio file %s",bitFileName);

    fileIdx++;
  }

  CmdLineEvalFree(paraList);

  if (mainDebugLevel >= 1)
    printf("%s: finished\n",progName);

  return 0;
}

/* end of mp4dec.c */

