📄 fft32.cpp
字号:
/* fix_fft.c - long-point Fast Fourier Transform */
/*
fix_fft() perform FFT or inverse FFT
window() applies a Hanning window to the (time) input
fix_loud() calculates the loudness of the signal, for
each freq point. Result is an integer array,
units are dB (values will be negative).
iscale() scale an integer value by (numer/denom).
fix_mpy() perform long-point multiplication.
Sinewave32[1024] sinewave normalized to 32767 (= 1.0).
Loudampl[100] Amplitudes for lopudnesses from 0 to -99 dB.
Low_pass Low-pass filter, cutoff at sample_freq / 4.
All data are long-point short integers, in which
-32768 to +32768 represent -1.0 to +1.0. Integer arithmetic
is used for speed, instead of the more natural floating-point.
For the forward FFT (time -> freq), long scaling is
performed to prevent arithmetic overflow, and to map a 0dB
sine/cosine wave (i.e. amplitude = 32767) to two -6dB freq
coefficients; the one in the lower half is reported as 0dB
by fix_loud(). The return value is always 0.
For the inverse FFT (freq -> time), long scaling cannot be
done, as two 0dB coefficients would sum to a peak amplitude of
64K, overflowing the 32k range of the long-point integers.
Thus, the fix_fft() routine performs variable scaling, and
returns a value which is the number of bits LEFT by which
the output must be shifted to get the actual amplitude
(i.e. if fix_fft() returns 3, each value of fr[] and fi[]
must be multiplied by 8 (2**3) for proper scaling.
Clearly, this cannot be done within the long-point short
integers. In practice, if the result is to be used as a
filter, the scale_shift can usually be ignored, as the
result will be approximately correctly normalized as is.
TURBO C, any memory model; uses inline assembly for speed
and for carefully-scaled arithmetic.
Written by: Tom Roberts 11/8/89
Made portable: Malcolm Slaney 12/15/94 malcolm@interval.com
Timing on a Macintosh PowerBook 180.... (using Symantec C6.0)
fix_fft (1024 points) 8 ticks
fft (1024 points - Using SANE) 112 Ticks
fft (1024 points - Using FPU) 11
*/
/* dosFIX_MPY() - long-point multiplication macro.
This macro is a statement, not an expression (uses asm).
BEWARE: make sure _DX is not clobbered by evaluating (A) or DEST.
args are all of type long.
Scaling ensures that 32767*32767 = 32767. */
//#include "stdafx.h"
/*
#define dosFIX_MPY(DEST,A,B) { \
_EDX=(B); \
_EAX=(A) \
asm imul edx; \
asm add eax,eax; \
asm adc edx,edx; \
(DEST)=_EDX }
*/
//#include "mfcc.h"
//#ifdef FIX_RECOG
extern "C" long dosFIX_MPY32_C(long x,long y);
long dosFIX_MPY32(long x,long y);
#define dosFIX_MPY32(x,y) dosFIX_MPY32_C(x,y)
//#define FIX_MPY(DEST,A,B) DEST = ((long)(A) * (long)(B))>>15
#define N_WAVE 1024 /* dimension of Sinewave[] */
#define LOG2_N_WAVE 10 /* log2(N_WAVE) */
#define N_LOUD 100 /* dimension of Loudampl[] */
//#ifndef long
//#define long long
//#endif
extern long Sinewave32[N_WAVE]; /* placed at end of this file for clarity */
//extern long Loudampl[N_LOUD];
//long db_from_ampl32(long re, long im);
/*
fix_fft() - perform fast Fourier transform.
if n>0 FFT is done, if n<0 inverse FFT is done
fr[n],fi[n] are real,imaginary arrays, INPUT AND RESULT.
size of data = 2**m
set inverse to 0=dft, 1=idft
*/
long fix_fft32(long fr[], long fi[], int m, int inverse)
{
long mr,nn,i,j,l,k,istep, n, scale, shift;
long qr,qi,tr,ti,wr,wi;
// ClickStart(1);
n = 1<<m;
if(n > N_WAVE)
return -1;
mr = 0;
nn = n - 1;
scale = 0;
/* decimation in time - re-order data */
for(m=1; m<=nn; ++m) {
l = n;
do {
l >>= 1;
} while(mr+l > nn);
mr = (mr & (l-1)) + l;
if(mr <= m) continue;
tr = fr[m];
fr[m] = fr[mr];
fr[mr] = tr;
ti = fi[m];
fi[m] = fi[mr];
fi[mr] = ti;
}
l = 1;
k = LOG2_N_WAVE-1;
while(l < n) {
if(inverse) {
/* variable scaling, depending upon data */
shift = 0;
for(i=0; i<n; ++i) {
j = fr[i];
if(j < 0)
j = -j;
m = fi[i];
if(m < 0)
m = -m;
if(j > 16383 || m > 16383) {
shift = 1;
break;
}
}
if(shift)
++scale;
} else {
/* long scaling, for proper normalization -
there will be log2(n) passes, so this
results in an overall factor of 1/n,
distributed to maximize arithmetic accuracy. */
shift = 1;
}
/* it may not be obvious, but the shift will be performed
on each data point exactly once, during this pass. */
istep = l << 1;
for(m=0; m<l; ++m) {
j = m << k;
/* 0 <= j < N_WAVE/2 */
wr = Sinewave32[j+N_WAVE/4];
wi = -Sinewave32[j];
if(inverse)
wi = -wi;
if(shift) {
wr >>= 1;
wi >>= 1;
}
for(i=m; i<n; i+=istep) {
j = i + l;
tr = dosFIX_MPY32(wr,fr[j]) -dosFIX_MPY32(wi,fi[j]);
ti = dosFIX_MPY32(wr,fi[j]) +dosFIX_MPY32(wi,fr[j]);
qr = fr[i];
qi = fi[i];
if(shift) {
qr >>= 1;
qi >>= 1;
}
fr[j] = qr - tr;
fi[j] = qi - ti;
fr[i] = qr + tr;
fi[i] = qi + ti;
}
}
--k;
l = istep;
}
// ClickEnd(1);
return scale;
}
/* window() - apply a Hanning window */
/*
void window32(long fr[], long n)
{
long i,j,k;
j = N_WAVE/n;
n >>= 1;
for(i=0,k=N_WAVE/4; i<n; ++i,k+=j)
fr[i]=dosFIX_MPY32(fr[i],0x40000000-(Sinewave32[k]>>1));
n <<= 1;
for(k-=j; i<n; ++i,k-=j)
fr[i]=dosFIX_MPY32(fr[i],0x40000000-(Sinewave32[k]>>1));
}
*/
/* fix_loud() - compute loudness of freq-spectrum components.
n should be ntot/2, where ntot was passed to fix_fft();
6 dB is added to account for the omitted alias components.
scale_shift should be the result of fix_fft(), if the time-series
was obtained from an inverse FFT, 0 otherwise.
loud[] is the loudness, in dB wrt 32767; will be +10 to -N_LOUD.
*/
/*
void fix_loud32(long loud[], long fr[], long fi[], long n, long scale_shift)
{
long i, max;
max = 0;
if(scale_shift > 0)
max = 10;
scale_shift = (scale_shift+1) * 6;
for(i=0; i<n; ++i) {
loud[i] = db_from_ampl32(fr[i],fi[i]) + scale_shift;
if(loud[i] > max)
loud[i] = max;
}
}
*/
/* db_from_ampl() - find loudness (in dB) from
the complex amplitude.
*/
/*
long db_from_ampl32(long re, long im)
{
static long loud2[N_LOUD] = {0};
long v;
long i;
if(loud2[0] == 0) {
loud2[0] = (long)Loudampl[0] * (long)Loudampl[0];
for(i=1; i<N_LOUD; ++i) {
v = (long)Loudampl[i] * (long)Loudampl[i];
loud2[i] = v;
loud2[i-1] = (loud2[i-1]+v) / 2;
}
}
v = (long)re * (long)re + (long)im * (long)im;
for(i=0; i<N_LOUD; ++i)
if(loud2[i] <= v)
break;
return (-i);
}
*/
/*
iscale() - scale an integer value by (numer/denom)
*/
/*
long iscale32(long value, long numer, long denom)
{
#ifdef DOS
asm mov eax,value
asm imul DWORD PTR numer
asm idiv DWORD PTR denom
return _EAX;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -