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



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

$Id: indilinesyn.c,v 1.7 1997/11/20 21:22:46 purnhage Exp $

Required libraries:
(none)

Required modules:
indilinecom.o		indiline common module

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

Changes:
01-sep-96   HP    first version based on indiline.c
10-sep-96   BE
11-sep-96   HP
26-sep-96   HP    new indiline module interfaces
17-jan-97   HP    fixed linePred>prevNumLine bug
14-apr-97   HP    new line start phase: cos(M_PI/2)
22-apr-97   HP    noisy stuff ...
23-apr-97   BE    noise synthesis ...
11-jun-97   HP    added IndiLineSynthFree()
23-jun-97   HP    improved env/harm/noise interface
27-jun-97   HP    fixed short fade
29-aug-97   HP    added random start phase
**********************************************************************/


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

#include "indilinecom.h"	/* indiline common module */
#include "indilinesyn.h"	/* indiline synthesiser module */
#include "uhd_fft.h"		/* fft/ifft/odft/iodft module */

#include "common.h"		/* for random() and RND_MAX */


/* 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 (global) ---------- */

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

#define SHORT_THR 5			/* env rate threshold for short fade */
#define SHORT_FAC (1./8.)		/* factor for short fade length */
#define NOISE_FAC (1./4.)		/* factor for noise fade length */

#define ANTIALIAS_FREQ 0.49		/* anti alias filter cutoff freq */

/* quick'n'dirty decoder control HP970514 */
int ILDrndPhase = 1;


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

/* status variables and arrays for individual line synthesis (ILS) */

struct ILSstatusStruct		/* ILS status handle struct */
{
 /* general parameters */
  int debugLevel;		/* debug level (0=off) */
  int maxFrameLen;		/* max num samples per frame */
  float fSample;		/* sampling frequency */
  int maxNumLine;		/* max num lines */
  int maxNumEnv;		/* max num envelopes */
  int maxNumNoisePara;		/* max num noise parameters */
  int maxNoiseLen;		/* >= maxFrameLen */

  /* parameters for synthesis */
  int frameLen;			/* num samples in current frame */
  int shortOff;			/* short fade offset (in, out, x-fade) */
  int noiseOff;			/* noise fade offset */

  /* pointers to fixed content arrays */
  float *longWin;		/* long fade-in window  [0..frameLen-1] */
  float *shortWin;		/* short fade-in window */
				/*  [0..frameLen-2*shortOff-1] */
  float *noiseWin;		/* noise fade-in window */
				/*  [0..frameLen-2*noiseOff-1] */

  /* pointers to variable content arrays */
  float *tmpLinePhase;		/* phase or phase deviation */
				/*   [0..maxNumLine-1] */
  float **env;			/* current frame envelope  */
				/*   [0..numEnv-1][0..2*frameLen-1] */
  float **prevEnv;		/* prev frame envelope */
				/*   [0..numEnv-1][0..2*frameLen-1] */
  int *prevLineSyn;		/* prev frame line synthesised */
				/*   [0..numLine-1] */
  int *prevLongEnvOut;		/* long fadeout  [0..numEnv-1] */
  int *longEnvIn;		/* long fadein  [0..numEnv-1] */
  float *noiseIdctIn;		/* idct in [0..numNoisePara-1] */
  float *noiseIdctOut;		/* idct out [0..noiseLen-1] */
  float *noiseRe;		/* noise real [0..2*noiseLen-1] */
  float *noiseIm;		/* noise imag [0..2*noiseLen-1] */

  /* variables and pointers to arrays for frame-to-frame memory */
  int prevNumLine;		/* num lines in prev frame */
  int prevNumEnv;		/* num env in prev frame */
  float **prevEnvPara;		/* envelope parameters  */
				/*   [0..numEnv-1][0..ENVPARANUM-1] */
  float *prevLineFreq;		/* line frequency  [0..numLine-1] */
  float *prevLineAmpl;		/* line amplitude  [0..numLine-1] */
  float *prevLinePhase;		/* line phase  [0..numLine-1] */
  int *prevLineEnv;		/* line envelope flag  [0..numLine-1] */
  int prevNoiseLen;		/* prev noise length */
  float *prevNoise;		/* prev noise [0..2*noiseLen-1] */
  int prevNoiseEnv;		/* prev noise envelope */

};


