mirror of
https://github.com/cookiengineer/audacity
synced 2025-11-20 16:07:14 +01:00
157 lines
5.7 KiB
C
157 lines
5.7 KiB
C
/*******************************************************************
|
|
This file extends the fftlib with calls to maintain the cosine and bit reversed tables
|
|
for you (including mallocs and free's). Call the init routine for each fft size you will
|
|
be using. Then you can call the fft routines below which will make the fftlib library
|
|
call with the appropriate tables passed. When you are done with all fft's you can call
|
|
fftfree to release the storage for the tables. Note that you can call fftinit repeatedly
|
|
with the same size, the extra calls will be ignored. So, you could make a macro to call
|
|
fftInit every time you call ffts. For example you could have someting like:
|
|
#define FFT(a,n) if(!fftInit(roundtol(LOG2(n)))) ffts(a,roundtol(LOG2(n)),1);else printf("fft error\n");
|
|
*******************************************************************/
|
|
#include <stdlib.h>
|
|
#include "fftlib.h"
|
|
#include "matlib.h"
|
|
#include "fftext.h"
|
|
|
|
// pointers to storage of Utbl's and BRLow's
|
|
static float *UtblArray[8*sizeof(long)] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
|
|
static short *BRLowArray[8*sizeof(long)/2] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
|
|
|
|
int fftInit(long M){
|
|
// malloc and init cosine and bit reversed tables for a given size fft, ifft, rfft, rifft
|
|
/* INPUTS */
|
|
/* M = log2 of fft size (ex M=10 for 1024 point fft) */
|
|
/* OUTPUTS */
|
|
/* private cosine and bit reversed tables */
|
|
|
|
int theError = 1;
|
|
/*** I did NOT test cases with M>27 ***/
|
|
if ((M >= 0) && (M < 8*sizeof(long))){
|
|
theError = 0;
|
|
if (UtblArray[M] == 0){ // have we not inited this size fft yet?
|
|
// init cos table
|
|
UtblArray[M] = (float *) malloc( (POW2(M)/4+1)*sizeof(float) );
|
|
if (UtblArray[M] == 0)
|
|
theError = 2;
|
|
else{
|
|
fftCosInit(M, UtblArray[M]);
|
|
}
|
|
if (M > 1){
|
|
if (BRLowArray[M/2] == 0){ // init bit reversed table for cmplx fft
|
|
BRLowArray[M/2] = (short *) malloc( POW2(M/2-1)*sizeof(short) );
|
|
if (BRLowArray[M/2] == 0)
|
|
theError = 2;
|
|
else{
|
|
fftBRInit(M, BRLowArray[M/2]);
|
|
}
|
|
}
|
|
}
|
|
if (M > 2){
|
|
if (BRLowArray[(M-1)/2] == 0){ // init bit reversed table for real fft
|
|
BRLowArray[(M-1)/2] = (short *) malloc( POW2((M-1)/2-1)*sizeof(short) );
|
|
if (BRLowArray[(M-1)/2] == 0)
|
|
theError = 2;
|
|
else{
|
|
fftBRInit(M-1, BRLowArray[(M-1)/2]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
return theError;
|
|
}
|
|
|
|
void fftFree(){
|
|
// release storage for all private cosine and bit reversed tables
|
|
long i1;
|
|
for (i1=8*sizeof(long)/2-1; i1>=0; i1--){
|
|
if (BRLowArray[i1] != 0){
|
|
free(BRLowArray[i1]);
|
|
BRLowArray[i1] = 0;
|
|
};
|
|
};
|
|
for (i1=8*sizeof(long)-1; i1>=0; i1--){
|
|
if (UtblArray[i1] != 0){
|
|
free(UtblArray[i1]);
|
|
UtblArray[i1] = 0;
|
|
};
|
|
};
|
|
}
|
|
|
|
/*************************************************
|
|
The following calls are easier than calling to fftlib directly.
|
|
Just make sure fftlib has been called for each M first.
|
|
**************************************************/
|
|
|
|
void ffts(float *data, long M, long Rows){
|
|
/* Compute in-place complex fft on the rows of the input array */
|
|
/* INPUTS */
|
|
/* *ioptr = input data array */
|
|
/* M = log2 of fft size (ex M=10 for 1024 point fft) */
|
|
/* Rows = number of rows in ioptr array (use 1 for Rows for a single fft) */
|
|
/* OUTPUTS */
|
|
/* *ioptr = output data array */
|
|
ffts1(data, M, Rows, UtblArray[M], BRLowArray[M/2]);
|
|
}
|
|
|
|
void iffts(float *data, long M, long Rows){
|
|
/* Compute in-place inverse complex fft on the rows of the input array */
|
|
/* INPUTS */
|
|
/* *ioptr = input data array */
|
|
/* M = log2 of fft size (ex M=10 for 1024 point fft) */
|
|
/* Rows = number of rows in ioptr array (use 1 for Rows for a single fft) */
|
|
/* OUTPUTS */
|
|
/* *ioptr = output data array */
|
|
iffts1(data, M, Rows, UtblArray[M], BRLowArray[M/2]);
|
|
}
|
|
|
|
void rffts(float *data, long M, long Rows){
|
|
/* Compute in-place real fft on the rows of the input array */
|
|
/* The result is the complex spectra of the positive frequencies */
|
|
/* except the location for the first complex number contains the real */
|
|
/* values for DC and Nyquest */
|
|
/* See rspectprod for multiplying two of these spectra together- ex. for fast convolution */
|
|
/* INPUTS */
|
|
/* *ioptr = real input data array */
|
|
/* M = log2 of fft size (ex M=10 for 1024 point fft) */
|
|
/* Rows = number of rows in ioptr array (use 1 for Rows for a single fft) */
|
|
/* OUTPUTS */
|
|
/* *ioptr = output data array in the following order */
|
|
/* Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), Re(x[2]), Im(x[2]), ... Re(x[N/2-1]), Im(x[N/2-1]). */
|
|
rffts1(data, M, Rows, UtblArray[M], BRLowArray[(M-1)/2]);
|
|
}
|
|
|
|
void riffts(float *data, long M, long Rows){
|
|
/* Compute in-place real ifft on the rows of the input array */
|
|
/* data order as from rffts */
|
|
/* INPUTS */
|
|
/* *ioptr = input data array in the following order */
|
|
/* M = log2 of fft size (ex M=10 for 1024 point fft) */
|
|
/* Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), Re(x[2]), Im(x[2]), ... Re(x[N/2-1]), Im(x[N/2-1]). */
|
|
/* Rows = number of rows in ioptr array (use 1 for Rows for a single fft) */
|
|
/* OUTPUTS */
|
|
/* *ioptr = real output data array */
|
|
riffts1(data, M, Rows, UtblArray[M], BRLowArray[(M-1)/2]);
|
|
}
|
|
|
|
void rspectprod(float *data1, float *data2, float *outdata, long N){
|
|
// When multiplying a pair of spectra from rfft care must be taken to multiply the
|
|
// two real values seperately from the complex ones. This routine does it correctly.
|
|
// the result can be stored in-place over one of the inputs
|
|
/* INPUTS */
|
|
/* *data1 = input data array first spectra */
|
|
/* *data2 = input data array second spectra */
|
|
/* N = fft input size for both data1 and data2 */
|
|
/* OUTPUTS */
|
|
/* *outdata = output data array spectra */
|
|
if(N>1){
|
|
outdata[0] = data1[0] * data2[0]; // multiply the zero freq values
|
|
outdata[1] = data1[1] * data2[1]; // multiply the nyquest freq values
|
|
cvprod(data1 + 2, data2 + 2, outdata + 2, N/2-1); // multiply the other positive freq values
|
|
}
|
|
else{
|
|
outdata[0] = data1[0] * data2[0];
|
|
}
|
|
}
|