我目前正在尝试使用 Android 实现一些代码,以检测何时通过手机的麦克风播放了一些特定的音频范围。我已经使用 AudioRecord
类设置了该类:
int channel_config = AudioFormat.CHANNEL_CONFIGURATION_MONO;
int format = AudioFormat.ENCODING_PCM_16BIT;
int sampleSize = 8000;
int bufferSize = AudioRecord.getMinBufferSize(sampleSize, channel_config, format);
AudioRecord audioInput = new AudioRecord(AudioSource.MIC, sampleSize, channel_config, format, bufferSize);
然后读入音频:
short[] audioBuffer = new short[bufferSize];
audioInput.startRecording();
audioInput.read(audioBuffer, 0, bufferSize);
执行 FFT 是我卡住的地方,因为我在这方面的经验很少。我一直在尝试使用这个类:
FFT in Java和 Complex class to go with it
然后我发送以下值:
Complex[] fftTempArray = new Complex[bufferSize];
for (int i=0; i<bufferSize; i++)
{
fftTempArray[i] = new Complex(audio[i], 0);
}
Complex[] fftArray = fft(fftTempArray);
这很容易让我误解了这个类的工作原理,但是返回的值到处乱跳,即使在沉默中也不能代表一致的频率。是否有人知道执行此任务的方法,或者我是否将事情复杂化以尝试仅获取少量频率范围而不是将其绘制为图形表示?
最佳答案
首先,您需要确保您获得的结果正确转换为 float / double 。我不确定 short[] 版本是如何工作的,但 byte[] 版本只返回原始字节版本。然后需要将此字节数组正确转换为 float 。转换代码应如下所示:
double[] micBufferData = new double[<insert-proper-size>];
final int bytesPerSample = 2; // As it is 16bit PCM
final double amplification = 100.0; // choose a number as you like
for (int index = 0, floatIndex = 0; index < bytesRecorded - bytesPerSample + 1; index += bytesPerSample, floatIndex++) {
double sample = 0;
for (int b = 0; b < bytesPerSample; b++) {
int v = bufferData[index + b];
if (b < bytesPerSample - 1 || bytesPerSample == 1) {
v &= 0xFF;
}
sample += v << (b * 8);
}
double sample32 = amplification * (sample / 32768.0);
micBufferData[floatIndex] = sample32;
}
然后你使用 micBufferData[] 创建你的输入复数数组。
得到结果后,请使用结果中复数的大小。除了具有实际值的频率之外,大多数幅度应该接近于零。
您需要采样频率来将数组索引转换为这样的幅度到频率:
private double ComputeFrequency(int arrayIndex) {
return ((1.0 * sampleRate) / (1.0 * fftOutWindowSize)) * arrayIndex;
}
关于java - Android音频FFT使用audiorecord检索特定频率幅度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5774104/