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

Posted

技术标签:

【中文标题】在Android中识别录制声音中的主频率【英文标题】:Identifying dominant frequency in recorded sound in Android 【发布时间】:2018-11-14 16:49:45 【问题描述】:

我正在尝试转换位于 https://github.com/rraval/pied-piper/blob/master/decode.py 到 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);
    

注意:RealDoubleFFT 来自 ca.uol.aig.fftpack

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

【问题讨论】:

【参考方案1】:

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

【讨论】:

感谢@hotpaw2 的回答,我对声音完全陌生,通过在网上大量阅读,我设法编写了上述代码。我确实对 bufferSizeInBytes ro 4096 进行了硬编码。但仍然没有看到过期的输出。每次我运行这个程序并播放相同的声音时,我都会为每个块获得不同的主频率。您能否通过更正上述代码来提供帮助。非常感谢。

以上是关于在Android中识别录制声音中的主频率的主要内容,如果未能解决你的问题,请参考以下文章

Android 音频相关

如何在 Android 应用中录制声音

在android中播放时录制声音并改变音高?

android soundpool 没有声音

音频中采样位数,采样率,比特率的名词解释(转)

使用 AVAudioEngine 进行语音识别会在录制后阻止声音