/* ---------- functions (internal) ---------- */


/* NoiseIdct */
/* IDCT of arbitrary length (sizex), uses only the sizey */
/* first IDCT input values. Note: input values are MODIFIED!!! */

static void NoiseIdct(
  float *y,			/* in:  IDCT input, MODIFIED!!! */
  float *x,			/* out: IDCT output */
  int sizey,			/* in:  length of vector y */
  int sizex,			/* in:  length of vector x */
  int sizedct)			/* in:  length of DCT */
{
  int i,j;

  y[0] /= sqrt(2.);
  for(i=0;i<sizey;i++)
    y[i] *= sqrt(2./(float)sizedct);

  for(j=0;j<sizex;j++) {
    x[j] = 0;
    for(i=0;i<sizey;i++)
      x[j] += y[i]*cos(M_PI*(float)i*((float)j+.5)/(float)sizedct);
  }
}


/* CalcMinLinePhaseDelta() */
/* Calculate min phase deviation from linear sweep. */
/* Result is stored in ILS->tmpLinePhase. */

static float *CalcMinLinePhaseDelta (
  ILSstatus *ILS,		/* ILS status handle */
  int frameLen,			/* in: frame length */
  int numLine,			/* in: num lines */
  float *lineFreq,		/* in: line frequency */
				/*     [0..numLine-1] */
  float *linePhase,		/* in: line phase */
				/*     [0..numLine-1] */
				/*     required if enhaMode!=0 */
  int *linePred)		/* in: line predecessor idx */
				/*     in prev frame */
				/*     [0..numLine-1] */
				/* returns: minLinePhaseDelta */
				/*          [0..numLine-1] */
{
  int il;
  float phase,freq,phi0,phi1,phi2,phi;

  for (il=0;il<numLine;il++)
    if (linePred[il] && linePred[il]<=ILS->prevNumLine) {
      phi0 = ILS->prevLinePhase[linePred[il]-1];
      phi1 = ILS->prevLineFreq[linePred[il]-1]/ILS->fSample*2*M_PI;
      phase = linePhase[il];
      freq = lineFreq[il]/ILS->fSample*2*M_PI;
      /* phi1+2*phi2*frameLen = freq */
      phi2 = (freq-phi1)/(2*frameLen);
      phi = phi0+phi1*frameLen+phi2*frameLen*frameLen;
      ILS->tmpLinePhase[il] = fmod(phase-phi,2*M_PI);
      if (ILS->tmpLinePhase[il]<0)
	ILS->tmpLinePhase[il] += 2*M_PI;
      if (ILS->tmpLinePhase[il]>M_PI)
	ILS->tmpLinePhase[il] -= 2*M_PI;
      if (ILS->debugLevel>=2)
	printf("%2d phase=%9.3f phi=%9.3f delta=%9.3f\n",
	       il,phase,phi,ILS->tmpLinePhase[il]);
    }
  return ILS->tmpLinePhase;
}


/* BuildEnv() */
/* Generate envelope from parameters. */

static void BuildEnv (
  float *envPara,		/* in: envelope parameters */
  int frameLen,			/* in: frame length */
  float *env)			/* out: envelope  [0..2*frameLen-1] */
{
  float atk_ratei,dec_ratei;
  int maxi;
  int i;

  maxi = (int)(envPara[0]*frameLen);
  atk_ratei = envPara[1]/frameLen;
  dec_ratei = envPara[2]/frameLen;
  for(i=0;i<2*frameLen;i++)
    env[i] = 0;
  i = maxi+frameLen/2;
  while (i>=0) {
    env[i] = 1-atk_ratei*(maxi-(i-frameLen/2));
    if (env[i] <= 0) {
      env[i] = 0;
      i = -1;
    } 
    else
      i--;
  }
  i = maxi+frameLen/2;
  while (i<2*frameLen) {
    env[i] = 1-dec_ratei*((i-frameLen/2)-maxi);
    if (env[i] <= 0) {
      env[i] = 0;
      i = 2*frameLen;
    } 
    else
      i++;
  }
}


/* AntiAlias() */
/* Anti alias filter. */

