shithub: aacenc

Download patch

ref: 0d1f2bd7bb45a4915cff6f4d1d5e6a8fafb8c26a
parent: fa41e69553cba9dfbd524684c11381b7d3d7bef9
author: menno <menno>
date: Mon Jan 17 16:53:04 EST 2000

Added sampling rate conversion (-s), buggy with some sample rates

--- a/aac_qc.c
+++ b/aac_qc.c
@@ -288,7 +288,6 @@
 	return bits;
 }
 
-
 int tf_encode_spectrum_aac(
 			   double      *p_spectrum[MAX_TIME_CHANNELS],
 			   double      *PsySigMaskRatio[MAX_TIME_CHANNELS],
@@ -428,7 +427,7 @@
 	/* initialize the scale_factors that aren't intensity stereo bands */
 	is_info=&(ch_info->is_info);
 	for(k=0; k< quantInfo -> nr_of_sfb ;k++) {
-		scale_factor[k]=((is_info->is_present)&&(is_info->is_used[k])) ? scale_factor[k] : 0;
+		scale_factor[k]=((is_info->is_present)&&(is_info->is_used[k])) ? scale_factor[k] : 0/*min(15,(int)(1.0/SigMaskRatio[k]+0.5))*/;
 	}
 
 	/* Mark IS bands by setting book_vector to INTENSITY_HCB */
--- a/aacenc.h
+++ b/aacenc.h
@@ -1,5 +1,7 @@
 
 
+typedef struct RCBufStruct RCBuf;	/* buffer handle */
+
 #define MAIN_PROFILE 0
 #define LOW_PROFILE 1
 
@@ -8,9 +10,9 @@
 
 typedef struct {
 	int channels;      // Number of channels: Currently has to be 2
-	int sampling_rate; // Sampling rate
-	int bit_rate;      // Bitrate: can be: 64000, 80000, 96000, 112000, 128000, 160000
-	                   //    192000, 224000 or 256000
+	int in_sampling_rate; // Sampling rate of the input file
+	int out_sampling_rate; // Sampling rate of the output AAC file
+	int bit_rate;      // Bitrate: can be any bitrate higher than 16kbps in steps of 1kbps
 	int profile;       // AAC Profile: can be MAIN_PROFILE or LOW_PROFILE
 	int write_header;  // If this is 1, a ADIF header will be written, if it is 0, no
 	                   //    header will be written. (better turn this on, because
@@ -23,6 +25,14 @@
 	int use_PNS;       // If 1, PNS is on, if 0, it is off
 } faacAACConfig;
 
+typedef struct {
+	int DLLMajorVersion; // These 2 values should always be checked, because the DLL
+	int DLLMinorVersion; // interface can change from version to version.
+	int MajorVersion;
+	int MinorVersion;
+	char HomePage[255];
+} faacVersion;
+
 // This structure is for internal use of the encoder only.
 typedef struct {
 	long total_bits;
@@ -30,7 +40,8 @@
 	long cur_frame;
 	int is_first_frame;
 	int channels;
-	int sampling_rate;
+	int out_sampling_rate;
+	int in_sampling_rate;
 	int frame_bits;
 	int available_bits;
 	int write_header;
@@ -41,15 +52,12 @@
 	int use_PNS;
 	int profile;
 	double **inputBuffer;
+	RCBuf *rc_buf;
+	int rc_needed;
+	int samplesToRead;
+	int savedSize;
+	float saved[2048];
 } faacAACStream;
-
-typedef struct {
-	int DLLMajorVersion; // These 2 values should always be checked, because the DLL
-	int DLLMinorVersion; // interface can change from version to version.
-	int MajorVersion;
-	int MinorVersion;
-	char HomePage[255];
-} faacVersion;
 
 #ifndef FAAC_DLL
 
--- a/enc_tf.c
+++ b/enc_tf.c
@@ -119,7 +119,7 @@
 		64000,80000,96000,112000,128000,160000,192000,224000,256000,0
 	};
 
-	sampling_rate = ac->sampling_rate;
+	sampling_rate = ac->out_sampling_rate;
 	bit_rate = ac->bit_rate;
 
 	for (i = 0; ; i++)
--- a/encoder.c
+++ b/encoder.c
@@ -10,6 +10,7 @@
 
 #include "aacenc.h"
 #include "bitstream.h"	/* bit stream module */
+#include "rateconv.h"
 
 #include "enc.h"	/* encoder cores */
 
@@ -49,7 +50,8 @@
 	as->frames = 0;
 	as->cur_frame = 0;
 	as->channels = ac->channels;
-	as->sampling_rate = ac->sampling_rate;
+	as->out_sampling_rate = ac->out_sampling_rate;
+	as->in_sampling_rate = ac->in_sampling_rate;
 	as->write_header = ac->write_header;
 	as->use_MS = ac->use_MS;
 	as->use_IS = ac->use_IS;
@@ -59,6 +61,11 @@
 	as->profile = ac->profile;
 	as->is_first_frame = 1;
 
