shithub: aacenc

Download patch

ref: d378fcfb11437762dc639711322a58212caf8148
parent: 0eed37002e2fdf7a89c034efa1f4d5a397e213e2
author: menno <menno>
date: Thu Jan 27 12:25:09 EST 2000

New block switching (sounds bad for now)

--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-SOURCE=aac_qc.c aac_se_enc.c bitstream.c enc_tf.c encoder.c imdct.c is.c mc_enc.c ms.c psych.c pulse.c tns.c transfo.c fastfft.c nok_ltp_enc.c nok_pitch.c
+SOURCE=aac_qc.c aac_se_enc.c bitstream.c enc_tf.c encoder.c imdct.c is.c mc_enc.c ms.c psych.c pulse.c tns.c transfo.c fastfft.c nok_ltp_enc.c nok_pitch.c winswitch.c
 
 
 OBJ = $(SOURCE:.c=.o)
--- a/enc_tf.c
+++ b/enc_tf.c
@@ -16,6 +16,7 @@
 #include "all.h"
 #include "aac_se_enc.h"
 #include "nok_ltp_enc.h"
+#include "winswitch.h"
 
 #define SQRT2 sqrt(2)
 
@@ -170,6 +171,8 @@
 	/* initialize psychoacoustic module */
 	EncTf_psycho_acoustic_init();
 
+	winSwitchInit(max_ch);
+
 	/* initialize spectrum processing */
 	/* initialize quantization and coding */
 	tf_init_encode_spectrum_aac(0);
@@ -336,34 +339,38 @@
 	* block_switch processing
 	*
 	******************************************************************************************************************************/
+	/* Window switching taken from the NTT source code in the MPEG4 VM. */
 	{
-		int chanNum = 0;
-		/* A few definitions:                                                      */
-		/*   block_type:  Initially, the block_type used in the previous frame.    */
-		/*                Will be set to the block_type to use this frame.         */
-		/*                A block type will be selected to ensure a meaningful     */
-		/*                window transition.                                       */
-		/*   next_desired_block_type:  Block_type (LONG or SHORT) which the psycho */
-		/*                model wants to use next frame.  The psycho model is      */
-		/*                using a look-ahead buffer.                               */
-		/*   desired_block_type:  Block_type (LONG or SHORT) which the psycho      */
-		/*                previously wanted to use.  It is the desired block_type  */
-		/*                for this frame.                                          */
-		if ( (block_type[chanNum]==ONLY_SHORT_WINDOW)||(block_type[chanNum]==LONG_SHORT_WINDOW) ) {
-			if ( (desired_block_type==ONLY_LONG_WINDOW)&&(next_desired_block_type==ONLY_LONG_WINDOW) ) {
-				block_type[chanNum]=SHORT_LONG_WINDOW;
-			} else {
-				block_type[chanNum]=ONLY_SHORT_WINDOW;
+		static int ntt_InitFlag = 1;
+		static double *sig_tmptmp, *sig_tmp;
+		int ismp, i_ch, top;
+		/* initialize */
+		if (ntt_InitFlag){
+			sig_tmptmp = malloc(max_ch*block_size_samples*3*sizeof(double));
+			sig_tmp = sig_tmptmp + block_size_samples * max_ch;
+			for (i_ch=0; i_ch<max_ch; i_ch++){
+				top = i_ch * block_size_samples;
+				for (ismp=0; ismp<block_size_samples; ismp++){
+					sig_tmp[ismp+top] = DTimeSigBuf[i_ch][ismp];
+				}
 			}
-		} else if (next_desired_block_type==ONLY_SHORT_WINDOW) {
-			block_type[chanNum]=LONG_SHORT_WINDOW;
-		} else {
-			block_type[chanNum]=ONLY_LONG_WINDOW;
 		}
-		desired_block_type=next_desired_block_type;
+		for (i_ch=0; i_ch<max_ch; i_ch++){
+			top = i_ch * block_size_samples;
+			for (ismp=0; ismp<block_size_samples; ismp++){
+				sig_tmp[ismp+block_size_samples*max_ch+top] =
+					DTimeSigLookAheadBuf[i_ch][ismp];
+			}
+		}
+		/* automatic switching module */
+		winSwitch(sig_tmp, &block_type[0], ntt_InitFlag);
+		for (ismp=0; ismp<block_size_samples*2*max_ch; ismp++){
+			sig_tmp[ismp-block_size_samples*max_ch] = sig_tmp[ismp];
+		}
+		ntt_InitFlag = 0;
 	}
 
-//	printf("%d %d\n", block_type[0], block_type[1]);
+//	printf("%d\n", block_type[0]);
 //	block_type[0] = ONLY_LONG_WINDOW;
 //	block_type[1] = ONLY_LONG_WINDOW;
 //	block_type[0] = ONLY_SHORT_WINDOW;
--- a/faac.dsp
+++ b/faac.dsp
@@ -154,6 +154,10 @@
 
 SOURCE=.\transfo.c
 # End Source File
+# Begin Source File
+
+SOURCE=.\winswitch.c
+# End Source File
 # End Group
 # End Target
 # End Project
--- a/faac_dll.dsp
+++ b/faac_dll.dsp
@@ -158,6 +158,10 @@
 
 SOURCE=.\transfo.c
 # End Source File
+# Begin Source File
+
+SOURCE=.\winswitch.c
+# End Source File
 # End Group
 # Begin Group "Resource Files"
 
--- /dev/null
+++ b/winswitch.c
@@ -1,0 +1,333 @@
+
+/*
+ * Window switching module
+ * Most of this has been taken from NTT source code in the MPEG-4
+ * Verification Model.
+ *
+ * TODO:
+ *  - better multi-channel support
+ */
+
+#include <math.h>
+#include "tf_main.h"
+#include "winswitch.h"
+
+#define ntt_N_SUP_MAX       2
+
+int num_channel;
+
+
+int winSwitch(/* Input */
+			double sig[],         /* input signal */
+			/* Output */
+			enum WINDOW_TYPE *w_type,     /* code index for block type */
+			/* Control */
+			int    InitFlag)/* initialization flag */
+{
+    /*--- Variables ---*/
+    int s_attack;
+	int ratio;
+
+    /*--- A.Jin 1997.10.19 ---*/
+	ratio = checkAttack(sig, &s_attack, InitFlag);
+
+    getWindowType( s_attack,  w_type, InitFlag );
+	return ratio;
+}
+
+
+void getWindowType(int flag,      /* Input : trigger for short block length */
+		 enum WINDOW_TYPE *w_type,   /* Output : code index for block type */
+		 int InitFlag ) /* Control : initialization flag */
+{
+    static int	w_type_pre;
+    static int	flag_pre;
+
+    if ( InitFlag ){
+		flag_pre = 0;
+		w_type_pre = ONLY_LONG_WINDOW;
+    }
+
+    if (InitFlag){
+		if (flag)        *w_type = ONLY_SHORT_WINDOW;
+		else             *w_type = ONLY_LONG_WINDOW;
+    }
+    else{
+		switch( w_type_pre ){
+		case ONLY_LONG_WINDOW:
+			if ( flag )      *w_type = LONG_SHORT_WINDOW;
+			else             *w_type = ONLY_LONG_WINDOW;
+			break;
+		case LONG_SHORT_WINDOW:
+			*w_type = ONLY_SHORT_WINDOW;
+			break;
+		case SHORT_LONG_WINDOW:
+			if ( flag )      *w_type = LONG_SHORT_WINDOW;
+			else             *w_type = ONLY_LONG_WINDOW;
+			break;
+		case ONLY_SHORT_WINDOW:
+			if (flag || flag_pre) *w_type = ONLY_SHORT_WINDOW;
+			else                  *w_type = SHORT_LONG_WINDOW;
+		}
+    }
+    w_type_pre = *w_type;
+    flag_pre = flag;
+}
+
+
+#define ST_CHKATK    (BLOCK_LEN_LONG/2+BLOCK_LEN_SHORT/2)
+
+#define N_BLK_MAX	4096
+#define	N_SFT_MAX   256
+#define	N_LPC_MAX	2
+
+__inline void ZeroMem(int n, double xx[])
+{
+	int i = n;
+	while(i-- != 0)
+		*(xx++) = 0.0;
+}
+
+void LagWindow(/* Output */
+                double wdw[],  /* lag window data */
+                /* Input */
+                int n,         /* dimension of wdw[.] */
+                double h)      /* ratio of window half value band width to sampling frequency */
+{
+	int i;
+	double pi=3.14159265358979323846264338327959288419716939;
+	double a,b,w;
+	if(h<=0.0) for(i=0;i<=n;i++) wdw[i]=1.0;
+	else
+	{
+		a=log(0.5)*0.5/log(cos(0.5*pi*h));
+		a=(double)((int)a);
+		w=1.0; b=a; wdw[0]=1.0;
+		for(i=1;i<=n;i++)
+		{
+			b+=1.0; w*=a/b; wdw[i]=w; a-=1.0;
+		}
+	}
+}
+
+void HammingWindow(/* Output */
+                double wdw[],  /* Hamming window data */
+                int n)         /* window length */
+{
+	int i;
+	double d,pi=3.14159265358979323846264338327950288419716939;
+	if(n>0)
+	{
+		d=2.0*pi/n;
+		for(i=0;i<n;i++)
+			wdw[i]=0.54-0.46*cos(d*i);
+	}
+}
+
+__inline void ntt_cutfr(int    st,      /* Input  --- Start point */
+	   int    len,     /* Input  --- Block length */
+	   int    ich,     /* Input  --- Channel number */
+	   double frm[],   /* Input  --- Input frame */
+	   double buf[])   /* Output --- Output data buffer */
+{
+    /*--- Variables ---*/
+    int stb, sts, edb, nblk, iblk, ibuf, ifrmb, ifrms;
+
+    stb = (st/BLOCK_LEN_LONG)*num_channel + ich;      /* start block */
+    sts = st % BLOCK_LEN_LONG;            /* start sample */
+    edb = ((st+len)/BLOCK_LEN_LONG)*num_channel + ich;        /* end block */
+    nblk = (edb-stb)/num_channel;             /* number of overflow */
+
+    ibuf=0; ifrmb=stb; ifrms=sts;
+    for ( iblk=0; iblk<nblk; iblk++ ){
+		while( ifrms < BLOCK_LEN_LONG )  buf[ibuf++] = frm[(ifrms++)+ifrmb*BLOCK_LEN_LONG];
+		ifrms = 0;
+		ifrmb += num_channel;
+    }
+    while( ibuf < len )
+		buf[ibuf++] = frm[(ifrms++)+ifrmb*BLOCK_LEN_LONG];
+}
+
+__inline void CopyMem(int n, double xx[], double yy[])
+{
+	int i = n;
+	if (i <= 0)
+		return;
+	do {
+		*(yy++) = *(xx++);
+	} while(--i);
+}
+
+__inline double DotProd(/* Input */
+                 int n,       /* dimension of data */
+                 double xx[],
+                 double yy[])
+{
+	int i;
+	double s;
+	s=0.0;
+	for(i=0;i<n;i++)
+		s+=xx[i]*yy[i];
+	return(s);
+}
+
+__inline void ntt_mulddd(/* Input */
+		int n,        /* dimension of data */
+		double xx[],
+		double yy[],
+		/* Output */
+		double zz[])
+{
+    int i;
+    for (i=0; i<n; i++ )
+		zz[i] = xx[i]*yy[i];
+}
+
+__inline void AutoCorr(double *sig, /* Input : signal sample sequence */
+		int n,       /* Input : length of sample sequence*/
+		double *_pow,/* Output : power */
+		double cor[],/* Output : autocorrelation coefficients */
+		int p)
+{
+	int k; 
+	register double sqsum,c, dsqsum;
+
+	if (n>0) {
+		sqsum = DotProd(n, sig, sig)+1.e-35;
+		dsqsum = 1./sqsum;
+		k=p;
+		do {
+			c = DotProd(n-k, sig, sig+k);
+			cor[k] = c*dsqsum;
+		}while(--k);
+	}
+	*_pow = (sqsum-1.e-35)/(double)n;
+}
+
+__inline void Corr2Ref(int p,          /* Input : LPC analysis order */
+	    double cor[],   /* Input : correlation coefficients */
+	    double alf[],   /* Output : linear predictive coefficients */
+	    double ref[],   /* Output : reflection coefficients */
+	    double *resid_) /* Output : normalized residual power */
+{
+	int i,j,k;
+	double resid,r,a;
+	if(p>0) {
+		ref[1]=cor[1];
+		alf[1]= -ref[1];
+		resid=(1.0-ref[1])*(1.0+ref[1]);
+		for(i=2;i<=p;i++) {
+			r=cor[i];
+			for(j=1;j<i;j++)
+				r+=alf[j]*cor[i-j];
+			alf[i]= -(ref[i]=(r/=resid));
+			j=0; k=i;
+			while(++j<=--k) {
+				a=alf[j];
+				alf[j]-=r*alf[k];
+				if(j<k) alf[k]-=r*a;
+			}
+			resid*=(1.0-r)*(1.0+r);
+		}
+		*resid_=resid;
+	}
+	else
+		*resid_=1.0;
+}
+
+int checkAttack(double in[],  /* Input signal */
+                  int    *flag, /* flag for attack */
+                  int    InitFlag) /* Initialization Flag */
+{
+	/*--- Variables ---*/
+	int                 n_div, iblk, ismp, ich;
+	double              bufin[N_SFT_MAX];
+	static double sig[ntt_N_SUP_MAX][N_BLK_MAX+N_LPC_MAX];
+	double        wsig[N_BLK_MAX];
+	static double wdw[N_BLK_MAX];
+	static double wlag[N_LPC_MAX+1];
+	double        cor[N_LPC_MAX+1],ref[N_LPC_MAX+1],alf[N_LPC_MAX+1];
+	static double prev_alf[ntt_N_SUP_MAX][N_LPC_MAX+1];
+	double        resid, wpowfr;
+	double        long_power;
+	double        synth, resid2;
+	static int    N_BLK, N_SFT, S_POW, L_POW, N_LPC;
+	double ratio, sum, product;
+
+	/*--- Initialization ---*/
+	if ( InitFlag ){
+		/* Set parameters */
+		N_BLK      = BLOCK_LEN_LONG;
+		N_SFT      = BLOCK_LEN_SHORT;
+		S_POW      = BLOCK_LEN_SHORT;
+		L_POW      = BLOCK_LEN_LONG;
+		N_LPC      = 1;
+		/* clear buffers */
+		for ( ich=0; ich<num_channel; ich++ ){
+			ZeroMem( N_LPC+N_BLK, sig[ich] );
+			ZeroMem( N_LPC+1, prev_alf[ich] );
+		}
+		/* set windows */
+		LagWindow( wlag, N_LPC, 0.02 );
+		HammingWindow( wdw, N_BLK );
+	}
+
+
+	n_div = BLOCK_LEN_LONG/N_SFT;
+	*flag = 0;
+	sum=0.0;
+	product=1.0;
+	for ( ich=0; ich<num_channel; ich++ ){
+		for ( iblk=0; iblk<n_div; iblk++ ){
+			ntt_cutfr( ST_CHKATK+iblk*N_SFT, N_SFT, ich, in, bufin );
+			CopyMem(N_SFT,bufin,&sig[ich][N_LPC+N_BLK-N_SFT]);
+			/*--- Calculate long power ---*/
+			long_power =
+				(DotProd( L_POW, &sig[ich][N_BLK-L_POW], &sig[ich][N_BLK-L_POW] )+0.1)
+				/ L_POW;
+			long_power = sqrt(long_power);
+
+			/*--- Calculate alpha parameter ---*/
+			ntt_mulddd( N_BLK, &sig[ich][N_LPC], wdw, wsig );
+			AutoCorr( wsig, N_BLK, &wpowfr, cor, N_LPC ); cor[0] = 1.0;
+			ntt_mulddd( N_LPC+1, cor, wlag, cor );
+			Corr2Ref( N_LPC, cor, alf, ref, &resid );
+			/*--- Get residual signal and its power ---*/
+			resid2 = 0.;
+			for ( ismp=N_BLK-S_POW; ismp<N_BLK; ismp++ ){
+				synth = sig[ich][ismp]+
+					prev_alf[ich][1]*sig[ich][ismp-1];
+				resid2 += synth*synth;
+			}
+			resid2 /= long_power;
+			resid2 = sqrt(resid2);
+			sum += resid2+0.0001;
+			product *= (resid2+0.0001);
+
+			CopyMem( N_LPC, &alf[1], &prev_alf[ich][1] );
+
+			CopyMem( N_BLK-N_SFT, &sig[ich][N_LPC+N_SFT], &sig[ich][N_LPC] );
+		}
+	}
+/*	ratio = sum/(n_div*num_channel)/pow(product, 1./(double)(n_div*num_channel)); */
+	/* This below is a bit different than the commented line above here,
+	   but I like it better this way, because it gives higher values,
+	   that are better to tune. */
+	ratio = pow(product, 1./(double)(n_div*num_channel));
+	ratio = (n_div*num_channel)/ratio;
+	ratio = sum/ratio;
+
+	if(ratio > 8000) {
+		*flag = 1;
+	} else {
+		*flag = 0;
+	}
+	return (int)(ratio+0.5);
+}
+
+
+void winSwitchInit(int max_ch)
+{
+	num_channel = max_ch;
+}
+
--- /dev/null
+++ b/winswitch.h
@@ -1,0 +1,24 @@
+
+#ifndef _WINSWITCH_H_
+#define _WINSWITCH_H_
+
+void getWindowType(int    flag,        /* Input : trigger for short block length */
+				   enum WINDOW_TYPE    *w_type,     /* Output : code index for block type*/
+				   int    InitFlag );  /* Control : initialization flag */
+
+int checkAttack(double in[],         /* Input : input signal */
+				int    *flag,/* Output : trigger for short block length */
+				int    InitFlag); /* Control : initialization flag */
+
+
+int winSwitch(/* Input */
+			  double sig[],          /* input signal */
+			  /* Output */
+			  enum WINDOW_TYPE    *w_type,     /* Output : code index for block type*/
+			  /* Control */
+			  int    InitFlag);      /* initialization flag */
+   
+void winSwitchInit(int max_ch);
+
+#endif
+