static float AntiAlias (
  float fSample,		/* in: sampling frequency */
  float freq)			/* in: signal frequency */
				/* returns: ampl. factor (0..1) */
{
  if (freq>=fSample/2 || freq<=0)
    return 0;
  else if (freq>fSample*ANTIALIAS_FREQ)
    return 1-(freq/fSample-ANTIALIAS_FREQ)/(0.5-ANTIALIAS_FREQ);
  else
    return 1;
}



/* ---------- functions (global) ---------- */

/* IndiLineSynthInit */
/* init for IndiLine functions */

ILSstatus *IndiLineSynthInit (
  int maxFrameLen,		/* in: max num samples per frame */
  float fSample,		/* in: sampling frequency */
  int maxNumLine,		/* in: max num lines */
  int maxNumEnv,		/* in: max num envelopes */
  int maxNumNoisePara,		/* in: max num noise parameters */
  int debugLevel)		/* in: debug level (0=off) */
				/* returns: ILS status handle */
{
  ILSstatus *ILS;
  int i;

  if ((ILS = (ILSstatus *) malloc(sizeof(ILSstatus)))==NULL)
    IndiLineExit("IndiLineSynthInit: memory allocation error");

  ILS->maxFrameLen = maxFrameLen;
  ILS->fSample = fSample;
  ILS->maxNumLine = maxNumLine;
  ILS->maxNumEnv = maxNumEnv;
  ILS->maxNumNoisePara = maxNumNoisePara;
  ILS->debugLevel = debugLevel;

  ILS->maxNoiseLen = 1;
  while (ILS->maxNoiseLen < maxFrameLen)
    ILS->maxNoiseLen *= 2;

  /* allocate memory for arrays */
  if (
      /* fixed content arrays */
      (ILS->longWin=(float*)malloc(maxFrameLen*sizeof(float)))==NULL ||
      (ILS->shortWin=(float*)malloc(maxFrameLen*sizeof(float)))==NULL ||
      (ILS->noiseWin=(float*)malloc(maxFrameLen*sizeof(float)))==NULL ||
      /* variable content arrays */
      (ILS->tmpLinePhase=(float*)malloc(ILS->maxNumLine*
					sizeof(float)))==NULL ||
      (ILS->env=(float**)malloc(ILS->maxNumEnv*sizeof(float*)))==NULL ||
      (ILS->env[0]=(float*)malloc(ILS->maxNumEnv*2*maxFrameLen*
				  sizeof(float)))==NULL ||
      (ILS->prevEnv=(float**)malloc(ILS->maxNumEnv*sizeof(float*)))==NULL ||
      (ILS->prevEnv[0]=(float*)malloc(ILS->maxNumEnv*2*maxFrameLen*
				      sizeof(float)))==NULL ||
      (ILS->prevLineSyn=(int*)malloc(ILS->maxNumLine*sizeof(int)))==NULL ||
      (ILS->prevLongEnvOut=(int*)malloc(ILS->maxNumEnv*sizeof(int)))==NULL ||
      (ILS->longEnvIn=(int*)malloc(ILS->maxNumEnv*sizeof(int)))==NULL ||
      (ILS->noiseIdctIn=(float*)malloc(ILS->maxNumNoisePara*
				       sizeof(float)))==NULL ||
      (ILS->noiseIdctOut=(float*)malloc(ILS->maxNoiseLen*
					sizeof(float)))==NULL ||
      (ILS->noiseRe=(float*)malloc(ILS->maxNoiseLen*2*sizeof(float)))==NULL ||
      (ILS->noiseIm=(float*)malloc(ILS->maxNoiseLen*2*sizeof(float)))==NULL ||
      /* arrays for frame-to-frame memory */
      (ILS->prevEnvPara=(float**)malloc(ILS->maxNumEnv*
					sizeof(float*)))==NULL ||
      (ILS->prevEnvPara[0]=(float*)malloc(ILS->maxNumEnv*ENVPARANUM*
					sizeof(float)))==NULL ||
      (ILS->prevLineFreq=(float*)malloc(ILS->maxNumLine*
					sizeof(float)))==NULL ||
      (ILS->prevLineAmpl=(float*)malloc(ILS->maxNumLine*
					sizeof(float)))==NULL ||
      (ILS->prevLinePhase=(float*)malloc(ILS->maxNumLine*
					 sizeof(float)))==NULL ||
      (ILS->prevLineEnv=(int*)malloc(ILS->maxNumLine*sizeof(int)))==NULL ||
      (ILS->prevNoise=(float*)malloc(ILS->maxNoiseLen*2*sizeof(float)))==NULL)
    IndiLineExit("IndiLineSynthInit: memory allocation error");
  
  for (i=1;i<ILS->maxNumEnv;i++) {
    ILS->env[i] = ILS->env[0]+i*2*maxFrameLen;
    ILS->prevEnv[i] = ILS->prevEnv[0]+i*2*maxFrameLen;
    ILS->prevEnvPara[i] = ILS->prevEnvPara[0]+i*ENVPARANUM;
  }

  /* clear frame-to-frame memory */
  ILS->prevNumLine = 0;
  ILS->prevNumEnv = 0;
  ILS->prevNoiseLen = 0;

  /* reset frameLen */
  ILS->frameLen = 0;

  if (ILS->debugLevel>=1)
    printf("maxfrmlen=%d fs=%9.3f numlin=%d\n",
	   ILS->maxFrameLen,ILS->fSample,ILS->maxNumLine);

  return ILS;
}


/* IndiLineSynth */
/* Synthesis of individual lines according to quantised parameters. */
/* enhaMode=0: For basic bitstream: phase information updated internally! */
/* enhaMode=1: For basic+enhancement bitstream: phase information required! */

void IndiLineSynth (
  ILSstatus *ILS,		/* ILS status handle */
  int enhaMode,			/* in: 0=basic mode  1=enhanced mode */
  int frameLen,			/* in: num samples in current frame */
  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] */
				/*     (required in enha mode) */
  float *linePhaseDelta,	/* in: line phase deviation from */
				/*     linear sweep for cont lines */
				/*     [0..numLine-1] */
				/*     or NULL if not available */
				/*     (utilised only in enha mode) */
  int *lineEnv,			/* in: line envelope flag */
				/*     [0..numLine-1] */
  int *linePred,		/* in: line predecessor idx */
				/*     in prev frame */
				/*     [0..numLine-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 *synthSignal)		/* out: synthesised signal */
				/*      [0..frameLen-1] */
				/*      2nd half previous frame and */
				/*      1st half current frame */
{
  int il,ilPrev;
  int i,j;
  float phi,phiT,phi0,phi1,phi2,phi3,phase,freq;
  float ae,as,a;

  float noiseAmpl,randFlt,qsNoise;
  int noiseLen,noiseBW;

  if (numLine>ILS->maxNumLine || frameLen>ILS->maxFrameLen)
	IndiLineExit("IndiLineSynth: error");

  if (frameLen != ILS->frameLen) {
    ILS->frameLen = frameLen;
    /* calc long and short fade-in windows for new frameLen */
    for (i=0;i<frameLen;i++)
      ILS->longWin[i] = 0.5*(1-cos(M_PI*(i+.5)/frameLen));
    ILS->shortOff = (int)(frameLen/2.*(1-SHORT_FAC));
    for (i=0;i<frameLen-2*ILS->shortOff;i++)
      ILS->shortWin[i] = 0.5*(1-cos(M_PI*(i+.5)/(frameLen-2*ILS->shortOff)));
    /* calc noise window */
    ILS->noiseOff = (int)(frameLen/2.*(1-NOISE_FAC));
    for (i=0;i<frameLen-2*ILS->noiseOff;i++)
      ILS->noiseWin[i] = sin(M_PI/2.*(i+.5)/(frameLen-2*ILS->noiseOff));
  }

  /* build previous & current envelope */
  for (i=0; i<ILS->prevNumEnv; i++)
    BuildEnv(ILS->prevEnvPara[i],frameLen,ILS->prevEnv[i]);
  for (i=0; i<numEnv; i++)
    BuildEnv(envPara[i],frameLen,ILS->env[i]);

  /* detect slow atk/dec */
  for (i=0; i<ILS->prevNumEnv; i++) {
    ILS->prevLongEnvOut[i] = (ILS->prevEnvPara[i][2] < SHORT_THR) &&
      ((ILS->prevEnvPara[i][0] < 0.5) || (ILS->prevEnvPara[i][1] < SHORT_THR));
    if (ILS->debugLevel>=1)
      printf("synt prev %d env t=%5.2f a=%5.2f d=%5.2f longOut=%1d\n",
	     i,ILS->prevEnvPara[i][0],ILS->prevEnvPara[i][1],
	     ILS->prevEnvPara[i][2],ILS->prevLongEnvOut[i]);
  }
  for (i=0; i<numEnv; i++) {
    ILS->longEnvIn[i] = (envPara[i][1] < SHORT_THR) &&
      ((envPara[i][0] > 0.5) || (envPara[i][2] < SHORT_THR));
    if (ILS->debugLevel>=1)
      printf("          %d env t=%5.2f a=%5.2f d=%5.2f  longIn=%1d\n",
	     i,envPara[i][0],envPara[i][1],envPara[i][2],ILS->longEnvIn[i]);
  }
  if (enhaMode==0)
    linePhase = ILS->tmpLinePhase;
  if (enhaMode != 0 && linePhaseDelta == NULL)
    linePhaseDelta = CalcMinLinePhaseDelta(ILS,frameLen,numLine,lineFreq,
					   linePhase,linePred);

  /* clear synthSignal */
  for (i=0;i<frameLen;i++)
    synthSignal[i] = 0;

  for (ilPrev=0;ilPrev<ILS->prevNumLine;ilPrev++)
    ILS->prevLineSyn[ilPrev] = 0;

  for (il=0;il<numLine;il++)
    if (linePred[il] && linePred[il]<=ILS->prevNumLine) {
      /* synthesise continued line */
      ilPrev = linePred[il]-1;
      if (ILS->debugLevel>=2) {
	printf(" cont ilp=%2d f=%7.1f a=%7.1f ",
	       ilPrev,ILS->prevLineFreq[ilPrev],ILS->prevLineAmpl[ilPrev]);
	printf("   to  il=%2d f=%7.1f a=%7.1f ",
	       il,lineFreq[il],lineAmpl[il]);
      }
      ILS->prevLineSyn[ilPrev] = 1;

      phi0 = ILS->prevLinePhase[ilPrev];
      phi1 = ILS->prevLineFreq[ilPrev]/ILS->fSample*2*M_PI;
      freq = lineFreq[il]/ILS->fSample*2*M_PI;
      /* phi1+2*phi2*frameLen = freq */
      phi2 = (freq-phi1)/(2*frameLen);
      phase = phi0+phi1*frameLen+phi2*frameLen*frameLen;
      if (enhaMode==0) {
	phi3 = 0;
	linePhase[il] = fmod(phase,2*M_PI);
      }
      else {
	phase += linePhaseDelta[il];
	/* phi0+phi1*frameLen+phi2*frameLen^2+phi3*frameLen^3 = phase */
	/* phi1+2*phi2*frameLen+3*phi3*frameLen^2 = freq */
	phi2 = (3*(phase-phi0-phi1*frameLen)/frameLen-(freq-phi1))/
	  frameLen;
	phi3 = ((freq-phi1)-2*(phase-phi0-phi1*frameLen)/frameLen)/
	  (frameLen*frameLen);
      }

      if ((lineEnv[il] && !ILS->longEnvIn[lineEnv[il]-1]) ||
	  (ILS->prevLineEnv[ilPrev] &&
	   !ILS->prevLongEnvOut[ILS->prevLineEnv[ilPrev]-1])) {
	/* short x-fade */
	if (ILS->debugLevel>=2)
	  printf("short x\n");
	a = ILS->prevLineAmpl[ilPrev]*AntiAlias(ILS->fSample,
						ILS->prevLineFreq[ilPrev]);
	for (i=0;i<ILS->shortOff;i++) {
	  phiT = i+0.5;
	  phi = phi0+phi1*phiT+phi2*phiT*phiT+phi3*phiT*phiT*phiT;
	  synthSignal[i] += a*cos(phi)*
	    ((ILS->prevLineEnv[ilPrev])?
	     ILS->prevEnv[ILS->prevLineEnv[ilPrev]-1][frameLen+i]:1);
	}
	for (j=0;j<frameLen-2*ILS->shortOff;j++) {
	  i = ILS->shortOff+j;
	  phiT = i+0.5;
	  phi = phi0+phi1*phiT+phi2*phiT*phiT+phi3*phiT*phiT*phiT;
	  as = ILS->prevLineAmpl[ilPrev]*
	    ((ILS->prevLineEnv[ilPrev])?
	     ILS->prevEnv[ILS->prevLineEnv[ilPrev]-1][frameLen+i]:1);
	  ae = lineAmpl[il]*
	    ((lineEnv[il])?ILS->env[lineEnv[il]-1][i]:1);
	  synthSignal[i] += AntiAlias(ILS->fSample,
				      (phi1+2*phi2*phiT+3*phi3*phiT*phiT)
				      /2/M_PI*ILS->fSample)*
	    (as+(ae-as)*((j+0.5)/(frameLen-2*ILS->shortOff)))*cos(phi);
	}
	a = lineAmpl[il]*AntiAlias(ILS->fSample,lineFreq[il]);
	for (i=frameLen-ILS->shortOff;i<frameLen;i++) {
	  phiT = i+0.5;
	  phi = phi0+phi1*phiT+phi2*phiT*phiT+phi3*phiT*phiT*phiT;
	  synthSignal[i] += a*cos(phi)*
	    ((lineEnv[il])?ILS->env[lineEnv[il]-1][i]:1);
	}
      }
      else {
	/* long x-fade */
	if (ILS->debugLevel>=2)
	  printf("long x\n");
	for (i=0;i<frameLen;i++) {
	  phiT = i+0.5;
	  phi = phi0+phi1*phiT+phi2*phiT*phiT+phi3*phiT*phiT*phiT;
	  as = ILS->prevLineAmpl[ilPrev]*
	    ((ILS->prevLineEnv[ilPrev])?
	     ILS->prevEnv[ILS->prevLineEnv[ilPrev]-1][frameLen+i]:1);
	  ae = lineAmpl[il]*
	    ((lineEnv[il])?ILS->env[lineEnv[il]-1][i]:1);
	  synthSignal[i] += AntiAlias(ILS->fSample,
				      (phi1+2*phi2*phiT+3*phi3*phiT*phiT)
				      /2/M_PI*ILS->fSample)*
	    (as+(ae-as)*((i+0.5)/frameLen))*cos(phi);
	}
      }
      if (ILS->debugLevel>=2)
	printf("p0=%9.6f p1=%9.6f p2=%9.6f p3=%9.6f\n",phi0,phi1,phi2,phi3);
    }
    else {
      /* synthesise starting line */
      if (ILS->debugLevel>=2)
	printf("start  il=%2d f=%7.1f a=%7.1f ",
	       il,lineFreq[il],lineAmpl[il]);
      if (enhaMode==0)
	if (ILDrndPhase==1)
	  linePhase[il] = 2.*M_PI*random()/(float)RND_MAX;
	else
	  linePhase[il] = M_PI/2;	/* HP 970414 changed 0 -> M_PI/2 */
      phi0 = linePhase[il];
      phi1 = lineFreq[il]/ILS->fSample*2*M_PI;
      a = lineAmpl[il]*AntiAlias(ILS->fSample,lineFreq[il]);
      if (lineEnv[il] && !ILS->longEnvIn[lineEnv[il]-1]) {
	/* short fade-in */
	if (ILS->debugLevel>=2)
	  printf("short in\n");
	for (j=0;j<frameLen-2*ILS->shortOff;j++) {
	  i = ILS->shortOff+j;
	  phiT = i-frameLen+0.5;
	  phi = phi0+phi1*phiT;
	  synthSignal[i] += a*cos(phi)*
	    ILS->shortWin[j]*((lineEnv[il])?ILS->env[lineEnv[il]-1][i]:1);
	}
	for (i=frameLen-ILS->shortOff;i<frameLen;i++) {
	  phiT = i-frameLen+0.5;
	  phi = phi0+phi1*phiT;
	  synthSignal[i] += a*cos(phi)*
	    ((lineEnv[il])?ILS->env[lineEnv[il]-1][i]:1);
	}
      }
      else {
	/* long fade-in */
	if (ILS->debugLevel>=2)
	  printf("long in\n");
	for (i=0;i<frameLen;i++) {
	  phiT = i-frameLen+0.5;
	  phi = phi0+phi1*phiT;
	  synthSignal[i] += a*cos(phi)*
	    ILS->longWin[i]*((lineEnv[il])?ILS->env[lineEnv[il]-1][i]:1);
	}
      }
      if (ILS->debugLevel>=2)
	printf("p0=%9.6f p1=%9.6f\n",phi0,phi1);
    }
  
  for (ilPrev=0;ilPrev<ILS->prevNumLine;ilPrev++)
    if (!ILS->prevLineSyn[ilPrev]) {
      /* synthesise ending line */
      if (ILS->debugLevel>=2)
	printf("  end ilp=%2d f=%7.1f a=%7.1f ",
	       ilPrev,ILS->prevLineFreq[ilPrev],ILS->prevLineAmpl[ilPrev]);
      phi0 = ILS->prevLinePhase[ilPrev];
      phi1 = ILS->prevLineFreq[ilPrev]/ILS->fSample*2*M_PI;
      a = ILS->prevLineAmpl[ilPrev]*AntiAlias(ILS->fSample,
					      ILS->prevLineFreq[ilPrev]);
      if (ILS->prevLineEnv[ilPrev] &&
	  !ILS->prevLongEnvOut[ILS->prevLineEnv[ilPrev]-1]) {
	/* short fade-out */
	if (ILS->debugLevel>=2)
	  printf("short out\n");
	for (i=0;i<ILS->shortOff;i++) {
	  phiT = i+0.5;
	  phi = phi0+phi1*phiT;
	  synthSignal[i] += a*cos(phi)*
	    ((ILS->prevLineEnv[ilPrev])?
	     ILS->prevEnv[ILS->prevLineEnv[ilPrev]-1][frameLen+i]:1);
	}
	for (j=0;j<frameLen-2*ILS->shortOff;j++) {
	  i = ILS->shortOff+j;
	  phiT = i+0.5;
	  phi = phi0+phi1*phiT;
	  synthSignal[i] += a*cos(phi)*
	    ILS->shortWin[frameLen-2*ILS->shortOff-1-j]*
	    ((ILS->prevLineEnv[ilPrev])?
	     ILS->prevEnv[ILS->prevLineEnv[ilPrev]-1][frameLen+i]:1);
	}
      }
      else {
	/* long fade-out */
	if (ILS->debugLevel>=2)
	  printf("long out\n");
	for (i=0;i<frameLen;i++) {
	  phiT = i+0.5;
	  phi = phi0+phi1*phiT;
	  synthSignal[i] += a*cos(phi)*
	    ILS->longWin[frameLen-1-i]*
	    ((ILS->prevLineEnv[ilPrev])?
	     ILS->prevEnv[ILS->prevLineEnv[ilPrev]-1][frameLen+i]:1);
	}
      }
      if (ILS->debugLevel>=2)
	printf("p0=%9.6f p1=%9.6f\n",phi0,phi1);
    }

  /* synthesise noise */
  if (numNoisePara) {
    noiseLen = 1;
    while (noiseLen<frameLen)
      noiseLen *= 2;
    for (i=0;i<numNoisePara;i++)
      ILS->noiseIdctIn[i] = noisePara[i];
    noiseBW = (int)(noiseLen*noiseFreq*2/ILS->fSample+.5);
    NoiseIdct(ILS->noiseIdctIn,ILS->noiseIdctOut,numNoisePara,
	      min(noiseLen,noiseBW),noiseBW);
    for (i=0;i<noiseLen;i++) {
      if (i<noiseBW) {
	noiseAmpl = ILS->noiseIdctOut[i];
	/* high pass and low pass */
	if (i==0 || i==noiseBW-1)
	  noiseAmpl = 0;
	if (i==1 || i==noiseBW-2)
	  noiseAmpl *= 0.3;
	if (i==2 || i==noiseBW-3)
	  noiseAmpl *= 0.7;
	noiseAmpl = max(0,noiseAmpl);	/* no negative noise ampl */
      }
      else
	noiseAmpl = 0;
      randFlt = 2.*M_PI*random()/(float)RND_MAX;
      ILS->noiseRe[i] = noiseAmpl*cos(randFlt);
      ILS->noiseIm[i] = noiseAmpl*sin(randFlt);
      ILS->noiseRe[2*noiseLen-1-i] = ILS->noiseRe[i];
      ILS->noiseIm[2*noiseLen-1-i] = -ILS->noiseIm[i];
    }
    UHD_iodft(ILS->noiseRe,ILS->noiseIm,2*noiseLen);
  }
  else
    noiseLen = 0;

  if (ILS->prevNoiseLen)
    for (i=0;i<ILS->noiseOff;i++)
      synthSignal[i] += ILS->prevNoise[i%(2*ILS->prevNoiseLen)]*
	(ILS->prevNoiseEnv?ILS->prevEnv[ILS->prevNoiseEnv-1][frameLen+i]:1);
  for (i=ILS->noiseOff;i<frameLen-ILS->noiseOff;i++) {
    if (ILS->prevNoiseLen)
      synthSignal[i] += ILS->prevNoise[i%(2*ILS->prevNoiseLen)]*
	ILS->noiseWin[frameLen-ILS->noiseOff-1-i]*
	(ILS->prevNoiseEnv?ILS->prevEnv[ILS->prevNoiseEnv-1][frameLen+i]:1);
    if (noiseLen)
      synthSignal[i] += ILS->noiseRe[2*noiseLen-frameLen+i]*
	ILS->noiseWin[i-ILS->noiseOff]*
	(noiseEnv?ILS->env[noiseEnv-1][i]:1);
  }
  if (noiseLen)
    for (i=frameLen-ILS->noiseOff;i<frameLen;i++)
      synthSignal[i] += ILS->noiseRe[2*noiseLen-frameLen+i]*
	(noiseEnv?ILS->env[noiseEnv-1][i]:1);

  if (ILS->debugLevel>=1) {
    printf("NoiseLen=%4d\n",noiseLen);
    qsNoise = 0;
    for(i=0;i<frameLen;i++)
      qsNoise += synthSignal[i]*synthSignal[i];
    printf("qsNoise=%e\n",qsNoise);
  }

  /* copy parameters into frame-to-frame memory */
  ILS->prevNumLine = numLine;
  ILS->prevNumEnv = numEnv;
  for (j=0; j<numEnv; j++)
    for (i=0;i<ENVPARANUM;i++)
      ILS->prevEnvPara[j][i] = envPara[j][i];
  for (i=0;i<numLine;i++) {
    ILS->prevLineFreq[i] = lineFreq[i];
    ILS->prevLineAmpl[i] = lineAmpl[i];
    ILS->prevLinePhase[i] = linePhase[i];
    ILS->prevLineEnv[i] = lineEnv[i];
  }
  ILS->prevNoiseLen = noiseLen;
  ILS->prevNoiseEnv = noiseEnv;
  for (i=0;i<2*noiseLen;i++)
    ILS->prevNoise[i] = -ILS->noiseRe[i];	/* odft: x[0]=-x[N] */
  
}


/* IndiLineSynthFree() */
/* Free memory allocated by IndiLineSynthInit(). */

void IndiLineSynthFree (
  ILSstatus *ILS)		/* ILS status handle */
{
  free(ILS->longWin);
  free(ILS->shortWin);
  free(ILS->noiseWin);
  free(ILS->tmpLinePhase);
  free(ILS->env[0]);
  free(ILS->env);
  free(ILS->prevEnv[0]);
  free(ILS->prevEnv);
  free(ILS->prevLineSyn);
  free(ILS->prevLongEnvOut);
  free(ILS->longEnvIn);
  free(ILS->noiseIdctIn);
  free(ILS->noiseIdctOut);
  free(ILS->noiseRe);
  free(ILS->noiseIm);
  free(ILS->prevEnvPara);
  free(ILS->prevLineFreq);
  free(ILS->prevLineAmpl);
  free(ILS->prevLinePhase);
  free(ILS->prevLineEnv);
  free(ILS->prevNoise);
  free(ILS);
}


/* end of indilinesyn.c */
