MockingBird/web/static/js/lib.fft.js

112 lines
2.8 KiB
JavaScript
Raw Normal View History

/*
时域转频域快速傅里叶变换(FFT)
https://github.com/xiangyuecn/Recorder
var fft=Recorder.LibFFT(bufferSize)
bufferSize取值2的n次方
fft.bufferSize 实际采用的bufferSize
fft.transform(inBuffer)
inBuffer:[Int16,...] 数组长度必须是bufferSize
返回[Float64(Long),...]长度为bufferSize/2
*/
/*
从FFT.java 移植Java开源库jmp123 版本0.3
https://www.iteye.com/topic/851459
https://sourceforge.net/projects/jmp123/files/
*/
Recorder.LibFFT=function(bufferSize){
"use strict";
var FFT_N_LOG,FFT_N,MINY;
var real, imag, sintable, costable;
var bitReverse;
var FFT_Fn=function(bufferSize) {//bufferSize只能取值2的n次方
FFT_N_LOG=Math.round(Math.log(bufferSize)/Math.log(2));
FFT_N = 1 << FFT_N_LOG;
MINY = ((FFT_N << 2) * Math.sqrt(2));
real = [];
imag = [];
sintable = [0];
costable = [0];
bitReverse = [];
var i, j, k, reve;
for (i = 0; i < FFT_N; i++) {
k = i;
for (j = 0, reve = 0; j != FFT_N_LOG; j++) {
reve <<= 1;
reve |= (k & 1);
k >>>= 1;
}
bitReverse[i] = reve;
}
var theta, dt = 2 * Math.PI / FFT_N;
for (i = (FFT_N >> 1) - 1; i > 0; i--) {
theta = i * dt;
costable[i] = Math.cos(theta);
sintable[i] = Math.sin(theta);
}
}
/*
用于频谱显示的快速傅里叶变换
inBuffer 输入FFT_N个实数返回 FFT_N/2个输出值(复数模的平方)
*/
var getModulus=function(inBuffer) {
var i, j, k, ir, j0 = 1, idx = FFT_N_LOG - 1;
var cosv, sinv, tmpr, tmpi;
for (i = 0; i != FFT_N; i++) {
real[i] = inBuffer[bitReverse[i]];
imag[i] = 0;
}
for (i = FFT_N_LOG; i != 0; i--) {
for (j = 0; j != j0; j++) {
cosv = costable[j << idx];
sinv = sintable[j << idx];
for (k = j; k < FFT_N; k += j0 << 1) {
ir = k + j0;
tmpr = cosv * real[ir] - sinv * imag[ir];
tmpi = cosv * imag[ir] + sinv * real[ir];
real[ir] = real[k] - tmpr;
imag[ir] = imag[k] - tmpi;
real[k] += tmpr;
imag[k] += tmpi;
}
}
j0 <<= 1;
idx--;
}
j = FFT_N >> 1;
var outBuffer=new Float64Array(j);
/*
* 输出模的平方:
* for(i = 1; i <= j; i++)
* inBuffer[i-1] = real[i] * real[i] + imag[i] * imag[i];
*
* 如果FFT只用于频谱显示,可以"淘汰"幅值较小的而减少浮点乘法运算. MINY的值
* 和Spectrum.Y0,Spectrum.logY0对应.
*/
sinv = MINY;
cosv = -MINY;
for (i = j; i != 0; i--) {
tmpr = real[i];
tmpi = imag[i];
if (tmpr > cosv && tmpr < sinv && tmpi > cosv && tmpi < sinv)
outBuffer[i - 1] = 0;
else
outBuffer[i - 1] = Math.round(tmpr * tmpr + tmpi * tmpi);
}
return outBuffer;
}
FFT_Fn(bufferSize);
return {transform:getModulus,bufferSize:FFT_N};
};