音频的分析离不开从时域转化为频域的过程,这一过程最直接相关的就是快速傅里叶变化DFT。 DFT 和他的逆变化有很多开源库,网上也有很多就不介绍,我这边使用的是Java jtransforms:代码如下:
```c
public double[] calculateSpectrumDBFS(short[] audioData) {
int n = audioData.length/2;
double[] fftData = new double[n * 2]; // FFT类需要双倍长度,实部+虚部
// 复制音频数据到FFT数据数组的实部,虚部设为0
for (int i = 0; i < n; i++) {
fftData[2 * i] = audioData[i*2];
fftData[2 * i + 1] = 0;
}
// 执行FFT
DoubleFFT_1D fft = new DoubleFFT_1D(n);
fft.complexForward(fftData);
// 计算每个频率分量的幅度和dBFS
double[] spectrumDBFS = new double[n / 2];
double ref = Math.pow(2, 15); // 16位PCM的最大值作为参考
for (int i = 0; i < n / 4; i++) {
double re = fftData[2 * i];
double im = fftData[2 * i + 1];
double magnitude = Math.sqrt(re * re + im * im);
double magreal = magnitude/(double) (n/2);
double dbfs = 20 * Math.log10(magreal / ref);
if(dbfs > -50)
Log.e(TAG, "ffff HZ = " + i * 48000 / (n) +" FftMediaFuncion: dbfs " + dbfs + " 模 " + magnitude );
spectrumDBFS[i] = dbfs;
}
return spectrumDBFS;
}
}
其中dbfs 简单的介绍一下:
dbfs 就是数字音频分贝的表示方法,计算公式 dbfs = 20log10(sample/2^15): sample 表示当前采样点样值,2^15 表示位深, 位深除了16bit 之外还有24bit 等。 位深: 表示一个采样点使用多少个bit 位来表示他的值,所以位深越大表示的频点精度也就越高,音质也就越好。目前移动设备包括车载软件一般都还是使用16bit 播放音频,少部分使用24bit 播放,这涉及到编解码以及硬件的传输能力,是个小课题。
傅里叶变化之后的返回值:
假设采样率位FS 采样点为N
傅里叶变换之后的返回值是一个复数,除了直流分量之外,复数的模的N/2就是当前所需频段的幅值。
频点的计算方法: fs = iFS/N 其中i代表第几个采样点,