Java 在Android中识别录制声音的主频

Java 在Android中识别录制声音的主频,java,audio,signal-processing,fft,pcm,Java,Audio,Signal Processing,Fft,Pcm,我正在尝试转换位于的Python程序 到Android Java文件 第一步是确定主频。为此,我编写了以下Java程序 private class RecordAudio extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... paramVarArgs) { int audioSource = AudioSource.M

我正在尝试转换位于的Python程序 到Android Java文件

第一步是确定主频。为此,我编写了以下Java程序

private class RecordAudio
        extends AsyncTask<Void, Void, Void> {

    @Override
    protected Void doInBackground(Void... paramVarArgs) {
        int audioSource = AudioSource.MIC;
        int sampleRateInHz = 44100;
        int channelConfig = AudioFormat.CHANNEL_IN_MONO;
        int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
        int bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
        byte Data[] = new byte[bufferSizeInBytes];

        AudioRecord audioRecorder = new AudioRecord(audioSource,
                sampleRateInHz,
                channelConfig,
                audioFormat,
                bufferSizeInBytes);
        audioRecorder.startRecording();

        boolean isRecording = true;
        while (isRecording) {
            audioRecorder.read(Data, 0, Data.length);
            fftPrint(Data, bufferSizeInBytes);
        }
        return null;
    }

    boolean fftPrint(byte[] waveArray, int bufferSizeInBytes) {
        double HANDSHAKE_START_HZ = 8192;
        double HANDSHAKE_END_HZ = 8192 + 512;
        int len = waveArray.length;
        double[] waveTransformReal = new double[len];
        double[] waveTransformImg = new double[len];

        for (int i = 0; i < len; i++) {
            waveTransformReal[i] = waveArray[i]; //copy of original
            waveTransformImg[i] = waveArray[i]; //FFT transformed below
        }

        RealDoubleFFT p = new RealDoubleFFT(bufferSizeInBytes);
        p.ft(waveTransformImg);

        //Calculating abs
        double[] abs = new double[len];
        for (int i = 0; i < len; i++) {
            abs[i] = (Math.sqrt(waveTransformReal[i] * waveTransformReal[i] + waveTransformImg[i] * waveTransformImg[i]));
        }

        //calculating maxIndex
        int maxIndex = 0;
        for (int i = 0; i < len; i++) {
            if (abs[i] > abs[maxIndex])
                maxIndex = i;
        }

        double dominantFrequency = (maxIndex * 44100) / len;
        if (dominantFrequency > 0) Log.d("Freq: ", String.format("%f", dominantFrequency));

        if (match(dominantFrequency, HANDSHAKE_START_HZ)) {
            Log.i("Handshake start:", "FOUND START");
        }
        if (match(dominantFrequency, HANDSHAKE_END_HZ)) {
            Log.i("Handshake end:", "FOUND END");
            return true;
        }
        return false;
    }

    boolean match(double freq1, double freq2) {
        return (Math.abs(freq1 - freq2) < 20);
    }
私有类录制音频
扩展异步任务{
@凌驾
受保护的Void doInBackground(Void…paravarargs){
int audioSource=audioSource.MIC;
int-sampleRateInHz=44100;
int channelConfig=AudioFormat.CHANNEL\u在单声道中;
int audioFormat=audioFormat.ENCODING_PCM_16位;
int bufferSizeInBytes=AudioRecord.getMinBufferSize(sampleRateInHz,channelConfig,audioFormat);
字节数据[]=新字节[bufferSizeInBytes];
录音机=新录音机(音频源,
拉泰因茨,
channelConfig,
音频格式,
缓冲区大小(字节);
录音机。开始录音();
布尔值isRecording=true;
while(isRecording){
录音机。读取(数据,0,数据。长度);
fftPrint(数据,缓冲大小单位);
}
返回null;
}
布尔fftPrint(字节[]waveArray,int bufferSizeInBytes){
双握手\u开始\u HZ=8192;
双握手频率=8192+512;
int len=waveArray.length;
double[]waveTransformReal=新的双精度[len];
double[]waveTransformImg=新的双精度[len];
对于(int i=0;iabs[maxIndex])
maxIndex=i;
}
双显性频率=(maxIndex*44100)/len;
如果(主频率>0)Log.d(“频率:”,String.format(“%f”,主频率));
if(匹配(主要频率、握手频率和启动频率)){
Log.i(“握手开始:,“找到开始”);
}
中频(匹配(主频率、握手频率){
Log.i(“握手结束:,“找到结束”);
返回true;
}
返回false;
}
布尔匹配(双频1,双频2){
返回(数学绝对值(频率1-频率2)<20);
}
注:RealDoubleFFT来自ca.uol.aig.fftpack


我不确定我是否做得对。我正在Logcat中打印频率,但他们没有找到正在播放的音频中存在的握手频率。我做错了什么?

请注意,FFT幅值峰值的频率分辨率取决于FFT的长度(和窗口等)。此长度在您的代码中没有指定或限制,因此您甚至不知道任何FFT结果是否可能在目标频率的20 Hz范围内。

感谢@hotpaw2的回答,我对声音完全陌生,我通过在网上大量阅读来编写上述代码。我对bufferSizeInBytes ro 40进行了硬编码96.但仍然没有看到过期的输出。每次我运行这个程序并播放相同的声音时,每个音块都会得到不同的主频。请你帮我更正上面的代码。非常感谢。