+	if (ac->in_sampling_rate != ac->out_sampling_rate)
+		as->rc_needed = 1;
+	else
+		as->rc_needed = 0;
+
 	if (as->write_header) {
 		*headerSize = 17;
 	} else {
@@ -72,8 +79,8 @@
 
 	*samplesToRead = frameNumSample * ac->channels;
 
-	as->frame_bits = (int)(ac->bit_rate*frameNumSample/ac->sampling_rate+0.5);
-	*bitBufferSize = (int)(((as->frame_bits * 2) + 7)/8);
+	as->frame_bits = (int)(ac->bit_rate*frameNumSample/ac->out_sampling_rate+0.5);
+	*bitBufferSize = (int)(((as->frame_bits * 5) + 7)/8);
 
 
 	/* num frames to start up encoder due to delay compensation */
@@ -83,87 +90,142 @@
 	as->cur_frame = -startupNumFrame;
 	as->available_bits = 8184;
 
+	if (as->rc_needed) {
+		as->rc_buf = RateConvInit (0,		/* in: debug level */
+			(double)as->out_sampling_rate/(double)as->in_sampling_rate, /* in: outputRate / inputRate */
+			as->channels,		/* in: number of channels */
+			-1,			/* in: num taps */
+			-1,			/* in: alpha for Kaiser window */
+			-1,			/* in: 6dB cutoff freq / input bandwidth */
+			-1,			/* in: 100dB cutoff freq / input bandwidth */
+			samplesToRead);		/* out: num input samples / frame */
+		as->samplesToRead = *samplesToRead;
+	} else
+		*samplesToRead = 1024*as->channels;
+
+	as->savedSize = 0;
+
 	return as;
 }
 
 int faacEncodeFrame(faacAACStream *as, short *Buffer, int Samples, unsigned char *bitBuffer, int *bitBufSize)
 {
-	int i, error;
+	int i, j, error;
 	int usedNumBit, usedBytes;
+	int savedSamplesOut, samplesOut, curSample = 0;
 	BsBitStream *bitBuf;
+	float *dataOut;
+	float *data = NULL;
+	int totalBytes = 0;
 
 	// Is this the last (incomplete) frame
-	if ((Samples < 1024*as->channels)&&(Samples > 0)) {
+	if ((Samples < as->samplesToRead)&&(Samples > 0)) {
 		// Padd with zeros
-		memset(Buffer + Samples, 0, (2048-Samples)*sizeof(short));
+		memset(Buffer + Samples, 0, (as->samplesToRead-Samples)*sizeof(short));
 	}
 
-	// Process Buffer
-	if (Buffer) {
-		if (as->channels == 2)
-		{
-			if (Samples > 0)
-				for (i = 0; i < 1024; i++)
-				{
-					as->inputBuffer[0][i] = *Buffer++;
-					as->inputBuffer[1][i] = *Buffer++;
-				}
-				else // (Samples == 0) when called by faacEncodeFinish
+	if (as->rc_needed && (Samples > 0)) {
+		savedSamplesOut = samplesOut = as->savedSize + RateConv (
+			as->rc_buf,			/* in: buffer (handle) */
+			Buffer,		/* in: input data[] */
+			as->samplesToRead,		/* in: number of input samples */
+			&dataOut);
+
+		data = malloc((samplesOut)*sizeof(float));
+		for (i = 0; i < as->savedSize; i++)
+			data[i] = as->saved[i];
+		for (j = 0; i < samplesOut; i++, j++)
+			data[i] = dataOut[j];
+	} else if (Samples > 0) {
+		samplesOut = 1024*as->channels;
+		data = malloc((samplesOut)*sizeof(float));
+		for (i = 0; i < samplesOut; i++)
+			data[i] = Buffer[i];
+	}
+
+	while(samplesOut >= 1024*as->channels)
+	{
+
+		// Process Buffer
+		if (Buffer) {
+			if (as->channels == 2)
+			{
+				if (Samples > 0)
 					for (i = 0; i < 1024; i++)
 					{
-						as->inputBuffer[0][i] = 0;
-						as->inputBuffer[1][i] = 0;
+						as->inputBuffer[0][i] = data[curSample+(i*2)];
+						as->inputBuffer[1][i] = data[curSample+(i*2)+1];
 					}
-		} else {
-			// No mono supported yet (basically only a problem with decoder
-			// the encoder in fact supports it).
-			return FERROR;
+					else // (Samples == 0) when called by faacEncodeFinish
+						for (i = 0; i < 1024; i++)
+						{
+							as->inputBuffer[0][i] = 0;
+							as->inputBuffer[1][i] = 0;
+						}
+			} else {
+				// No mono supported yet (basically only a problem with decoder
+				// the encoder in fact supports it).
+				return FERROR;
+			}
 		}
-	}
 
-	if (as->is_first_frame) {
-		EncTfFrame(as, (BsBitStream*)NULL);
+#if 0
+		if (as->is_first_frame) {
+			EncTfFrame(as, (BsBitStream*)NULL);
 
-		as->is_first_frame = 0;
-		as->cur_frame++;
+			as->is_first_frame = 0;
+			as->cur_frame++;
 
-		*bitBufSize = 0;
+			*bitBufSize = 0;
 
-		return FNO_ERROR;
-	}
+			return FNO_ERROR;
+		}
+#endif
 
-	bitBuf = BsOpenWrite(as->frame_bits * 10);
+		bitBuf = BsOpenWrite(as->frame_bits * 10);
 
-	/* compute available number of bits */
-	/* frameAvailNumBit contains number of bits in reservoir */
-	/* variable bit rate: don't exceed bit reservoir size */
-	if (as->available_bits > 8184)
-		as->available_bits = 8184;
+		/* compute available number of bits */
+		/* frameAvailNumBit contains number of bits in reservoir */
+		/* variable bit rate: don't exceed bit reservoir size */
+		if (as->available_bits > 8184)
+			as->available_bits = 8184;
 		
-	/* Add to frameAvailNumBit the number of bits for this frame */
-	as->available_bits += as->frame_bits;
+		/* Add to frameAvailNumBit the number of bits for this frame */
+		as->available_bits += as->frame_bits;
 
-	/* Encode frame */
-	error = EncTfFrame(as, bitBuf);
+		/* Encode frame */
+		error = EncTfFrame(as, bitBuf);
 
-	if (error == FERROR)
-		return FERROR;
+		if (error == FERROR)
+			return FERROR;
 
-	usedNumBit = BsBufferNumBit(bitBuf);
-	as->total_bits += usedNumBit;
+		usedNumBit = BsBufferNumBit(bitBuf);
+		as->total_bits += usedNumBit;
 
-	// Copy bitBuf into bitBuffer here
-	usedBytes = (int)((usedNumBit+7)/8);
-	*bitBufSize = usedBytes;
-	for (i = 0; i < usedBytes; i++)
-		bitBuffer[i] = bitBuf->data[i];
-	BsClose(bitBuf);
+		// Copy bitBuf into bitBuffer here
+		usedBytes = (int)((usedNumBit+7)/8);
+		for (i = 0; i < usedBytes; i++)
+			bitBuffer[i+totalBytes] = bitBuf->data[i];
+		totalBytes += usedBytes;
+		BsClose(bitBuf);
 
-	/* Adjust available bit counts */
-	as->available_bits -= usedNumBit;    /* Subtract bits used */
+		/* Adjust available bit counts */
+		as->available_bits -= usedNumBit;    /* Subtract bits used */
 
-	as->cur_frame++;
+		as->cur_frame++;
 
+		samplesOut -= (as->channels*1024);
+		curSample  += (as->channels*1024);
+
+	}
+
+	*bitBufSize = totalBytes;
+
+	as->savedSize = samplesOut;
+	for (i = 0; i < samplesOut; i++)
+		as->saved[i] = data[curSample+i];
+	if (data) free(data);
+
 	return FNO_ERROR;
 }
 
@@ -188,11 +250,13 @@
 	float seconds;
 	int bits, bytes, ch;
 
-	seconds = (float)as->sampling_rate/(float)1024;
+	seconds = (float)as->out_sampling_rate/(float)1024;
 	seconds = (float)as->cur_frame/seconds;
 
 	/* free encoder memory */
 	EncTfFree();
+	if (as->rc_needed)
+		RateConvFree (as->rc_buf);
 
 	if (as->write_header)
 	{
@@ -205,7 +269,7 @@
 
 		for (i = 0; ; i++)
 		{
-			if (SampleRates[i] == as->sampling_rate)
+			if (SampleRates[i] == as->out_sampling_rate)
 				break;
 			else if (SampleRates[i] == 0)
 			{
@@ -340,6 +404,7 @@
 	printf(" -np   Don't use LTP (Long Term Prediction).\n");
 	printf(" -nh   No header will be written to the AAC file.\n");
 	printf(" -oX   Set output directory.\n");
+	printf(" -sX   Set output sampling rate.\n");
 	printf(" -r    Use raw data input file.\n");
 	printf(" file  Multiple files can be given as well as wild cards.\n");
 	printf("       Can be any of the filetypes supported by libsndfile\n");
@@ -354,7 +419,7 @@
 {
 	int readNumSample;
 
-	short sampleBuffer[2048];
+	short *sampleBuffer;
 	unsigned char *bitBuffer = NULL;
 	FILE *aacfile;
 	SNDFILE *sndfile;
@@ -369,6 +434,7 @@
 	int no_header = 0;
 	int use_IS = 0, use_MS = 0, use_TNS = 1, use_LTP = 1, use_PNS = 0;
 	int bit_rate = 128;
+	int out_rate = 0;
 	char out_dir[255];
 	int out_dir_set = 0;
 	int raw_audio = 0;
@@ -481,6 +547,10 @@
 			case 'B':
 				bit_rate = atoi(&argv[i][2]);
 				break;
+			case 's':
+			case 'S':
+				out_rate = atoi(&argv[i][2]);
+				break;
 			case 'o':
 			case 'O':
 				out_dir_set = 1;
@@ -541,7 +611,8 @@
 		}
 
 		ac.channels = sf_info.channels;
-		ac.sampling_rate = sf_info.samplerate;
+		ac.in_sampling_rate = sf_info.samplerate;
+		ac.out_sampling_rate = out_rate ? out_rate : sf_info.samplerate;
 		ac.bit_rate = bit_rate * 1000;
 		ac.profile = profile;
 		ac.use_MS = use_MS;
@@ -556,6 +627,7 @@
 			printf("Error while encoding %s.\n", FileNames[i]);
 			continue;
 		}
+		sampleBuffer = malloc(readNumSample*sizeof(short));
 
 		bitBuffer = malloc((bitBufSize+100)*sizeof(char));
 
@@ -614,6 +686,7 @@
 
 		fclose(aacfile);
 		if (bitBuffer) { free(bitBuffer); bitBuffer = NULL; }
+		if (sampleBuffer) { free(sampleBuffer); sampleBuffer = NULL; }
 
 #ifdef WIN32
 		end = GetTickCount();
--- a/faac.dsp
+++ b/faac.dsp
@@ -144,6 +144,10 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\rateconv.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\tns.c
 # End Source File
 # Begin Source File
--- a/faac_dll.dsp
+++ b/faac_dll.dsp
@@ -148,6 +148,10 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\rateconv.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\tns.c
 # End Source File
 # Begin Source File
--- /dev/null
+++ b/rateconv.c
@@ -1,0 +1,810 @@
+/**********************************************************************
+audio sample rate converter
+
+$Id: rateconv.c,v 1.1 2000/01/17 21:53:04 menno Exp $
+
+Source file: rateconv.c
+
+Authors:
+NM    Nikolaus Meine, Uni Hannover (c/o Heiko Purnhagen)
+HP    Heiko Purnhagen, Uni Hannover <purnhage@tnt.uni-hannover.de>
+
+Changes:
+xx-jun-98   NM      resamp.c
+18-sep-98   HP      converted into module
+03-aug-99   NM      now even faster ...
+04-nov-99   NM/HP   double ratio, htaps1 /= 2
+11-nov-99   HP      improved RateConvInit() debuglevel
+**********************************************************************/
+
+/*
+ * Sample-rate converter
+ *
+ * Realized in three steps:
+ *
+ * 1. Upsampling by factor two while doing appropriate lowpass-filtering.
+ *    This is done by using an FFT-based convolution algorithm with a multi-tap
+ *    Kaiser-windowed lowpass filter.
+ *    If the cotoff-frequency is less than 0.5, only lowpass-filtering without
+ *    the upsampling is done.
+ * 2. Upsampling by factor 128 using a 15 tap Kaiser-windowed lowpass filter
+ *    (alpha=12.5) and conventional convolution algorithm.
+ *    Two values (the next neighbours) are computed for every sample needed.
+ * 3. Linear interpolation between the two bounding values.
+ *
+ * Stereo and mono data is supported.
+ * Up- and downsampling of any ratio is possible.
+ * Input and output file format is Sun-audio.
+ *
+ * Written by N.Meine, 1998
+ *
+ */
+
+/* Multi channel data is interleaved: l0 r0 l1 r1 ... */
+/* Total number of samples (over all channels) is used. */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+
+#include "aacenc.h"
+#include "rateconv.h"
+
+/* ---------- declarations ---------- */
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef min
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+/* ---------- declarations (structures) ---------- */
+
+#define real	double	/* float seems to be precise enough, but it	*/
+			/* doesn't run much faster than double		*/
+
+typedef struct {
+	real	re,im;
+} complex;
+
+
+struct RCBufStruct		/* buffer handle */
+{
+  int numChannel;		/* number of channels */
+  long currentSampleIn;		/* number of input samples */
+  long currentSampleOut;	/* number of output samples */
+
+  real *wtab;
+  complex *x;
+  real *tp1;
+  real *tp2;
+  complex *ibuf;
+
+  long nfn;
+  long adv;
+  long istart;
+  long numode;
+  long fm;
+  double p1;
+  double d1;
+
+  long outSize;
+  float *out;
+};
+
+
+/* ---------- variables ---------- */
+
+static int RCdebugLevel = 0;	/* debug level */
+
+
+#define deftaps1	485
+
+#define ov2exp	7		/* Oversampling exponent in the second step */
+#define ov2fac	(1<<ov2exp)	/* Oversampling factor in the second step */
+#define htaps2	7		/* Num. taps of the 2nd filter: 2*htaps2+1 */
+#define alpha2	12.5		/* Kaiser-parameter for the second filter */
+#define cutoff2	0.97		/* cutoff-frequency for the second filter */
+
+#define cexp	(CACHE1-(sizeof(real)==4 ? 3 : 4 ))
+#define cache	(1<<cexp)
+
+#define pi	3.1415926535897932
+#define zpi	6.2831853071795965
+
+
+/* ---------- local functions ---------- */
+
+
+static void mkeiwutab(real *st,long fn)
+{
+	register int	i,k;
+	register double	phi;
+
+	for (k=fn; k; k>>=1)
+	{
+		phi = zpi/((double) k);
+		for (i=0; i<k; i++) st[i]=(real) sin(phi*((double) i));
+		st+=k;
+	}
+}
+
+static void r4fftstep(register real *x0,register long n,register real *t)
+{
+	register long		n4 = n/4;
+	register real		*x1 = x0+2*n4;
+	register real		*x2 = x1+2*n4;
+	register real		*x3 = x2+2*n4;
+	register real		*y;
+	register real		wr,wi,ar,ai,br,bi,cr,ci,dr,di,hr,hi;
+	register long		i;
+
+
+	if ( n>16 )
+	{
+		y=t+6*n4;
+		r4fftstep(x0,n4,y);
+		r4fftstep(x1,n4,y);
+		r4fftstep(x2,n4,y);
+		r4fftstep(x3,n4,y);
+	}
+	else
+	{
+		if ( n==8 )
+		{
+			for (y=x0; y<x0+16; y+=4)
+			{
+				ar=y[0]; ai=y[1];
+				br=y[2]; bi=y[3];
+				y[0]=ar+br;
+				y[1]=ai+bi;
+				y[2]=ar-br;
+				y[3]=ai-bi;
+			}
+		}
+		else
+		{
+			for (y=x0; y<x0+32; y+=8)
+			{
+				ar=y[0]; ai=y[1];
+				br=y[2]; bi=y[3];
+				cr=y[4]; ci=y[5];
+				dr=y[6]; di=y[7];
+				hr=ar+cr; wr=ar-cr; hi=ai+ci; wi=ai-ci;
+				ar=br+dr; cr=br-dr; ai=bi+di; ci=bi-di;
+				y[0]=hr+ar; y[1]=hi+ai;
+				y[2]=wr+ci; y[3]=wi-cr;
+				y[4]=hr-ar; y[5]=hi-ai;
+				y[6]=wr-ci; y[7]=wi+cr;
+			}
+		}
+	}
+
+	y=t+n4;
+	for (i=0; i<n4; i++)
+	{
+		ar=x0[0]; ai=x0[1];
+		wr=y[  i]; wi=t[  i]; hr=x1[0]; hi=x1[1]; br=wr*hr+wi*hi; bi=wr*hi-wi*hr;
+		wr=y[2*i]; wi=t[2*i]; hr=x2[0]; hi=x2[1]; cr=wr*hr+wi*hi; ci=wr*hi-wi*hr;
+		wr=y[3*i]; wi=t[3*i]; hr=x3[0]; hi=x3[1]; dr=wr*hr+wi*hi; di=wr*hi-wi*hr;
+		hr=ar+cr; wr=ar-cr; hi=ai+ci; wi=ai-ci;
+		ar=br+dr; cr=br-dr; ai=bi+di; ci=bi-di;
+		x0[0]=hr+ar; x0[1]=hi+ai;
+		x1[0]=wr+ci; x1[1]=wi-cr;
+		x2[0]=hr-ar; x2[1]=hi-ai;
+		x3[0]=wr-ci; x3[1]=wi+cr;
+		x0+=2; x1+=2; x2+=2; x3+=2;
+	}
+}
+
+
+static void r4ifftstep(register real *x0,register long n,register real *t)
+{
+	register long		n4 = n/4;
+	register real		*x1 = x0+2*n4;
+	register real		*x2 = x1+2*n4;
+	register real		*x3 = x2+2*n4;
+	register real		*y;
+	register real		wr,wi,ar,ai,br,bi,cr,ci,dr,di,hr,hi;
+	register long		i;
+
+	if ( n>16 )
+	{
+		y=t+6*n4;
+		r4ifftstep(x0,n4,y);
+		r4ifftstep(x1,n4,y);
+		r4ifftstep(x2,n4,y);
+		r4ifftstep(x3,n4,y);
+	}
+	else
+	{
+		if ( n==8 )
+		{
+			for (y=x0; y<x0+16; y+=4)
+			{
+				ar=y[0]; ai=y[1];
+				br=y[2]; bi=y[3];
+				y[0]=ar+br;
+				y[1]=ai+bi;
+				y[2]=ar-br;
+				y[3]=ai-bi;
+			}
+		}
+		else
+		{
+			for (y=x0; y<x0+32; y+=8)
+			{
+				ar=y[0]; ai=y[1];
+				br=y[2]; bi=y[3];
+				cr=y[4]; ci=y[5];
+				dr=y[6]; di=y[7];
+				hr=ar+cr; wr=ar-cr; hi=ai+ci; wi=ai-ci;
+				ar=br+dr; cr=br-dr; ai=bi+di; ci=bi-di;
+				y[0]=hr+ar; y[1]=hi+ai;
+				y[2]=wr-ci; y[3]=wi+cr;
+				y[4]=hr-ar; y[5]=hi-ai;
+				y[6]=wr+ci; y[7]=wi-cr;
+			}
+		}
+	}
+
+	y=t+n4;
+	for (i=0; i<n4; i++)
+	{
+		ar=x0[0]; ai=x0[1];
+		wr=y[  i]; wi=t[  i]; hr=x1[0]; hi=x1[1]; br=wr*hr-wi*hi; bi=wr*hi+wi*hr;
+		wr=y[2*i]; wi=t[2*i]; hr=x2[0]; hi=x2[1]; cr=wr*hr-wi*hi; ci=wr*hi+wi*hr;
+		wr=y[3*i]; wi=t[3*i]; hr=x3[0]; hi=x3[1]; dr=wr*hr-wi*hi; di=wr*hi+wi*hr;
+		hr=ar+cr; wr=ar-cr; hi=ai+ci; wi=ai-ci;
+		ar=br+dr; cr=br-dr; ai=bi+di; ci=bi-di;
+		x0[0]=hr+ar; x0[1]=hi+ai;
+		x1[0]=wr-ci; x1[1]=wi+cr;
+		x2[0]=hr-ar; x2[1]=hi-ai;
+		x3[0]=wr+ci; x3[1]=wi-cr;
+		x0+=2; x1+=2; x2+=2; x3+=2;
+	}
+}
+
+
+static void perm4(real *x,long p)
+{
+	register real	a,b,c,d;
+	register long	i,j,k,l;
+
+	l=1<<(p-1);
+	for (i=j=0; i<(2<<p); i+=2)
+	{
+		if ( j>i )
+		{
+			a=x[i]; b=x[i+1]; c=x[j]; d=x[j+1]; x[j]=a; x[j+1]=b; x[i]=c; x[i+1]=d;	
+		}
+		j+=l;
+		for (k=l<<2; j&k; k>>=2) j=(j^=k)+(k>>4);
+	}
+}
+
+static void perm42(real *x,long p)
+{
+	register real	*y,*z;
+	register long	i,n;
+
+	n=1<<p;
+	perm4(x  ,p-1);
+	perm4(x+n,p-1);
+
+	y=x+2*n;
+	z=x+n;
+	for (i=0; i<n; i+=2)
+	{
+		y[2*i  ]=x[i  ];
+		y[2*i+1]=x[i+1];
+		y[2*i+2]=z[i  ];
+		y[2*i+3]=z[i+1];
+		x[i  ]=y[i  ];
+		x[i+1]=y[i+1];
+	}
+	for (; i<2*n; i+=2)
+	{
+		x[i  ]=y[i  ];
+		x[i+1]=y[i+1];
+	}
+}
+
+static void r4fft(real *t,real *x,long p)
+{
+	register long	n  = 1<<p;
+
+	if ( p&1 ) perm42(x,p); else perm4(x,p);
+	r4fftstep(x,n,t);
+}
+
+static void r4ifft(real *t,real *x,long p)
+{
+	register long	n  = 1<<p;
+
+	if ( p&1 ) perm42(x,p); else perm4(x,p);
+	r4ifftstep(x,n,t);
+}
+
+
+static double bessel(double x)
+{
+  register double	p,s,ds,k;
+
+  x*=0.5;
+  k=0.0;
+  p=s=1.0;
+  do
+    {
+      k+=1.0;
+      p*=x/k;
+      ds=p*p;
+      s+=ds;
+    }
+  while ( ds>1.0e-17*s ); 
+
+  return s;
+}
+
+static void mktp1(complex *y,double fg,double a,long fn,long htaps1)
+{
+  register long	i;
+  register double	f,g,x,px;
+
+  y[0].re=fg;
+  y[0].im=0.0;
+
+  f=1.0/bessel(a);
+  g=1.0/(htaps1+0.5);
+  g*=g;
+
+  for (i=1; i<=htaps1; i++)
+    {
+      x=(double) i;
+      px=pi*x;
+      y[i].re=(real) f*bessel(a*sqrt(1.0-g*x*x))*sin(fg*px)/px;
+      y[i].im=(real) 0.0;
+      y[fn-i]=y[i];
+    }
+  for (; i<fn-htaps1; i++) y[i].re=y[i].im=0.0;
+}
+
+static void mktp2(real *y,double fg,double a)
+{
+  register long	i;
+  register double	f,g,x,px;
+
+  y[0]=fg;
+
+  f=1.0/bessel(a);
+  g=1.0/(((double) ((htaps2+1)*ov2fac))-0.5);
+  g*=g;
+
+  for (i=1; i<(htaps2+1)*ov2fac; i++)
+    {
+      x=(double) i;
+      px=(pi/ov2fac)*x;
+      y[i]=(real) f*bessel(a*sqrt(1.0-g*x*x))*sin(fg*px)/px;
+    }
+  for (; i<(htaps2+2)*ov2fac; i++) y[i]=0.0;
+}
+
+static void ctp2_m(real *x,double p,real *k,float **out)
+{
+  register long	n,i,j;
+  register double	h,l,r;
+  register real	*ka,*kb;
+  register real	*xa,*xb;
+
+  h=ov2fac*p;
+  i=(long) h;
+  h-=(double) i;
+
+  j=i&(ov2fac-1); i>>=ov2exp;
+
+  l=r=0.0;
+  ka=k+j;	kb=k+ov2fac-j;
+  i<<=1;
+  xa=x+i;	xb=x+i+2;
+
+  n=htaps2+1;
+  do
+    {
+      l+=xa[0]*ka[ 0] + xb[0]*kb[ 0];
+      r+=xa[0]*ka[ 1] + xb[0]*kb[-1];
+
+      ka+=ov2fac;
+      kb+=ov2fac;
+      xa-=2;
+      xb+=2;
+    }
+  while (--n);
+
+  *(*out)++ = (float) (l+h*(r-l));
+}
+
+static void ctp2_s(complex *x,double p,real *k,float **out)
+{
+  register long	n,i,j;
+  register double	h,l0,l1,r0,r1;
+  register real	*ka,*kb;
+  register complex *xa,*xb;
+
+  h=ov2fac*p;
+  i=(long) h;
+  h-=(double) i;
+
+  j=i&(ov2fac-1); i>>=ov2exp;
+
+  l0=l1=r0=r1=0.0;
+  ka=k+j;	kb=k+ov2fac-j;
+  xa=x+i;	xb=x+i+1;
+
+  n=htaps2+1;
+  do
+    {
+      l0+=xa[0].re*ka[ 0] + xb[0].re*kb[ 0];
+      l1+=xa[0].im*ka[ 0] + xb[0].im*kb[ 0];
+      r0+=xa[0].re*ka[ 1] + xb[0].re*kb[-1];
+      r1+=xa[0].im*ka[ 1] + xb[0].im*kb[-1];
+
+      ka+=ov2fac;
+      kb+=ov2fac;
+      xa--;
+      xb++;
+    }
+  while (--n);
+
+  *(*out)++ = (float) (l0+h*(r0-l0));
+  *(*out)++ = (float) (l1+h*(r1-l1));
+}
+
+static void ctp1_1(complex *x,real *tp1,real *wtab,long fm)
+{
+  register long	i,fn2;
+
+  fn2=1<<(fm-1);
+  r4fft(wtab,(real *) x,fm);
+  for (i=0; i<fn2; i++)
+    {
+      x[i+fn2].re*=tp1[fn2-i];
+      x[i+fn2].im*=tp1[fn2-i];
+      x[i    ].re*=tp1[i    ];
+      x[i    ].im*=tp1[i    ];
+    }
+  r4ifft(wtab,(real *) x,fm);
+}
+
+static void ctp1_2(complex *x,real *tp1,real *wtab,long fm)
+{
+  register long	i,fn2;
+
+  fn2=1<<(fm-1);
+
+  r4fft(wtab+(1<<fm),(real *) x,fm-1);
+  for (i=0; i<fn2; i++)
+    {
+      x[i+fn2].re=x[i].re*tp1[fn2-i];
+      x[i+fn2].im=x[i].im*tp1[fn2-i];
+      x[i].re*=tp1[i];
+      x[i].im*=tp1[i];
+    }
+  r4ifft(wtab,(real *) x,fm);
+}
+
+
+/* ---------- functions ---------- */
+
+/* RateConvInit() */
+/* Init audio sample rate conversion. */
+
+RCBuf *RateConvInit (
+  int debugLevel,		/* in: debug level */
+				/*     0=off  1=basic  2=full */
+  double ratio,			/* in: outputRate / inputRate */
+  int numChannel,		/* in: number of channels */
+  int htaps1,			/* in: num taps */
+				/*      -1 = auto */
+  float a1,			/* in: alpha for Kaiser window */
+				/*      -1 = auto */
+  float fc,			/* in: 6dB cutoff freq / input bandwidth */
+				/*      -1 = auto */
+  float fd,			/* in: 100dB cutoff freq / input bandwidth */
+				/*      -1 = auto */
+  long *numSampleIn)		/* out: num input samples / frame */
+				/* returns: */
+				/*  buffer (handle) */
+				/*  or NULL if error */
+{
+  real *wtab;
+  complex *x;
+  real *tp1;
+  real *tp2;
+  complex *ibuf;
+
+  long nfn;
+  long adv;
+  long istart;
+  long numode;
+  long fm;
+  double p1;
+  double d1;
+
+  double sf2;
+  double trw2;
+  long fn;
+  long fn2;
+  long i;
+  double h;
+  double a;
+
+  RCBuf *buf;
+
+  RCdebugLevel = debugLevel;
+  if (RCdebugLevel)
+    printf("RateConvInit: debugLevel=%d ratio=%f numChannel=%d\n"
+	   "htaps1=%d a1=%f fc=%f fd=%f\n",
+	   RCdebugLevel,ratio,numChannel,htaps1,a1,fc,fd);
+
+  buf=(RCBuf*)malloc(sizeof(RCBuf));
+//  if (!(buf=(RCBuf*)malloc(sizeof(RCBuf))))
+//    CommonExit(-1,"RateConvInit: Can not allocate memory");
+  buf->currentSampleIn = 0;
+  buf->currentSampleOut = 0;
+  buf->numChannel = numChannel;
+
+  if (htaps1<0)
+    htaps1 = deftaps1;
+  htaps1 /= 2;	/* NM 991104 */
+  if (a1<0)
+    a1 = 10.0;
+  numode = 0;
+  for (fm=2; (1<<fm)<8*htaps1; fm+=2);
+  fn=1<<fm;
+  fn2=fn/2;
+
+  wtab=(real *) malloc((4*fn + fn2+1 + (htaps2+2)*ov2fac)*sizeof(real));
+//  if (!(wtab=
+//	(real *) malloc((4*fn + fn2+1 + (htaps2+2)*ov2fac)*sizeof(real))))
+//    CommonExit(-1,"RateConvInit: Can not allocate memory");
+  x=((complex *) wtab)+fn;
+  tp1=(real *) (x+fn);
+  tp2=tp1+fn2+1;
+
+  mkeiwutab(wtab,fn);
+  mktp1(x,0.5,a1,fn,htaps1);
+  r4fft(wtab,(real *) x,fm);
+  h=x[0].re*x[0].re*1.0e-10;
+  for (i=fn/2; x[i].re*x[i].re<h; i--);
+  trw2=((double) (i-(fn2/2)))/((double) (fn2/2));
+
+  sf2 = ratio;
+  if ( sf2<0.0 ) sf2=1.0;
+
+  d1=1.0/sf2;
+  p1=htaps1+htaps2+2;		/* delay compensation */
+
+  if ( fc<0.0 )
+    {
+      if ( fd<0.0 )
+	{
+	  fc=1.0/d1-trw2;
+	  if ( fc<0.5-0.5*trw2 ) { numode=1; fc=2.0/d1-trw2; }
+	  if ( fc>1.0-trw2 ) fc=1.0-trw2;
+	}
+      else
+	{
+	  fc=fd-trw2;
+	  if ( fd<=0.5 ) { numode=1; fc=2.0*fd-trw2; }
+	}
+    }
+  else
+    {
+      if ( fc<0.5-trw2 ) { numode=1; fc+=fc; }
+    }
+
+  if ( fc>2.0 ) fc=2.0;
+
+  if ( fc<=0.0 ) {
+//    CommonWarning("RateConvInit: cutoff frequency to low: %f %f %f\n",
+//		  fc,fd,trw2);
+    free(wtab);
+    free(buf);
+    return NULL;
+  }
+
+  nfn=fn;
+  adv=fn-2*(htaps1+htaps2+2);
+  istart=htaps1+htaps2+2;
+  if ( !numode ) { nfn>>=1; adv>>=1; d1+=d1; }
+
+  mktp1(x,0.5*fc,a1,fn,htaps1);
+  r4fft(wtab,(real *) x,fm);
+  a=1.0/((double) (((1+numode)*fn2)));
+  for (i=0; i<=fn2 ; i++) tp1[i]=a*x[i].re;
+
+  mktp2(tp2,cutoff2,alpha2);
+
+  *numSampleIn = 2*adv;
+  buf->outSize = (long)((2*adv+4)*ratio+4);
+  buf->out=(float*)malloc(buf->outSize*sizeof(float));
+//  if (!(buf->out=(float*)malloc(buf->outSize*sizeof(float))))
+//    CommonExit(-1,"RateConvInit: Can not allocate memory");
+
+  ibuf = (complex *) malloc((nfn-adv)*sizeof(complex));
+//  if (!(ibuf = (complex *) malloc((nfn-adv)*sizeof(complex))))
+//    CommonExit(-1,"RateConvInit: Can not allocate memory");
+
+
+  if ( buf->numChannel==1 ) {
+    /* ibuf[?].im not used ... */
+    for (i=0; i<(nfn-adv)/2; i++)
+      ibuf[i].re=0.0;
+    for (   ; i<(nfn-adv)  ; i++)
+      ibuf[i].re=0.0;
+    /* ibuf[i].re=(real) dataIn[idxIn++]; */
+  }
+  else {
+    for (i=0; i<  (nfn-adv); i++)
+      ((real *) ibuf)[i]=0.0;
+    for (   ; i<2*(nfn-adv); i++)
+      ((real *) ibuf)[i]=0.0;
+    /* ((real *) ibuf)[i]=(real) dataIn[idxIn++]; */
+  }
+
+  if (RCdebugLevel)
+    printf("RateConvInit: inSize=%ld outSize=%ld\n"
+	   "  output/input ratio : %8.2f\n"
+	   "  cutoff frequency   : %10.4f\n"
+	   "  Kaiser parameter   : %10.4f\n"
+	   "  filter 1 taps      : %5li\n"
+	   "  filter 1 transition: %10.4f\n"
+	   "  FFT length         : %5li\n"
+	   "  oversampling factor: %5li\n",
+	   2*adv,buf->outSize,
+	   sf2,fc/(1+numode),a1,(long)2*htaps1+1,0.5*trw2,
+	   fn,ov2fac*(2-numode));
+
+  buf->wtab = wtab;
+  buf->x= x;
+  buf->tp1 = tp1;
+  buf->tp2 = tp2;
+  buf->ibuf = ibuf;
+
+  buf->nfn = nfn;
+  buf->adv = adv;
+  buf->istart = istart;
+  buf->numode = numode;
+  buf->fm = fm;
+  buf->p1 = p1;
+  buf->d1 = d1;
+
+  return buf;
+}
+
+
+/* RateConv() */
+/* Convert sample rate for one frame of audio data. */
+
+long RateConv (
+  RCBuf *buf,			/* in: buffer (handle) */
+  short *dataIn,		/* in: input data[] */
+  long numSampleIn,		/* in: number of input samples */
+  float **dataOut)		/* out: output data[] */
+				/* returns: */
+				/*  numSampleOut */
+{
+  real *wtab = buf->wtab;
+  complex *x = buf->x;
+  real *tp1 = buf->tp1;
+  real *tp2 = buf->tp2;
+  complex *ibuf = buf->ibuf;
+
+  long nfn = buf->nfn;
+  long adv = buf->adv;
+  long istart = buf->istart;
+  long numode = buf->numode;
+  long fm = buf->fm;
+  double p1 = buf->p1;
+  double d1 = buf->d1;
+
+  long i;
+  double p,h;
+
+  long idxIn,numOut;
+  float *out;
+
+  if (RCdebugLevel)
+    printf("RateConv: numSampleIn=%ld\n",numSampleIn);
+
+//  if (numSampleIn != 2*adv)
+//    CommonExit(-1,"RateConv: wrong numSampleIn");
+
+  idxIn = 0;
+  out = buf->out;
+
+  if ( buf->numChannel==1 ) {
+    /* ibuf[?].im not used ... */
+    for (i=0      ; i<nfn-adv; i++)
+      x[i].re=ibuf[i].re;
+    for (         ; i<    adv; i++)
+      x[i].re=(real) dataIn[idxIn++];
+    for (         ; i<    nfn; i++)
+      x[i].re=x[i-adv].im=(real) dataIn[idxIn++];
+    for (i=nfn-adv; i<    adv; i++)
+      x[i].im=(real) dataIn[idxIn++];
+    for (         ; i<    nfn; i++)
+      x[i].im=ibuf[i-adv].re=(real) dataIn[idxIn++];
+      
+    if ( numode )
+      ctp1_1(x,tp1,wtab,fm);
+    else
+      ctp1_2(x,tp1,wtab,fm);
+      
+    i=adv;
+    h=(double) ((2*i)>>numode);
+    for (p=p1; p<h; p+=d1) ctp2_m(&(x[istart].re),p,tp2,&out);
+    p1=p-h;
+      
+    i=adv;
+    h=(double) ((2*i)>>numode);
+    for (p=p1; p<h; p+=d1) ctp2_m(&(x[istart].im),p,tp2,&out);
+    p1=p-h;
+  }
+  else {
+    for (i=0; i<nfn-adv; i++)
+      x[i]=ibuf[i];
+    for (; i<adv; i++) {
+      x[i].re=(real) dataIn[idxIn++];
+      x[i].im=(real) dataIn[idxIn++];
+    }
+    for (; i<nfn; i++) {
+      x[i].re=ibuf[i-adv].re=(real) dataIn[idxIn++];
+      x[i].im=ibuf[i-adv].im=(real) dataIn[idxIn++];
+    }
+      
+    if ( numode )
+      ctp1_1(x,tp1,wtab,fm);
+    else
+      ctp1_2(x,tp1,wtab,fm);
+      
+    i=2*adv;
+    h=(double) (i>>numode);
+    for (p=p1; p<h; p+=d1) ctp2_s(x+istart,p,tp2,&out);
+    p1=p-h;
+  }
+
+  buf->p1 = p1;
+
+  *dataOut = buf->out;
+  numOut = out - buf->out;
+//  if (numOut > buf->outSize)
+//    CommonExit(-1,"RateConv: output buffer size troubles");
+  buf->currentSampleIn += 2*adv;
+  buf->currentSampleOut += numOut;
+  
+  return numOut;
+}
+
+
+/* RateConvFree() */
+/* Free RateConv buffers. */
+
+void RateConvFree (
+  RCBuf *buf)			/* in: buffer (handle) */
+{
+  if (RCdebugLevel)
+    printf("RateConvFree: sampleIn=%ld sampleOut=%ld\n",
+	   buf->currentSampleIn,buf->currentSampleOut);
+  free(buf->out);
+  free(buf->wtab);
+  free(buf->ibuf);
+  free(buf);
+}
+
+
+/* end of rateconv.c */
+
--- /dev/null
+++ b/rateconv.h
@@ -1,0 +1,107 @@
+/**********************************************************************
+audio sample rate converter
+
+$Id: rateconv.h,v 1.1 2000/01/17 21:53:04 menno Exp $
+
+Header file: rateconv.h
+
+Authors:
+NM    Nikolaus Meine, Uni Hannover (c/o Heiko Purnhagen)
+HP    Heiko Purnhagen, Uni Hannover <purnhage@tnt.uni-hannover.de>
+
+Changes:
+xx-jun-98   NM      resamp.c
+18-sep-98   HP      converted into module
+04-nov-99   NM/HP   double ratio
+**********************************************************************/
+
+/*
+ * Sample-rate converter
+ *
+ * Realized in three steps:
+ *
+ * 1. Upsampling by factor two while doing appropriate lowpass-filtering.
+ *    This is done by using an FFT-based convolution algorithm with a multi-tap
+ *    Kaiser-windowed lowpass filter.
+ *    If the cotoff-frequency is less than 0.5, only lowpass-filtering without
+ *    the upsampling is done.
+ * 2. Upsampling by factor 128 using a 15 tap Kaiser-windowed lowpass filter
+ *    (alpha=12.5) and conventional convolution algorithm.
+ *    Two values (the next neighbours) are computed for every sample needed.
+ * 3. Linear interpolation between the two bounding values.
+ *
+ * Stereo and mono data is supported.
+ * Up- and downsampling of any ratio is possible.
+ * Input and output file format is Sun-audio.
+ *
+ * Written by N.Meine, 1998
+ *
+ */
+
+/* Multi channel data is interleaved: l0 r0 l1 r1 ... */
+/* Total number of samples (over all channels) is used. */
+
+
+#ifndef _rateconv_h_
+#define _rateconv_h_
+
+
+/* ---------- declarations ---------- */
+
+
+
+/* ---------- functions ---------- */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* RateConvInit() */
+/* Init audio sample rate conversion. */
+
+RCBuf *RateConvInit (
+  int debugLevel,		/* in: debug level */
+				/*     0=off  1=basic  2=full */
+  double ratio,			/* in: outputRate / inputRate */
+  int numChannel,		/* in: number of channels */
+  int htaps1,			/* in: num taps */
+				/*      -1 = auto */
+  float a1,			/* in: alpha for Kaiser window */
+				/*      -1 = auto */
+  float fc,			/* in: 6dB cutoff freq / input bandwidth */
+				/*      -1 = auto */
+  float fd,			/* in: 100dB cutoff freq / input bandwidth */
+				/*      -1 = auto */
+  long *numSampleIn);		/* out: num input samples / frame */
+				/* returns: */
+				/*  buffer (handle) */
+				/*  or NULL if error */
+
+
+/* RateConv() */
+/* Convert sample rate for one frame of audio data. */
+
+long RateConv (
+  RCBuf *buf,			/* in: buffer (handle) */
+  short *dataIn,		/* in: input data[] */
+  long numSampleIn,		/* in: number of input samples */
+  float **dataOut);		/* out: output data[] */
+				/* returns: */
+				/*  numSampleOut */
+
+
+/* RateConvFree() */
+/* Free RateConv buffers. */
+
+void RateConvFree (
+  RCBuf *buf);			/* in: buffer (handle) */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* #ifndef _rateconv_h_ */
+
+/* end of rateconv.h */