Android active noise cancellation
Asked Answered
P

1

8

I'm working a somewhat ambitious project to get active noise-reduction achieved on Android with earbuds or headphones on.

My objective is to record ambient noise with the android phone mic, invert the phase (a simple *-1 on the short-value pulled from the Audio Record?), and playback that inverted waveform through the headphones. If the latency and amplitude are close to correct, it should nullify a good amount of mechanical structured noise in the environment.

Here's what I've got so far:

@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();
        }
    }

I was momentarily excited to find the Android API actually already has a NoiseSuppression algorithm (you'll see it commented out above). I tested with it and found NoiseSuppressor wasn't doing much to null out constant tones which leads me to believe it's actually just performing a band-pass filter at non-vocal frequencies.

So, my questions:

1) The above code takes about 250-500ms from mic record through playback in headphones. This latency sucks and it would be great to reduce it. Any suggestions there would be appreciated.

2) Regardless of how tight the latency is, my understanding is that the playback waveform WILL have phase offset from the actual ambient noise waveform. This suggests I need to execute some kind of waveform matching to calculate this offset and compensate. Thoughts on how that gets calculated?

3) When it comes to compensating for latency, what would that look like? I've got an array of shorts coming in every cycle, so what would a 30ms or 250ms latency look like?

I'm aware of fundamental problems with this approach being that the location of the phone being not next to the head is likely to introduce some error, but I'm hopeful with some either dynamic or fixed latency correction it maybe be possible to overcome it.

Thanks for any suggestions.

Petrozavodsk answered 22/11, 2013 at 20:3 Comment(4)
Theoretically, you might be able to do something for extremely low frequencies, but even that's not realistic.Sorce
Any update on how is your project coming through ?Rambler
Sadly no. I shelved it after coming to the conclusion I couldn't compensate for variable distance from the phone mic to the user's ear. I'd love to pick it back up again but it's not clear where to start now.Petrozavodsk
A single smartphone is not enough for such a project: you need two ones, or a smartphone and a bluetooth headset, some meters apart from the user, which catches sounds and sends them to the user at lightspeed rather than soundspeed. Of course the far microphone should be close to the noise source.Inflammable
A
4

Even if you were able to do something about the latency, it's a difficult problem as you don't know the distance of the phone from the ear, plus there's the fact that distance is not fixed (as the user will move the phone), plus the fact that you don't have a microphone for each ear (so you can't know what the wave will be at one ear until after it's got there, even if you have zero latency)

Having said that, you might be able to do something that could cancel highly periodic waveforms. All you could do though is allow the user to manually adjust the time delay for each ear - as you have no microphones near the ears themselves, you can have no way in your code to know if you're making the problem better or worse.

Annual answered 22/11, 2013 at 23:17 Comment(4)
I hate that this might be true as I don't like to accept that something isn't possible. Even if the solution isn't perfect, I have to believe there is a way to set up a calibration scheme or mechanism to dynamically compensate. I appreciate the feedback and upvoted, though :)Petrozavodsk
I can't see that you can do any calibration or compensation unless you involve the user, and that process is likely to be more annoying to them than the noise itself, especially if they have some of those tight-fitting earbuds that block out a lot of noise anyway! And again it only helps for very periodic or predictable noise. Real-world environmental noise is not like that, so you get into the realm of having to predict the future... still, it might be interesting to try something with calibration to work on very periodic external noise (probably low frequency, as Bjorn Roche says)Sibella
SONY Xperia Z2 seems to have taken a shot of this. Check out androidheadlines.com/page/2 . As you have correctly pointed out, user is involved to some extent in deciding the noise cancellation schemeRambler
From forum.xda-developers.com/showthread.php?t=2743254 it looks like the special headphones you need to use have a mic mounted on the outside of one of the headphones, which would solve some of the distance-related problems.Sibella

© 2022 - 2024 — McMap. All rights reserved.