Android主动降噪

8

我正在进行一个相当有雄心的项目,旨在实现安卓系统上耳塞或者耳机的主动降噪。

我的目标是使用安卓手机麦克风记录环境噪声,对相应的音频数据进行相位反转(从 Audio Record 中获取的 short-value 加一个简单的 *-1 操作?),然后把这个反转后的波形通过耳机播放出来。如果延迟和振幅准确无误,这样应该能有效地消除大量机械结构性噪声。

以下是目前为止的进展:

@Override
    public void run()
    {
        Log.i("Audio", "Running Audio Thread");
        AudioRecord recorder = null;
        AudioTrack track = null;
        short[][] buffers  = new short[256][160];
        int ix = 0;

    /*
     * Initialize buffer to hold continuously recorded audio data, start recording, and start
     * playback.
     */
        try
        {
            int N = AudioRecord.getMinBufferSize(8000,AudioFormat.CHANNEL_IN_MONO,AudioFormat.ENCODING_PCM_16BIT);
            recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, N*10);
            //NoiseSuppressor ns = NoiseSuppressor.create(recorder.getAudioSessionId());
            //ns.setEnabled(true);

            track = new AudioTrack(AudioManager.STREAM_MUSIC, 8000,
                    AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, N*10, AudioTrack.MODE_STREAM);
            recorder.startRecording();
            track.play();
        /*
         * Loops until something outside of this thread stops it.
         * Reads the data from the recorder and writes it to the audio track for playback.
         */
            while(!stopped)
            {                    
                short[] buffer = buffers[ix++ % buffers.length];
                N = recorder.read(buffer,0,buffer.length);

                for(int iii = 0;iii<buffer.length;iii++){
                    //Log.i("Data","Value: "+buffer[iii]);
                    buffer[iii] = buffer[iii] *= -1;                        
                }                    
                track.write(buffer, 0, buffer.length);
            }
        }
        catch(Throwable x)
        {
            Log.w("Audio", "Error reading voice audio", x);
        }
    /*
     * Frees the thread's resources after the loop completes so that it can be run again
     */
        finally
        {
            recorder.stop();
            recorder.release();
            track.stop();
            track.release();
        }
    }

我刚刚发现Android API实际上已经有了一个NoiseSuppression算法(如上所述的注释)。我进行了测试并发现NoiseSuppressor无法有效地消除恒定音调,这使我相信它实际上只是在非语音频率上执行一个带通滤波器。
所以,我的问题是:
1) 上述代码从麦克风记录到耳机播放需要约250-500毫秒。这种延迟非常糟糕,如果能减少就好了。对此,是否有任何建议?
2) 无论延迟如何紧密,我的理解是播放波形将与实际环境噪音波形存在相位偏移。这表明我需要执行某种波形匹配来计算这个偏移量并进行补偿。对于如何计算这个偏移量,有什么想法吗?
3) 在补偿延迟方面,它会是什么样子?我每个周期都有一组shorts数据,那么30ms或250ms的延迟会是什么样子?
我知道这种方法的基本问题是手机位置不在头旁边可能会引入一些误差,但我希望通过一些动态或固定的延迟校正来克服它。
感谢您提出的任何建议。

从理论上讲,你可能能够做一些极低频率的事情,但即使如此也是不现实的。 - Bjorn Roche
你的项目进展如何了?有什么更新吗? - The Mitra Boy
很遗憾,我在得出结论无法弥补电话麦克风到用户耳朵的可变距离后放弃了它。我很想再次开始,但现在不清楚从哪里开始。 - Raevik
单独的智能手机并不足以完成这个项目:您需要两部设备,或者一部智能手机和一个蓝牙耳机,距离用户数米远,用于捕捉声音并以光速而非声速发送给用户。当然,远程麦克风应该靠近噪音源。 - jumpjack
1个回答

4
即使您能够解决延迟问题,这仍是一个困难的问题,因为您不知道手机与耳朵之间的距离。此外,距离不是固定的(因为用户会移动手机),还有一个问题是您没有每只耳朵的麦克风(因此在信息到达之前无法知道波将在哪个耳朵)。尽管如此,您可能能够做些取消高周期波形的事情。但您唯一能做的就是允许用户手动调整每只耳朵的时间延迟,在您的代码中,由于没有靠近耳朵的麦克风,所以您无法知道是否正在改善问题。

我讨厌这可能是真的,因为我不喜欢接受某些事情不可能的事实。即使解决方案不完美,我也必须相信有一种方法可以建立校准方案或机制来动态补偿。虽然我很感激反馈并点赞 :) - Raevik
我认为除非涉及用户,否则您无法进行任何校准或补偿,而该过程可能比噪音本身更令人讨厌,特别是如果他们使用一些紧密贴合的耳塞来阻挡大量噪音!再次强调,这只有在非常周期性或可预测的噪音情况下才有帮助。现实世界中的环境噪声并非如此,因此您需要预测未来...不过,尝试使用校准处理非常周期性的外部噪声(可能是低频,正如Bjorn Roche所说)可能会很有趣。 - Нет войне
SONY Xperia Z2 似乎已经拍摄了这个。请查看 http://www.androidheadlines.com/page/2 。正如您所指出的,用户在某种程度上参与了噪声抵消方案的决定。 - The Mitra Boy
从http://forum.xda-developers.com/showthread.php?t=2743254看起来,你需要使用的特殊耳机上有一个麦克风安装在其中一个耳机的外部,这将解决一些与距离相关的问题。 - Нет войне

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接