Java 基于Mic的Android哨声检测

Java 基于Mic的Android哨声检测,java,android,android-studio,fft,Java,Android,Android Studio,Fft,我正在尝试实现一个应用程序,在该应用程序中,即使存在环境背景噪声,我也可以检测特定频率(1000Hz-1500Hz)的口哨。在网络上做了大量研究之后,我使用FFT方法尝试并检测从麦克风捕获的最大振幅是否与口哨音调频率对应 public void run() { if (ar == null) { bufferSize = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, A

我正在尝试实现一个应用程序,在该应用程序中,即使存在环境背景噪声,我也可以检测特定频率(1000Hz-1500Hz)的口哨。在网络上做了大量研究之后,我使用FFT方法尝试并检测从麦克风捕获的最大振幅是否与口哨音调频率对应

public void run() {
    if (ar == null) {
        bufferSize = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
        ar = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000,AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,bufferSize);
        audioBuffer = new short[bufferSize];
        ar.startRecording();
        ar.read(audioBuffer, 0, bufferSize);

        //Conversion from short to double
        double[] micBufferData = new double[bufferSize];//size may need to change
        final int bytesPerSample = 2; // As it is 16bit PCM
        final double amplification = 1.0; // choose a number as you like
        for (int index = 0, floatIndex = 0; index < (byte) bufferSize - bytesPerSample + 1; index += bytesPerSample, floatIndex++) {
            double sample = 0;
            for (int b = 0; b < bytesPerSample; b++) {
                int v = audioBuffer[index + b];
                if (b < bytesPerSample - 1 || bytesPerSample == 1) {
                    v &= 0xFF;
                }
                sample += v << (b * 8);
            }
            double sample32 = amplification * (sample / 32768.0);
            micBufferData[floatIndex] = sample32;
        }

        //Create Complex array for use in FFT
        Complex[] fftTempArray = new Complex[bufferSize];
        for (int i=0; i< (byte) bufferSize; i++)
        {
            fftTempArray[i] = new Complex(micBufferData[i], 0);
        }

        //Obtain array of FFT data
        final Complex[] fftArray = FFT.fft(fftTempArray);
        //final Complex[] fftInverse = FFT.ifft(fftTempArray);

        //Create an array of magnitude of fftArray
        double[] magnitude = new double[fftArray.length];
        for (int i=0; i<fftArray.length; i++){
            magnitude[i]= fftArray[i].abs();
        }


        double maxVal = -1.0;
        int maxIndex = 1;
        for( int j=0; j < fftArray.length / 2; ++j ) {
            double v = magnitude[2*j] * magnitude[2*j] + magnitude[2*j+1] * magnitude[2*j+1];
            if( v > maxVal ) {
                maxVal = v;
                maxIndex = j;
            }
        }

        maxFrequency =  ((1.0 * 44100) / (1.0 * bufferSize)) * maxIndex;

    }
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if (isRunning) {
                tv2.setText("Frequency Detected: " + maxFrequency);
            }
        }
    });

}
public void run(){
if(ar==null){
bufferSize=AudioRecord.getMinBufferSize(8000,AudioFormat.CHANNEL\u CONFIGURATION\u MONO,AudioFormat.ENCODING\u PCM\u 16位);
ar=新的音频记录(MediaRecorder.AudioSource.MIC,8000,AudioFormat.CHANNEL\u CONFIGURATION\u MONO,AudioFormat.ENCODING\u PCM\u 16位,bufferSize);
audioBuffer=新的短[bufferSize];
ar.startRecording();
ar.read(音频缓冲区,0,缓冲区大小);
//从短到双的转换
double[]micBufferData=new double[bufferSize];//大小可能需要更改
final int bytesPerSample=2;//因为它是16位PCM
最终双放大=1.0;//根据需要选择一个数字
对于(int index=0,floatIndex=0;index<(字节)bufferSize-bytesPerSample+1;index+=bytesPerSample,floatIndex++){
双样本=0;
for(int b=0;b样本+=v以下线路不能可靠工作:

for (int i=0; i< (byte) bufferSize; i++)
for(int i=0;i<(字节)bufferSize;i++)
bufferSize
可以远大于一个字节,然后强制转换可以产生偶数负数,这样循环就不会一次执行。
fftTempArray
不会初始化

删除
(字节)
将更正此错误

但至少还有第二个错误:您的“从短到双的转换”是错误的。它将两个连续的16位采样组合为
micBufferData
中的一个双采样,而每个16位采样应该对应于它自己的双采样

编辑


您的评论中的错误表明,您的数组还需要2^N大小。因此,找到下一个小于
bufferSize

的2^N大小是什么意思?您不理解代码在做什么?它不是您的?如果您试图确定声音中是否存在特定频率,则FFT是正确的选择y继续。你的问题到底是什么?当我试图运行代码时,我遇到了一些错误。我得到了java.lang.RuntimeException:N不是最终复数的2的幂[]fftArray=FFT.FFT(fftTempArray);请看:这是一种最好先用高级语言(mathematica、matlab、python numpy)进行原型化的东西整理数学。对于numpy中的带通,例如,我似乎不明白为什么会发生这种情况?我可以从打印语句中看出,当N=5时,它会出错。我相信它的起始索引是640。这个数字有意义吗?结果是,我的bufferSize=640,而不是索引2。这很有趣,所以下一个较低的2^N数字是512(=2^9)