variable showing strange value when implementing NLMS algorithm in Android

260 Views Asked by At

I have been scratching my head about this all day and have run out of ideas now, so I am posting this here

I am trying to implement a feedback suppressor in Android using the NLMS algorithm
I use an AudioRecord to obtain audio samples from the MIC and AudioTrack to play it back. I read in 1 sample at a time as a short variable, convert it to double, pass it through my algorithm, convert it back to short and send it to the speaker. However, I am getting weird values in the intermediate variable and canot understand why it is happening. Here is the code:

public class MainActivity extends Activity {
    AudioManager am = null;
    AudioRecord record =null;
    AudioTrack track =null;
    final int SAMPLE_FREQUENCY = 16000; // ORIGINAL 44100
    final int SIZE_OF_RECORD_ARRAY = 1;     // 1024 ORIGINAL; 1000 / 40 = 25
    // final int WAV_SAMPLE_MULTIPLICATION_FACTOR = 1;
    final double WAV_SAMPLE_MULTIPLICATION_FACTOR = 0.5;
    final int N = 4; // ORIGINAL 40
    final int FEEDBACK_DELAY_IN_MSEC = 1;   // use small integer values here to keep the calculation of NO_OF_DELAY_SAMPLES from becoming non-whole number
    // final int NO_OF_DELAY_SAMPLES = SAMPLE_FREQUENCY / (FEEDBACK_DELAY_IN_MSEC * 1000); // NO_OF_DELAY_SAMPLES = 16
    final int NO_OF_DELAY_SAMPLES = 0; 
    final int TOTAL_SIZE_OF_X = N + NO_OF_DELAY_SAMPLES;
    int i = 0, n = 0; // n represents nth sample
    boolean isPlaying = false; // represents if the Pass Through button is pressed
    boolean applyDsp = false; // represents if the Apply Filter button is pressed
    boolean bufferFull = false;
    private volatile boolean keepThreadRunning;
    double[] w = new double[N];     // w represents filter coefficients
    double[] x = new double[TOTAL_SIZE_OF_X];
    double e; 
    double d;
    double send_out;
    double mu;
    double y = 0;

    // /*
    private RandomAccessFile stateFile;
    String stateFileLoc = Environment.getExternalStorageDirectory().getPath();
    FileDescriptor fd;
    // */

    class MyThread extends Thread{
        private volatile boolean needsToPassThrough;
        // /*
        MyThread(){
            super();
        }

        MyThread(boolean newPTV){
            this.needsToPassThrough = newPTV;
        }
        // */

        // /*
        @Override
        public void run(){
            short[] lin = new short[SIZE_OF_RECORD_ARRAY];
            short[] speaker = new short[SIZE_OF_RECORD_ARRAY];
            double speaker_double;
            int num = 0;
            Log.d("MYLOG", "ENTERED RUN");
            if(needsToPassThrough){
                record.startRecording();
                track.play();
                Log.d("MYLOG", "COMES HERE BEFORE BTN PRESS?");
            }
                        n = TOTAL_SIZE_OF_X -1;
            while (keepThreadRunning) { // thread runs until this loop stops; this loop runs as long as the program is running
                num = record.read(lin, 0, SIZE_OF_RECORD_ARRAY);
                for(i=0;i<lin.length;i++)
                    d = (double)lin[i];         // this line requires that lin[] has to be a single element array 
                if(isPlaying){
                    if(applyDsp){
                        y=0.0; // initialize every time
                        for(i=0; i<N; i++){
                           y += w[N-1-i] * x[n-i - NO_OF_DELAY_SAMPLES];
                        }

                        // Implementing step 2
                        e = d - y;

                        // /*
                        try {
                            stateFile.writeDouble(e);
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }

                        // Implementing step 3
                        mu = 0.5 / (x[n] * x[n] + 0.01);

                        // Implementing step 4
                        for(i=0; i<N; i++){
                               w[N-1-i] = w[N-1-i] + 2.0*mu*e*x[n-i - NO_OF_DELAY_SAMPLES];
                        }
                    } // closing of if(applyDsp) block

                    // Implementing step 5
                        for(i=0;i<TOTAL_SIZE_OF_X-1;i++){
                            x[i] = x[i+1];
                        }

                    send_out = e;   
                    speaker_double = send_out * WAV_SAMPLE_MULTIPLICATION_FACTOR;

                    // implementing step 6
                    x[TOTAL_SIZE_OF_X -1] = speaker_double;

                    for(i=0;i<speaker.length; i++)
                        speaker[i] = (short)speaker_double;

                    track.write(speaker, 0, num);
                } // if(isPlaying) block closed; this represents if the "Pass Through" button has been clicked

            } // while (keepThreadRunning) closes here; this infinite loop runs as long as the program is running 
            record.stop();
            track.stop();
            record.release();
            track.release();
        }

        public void stopThread(){
            keepThreadRunning = false;
        }

    } // End of MyThread class

    MyThread newThread;  

I have just included that part of the code that contains the Thread which performs the NLMS to keep it short. Since SIZE_OF_RECORD_ARRAY is 1, the lin variable in num = record.read(lin, 0, SIZE_OF_RECORD_ARRAY); will always be a short array with just one element. (in fact, anu double or short array that may be encountered in the above code will just have a single element). the line e = d - y is key here. d is the value I get from the mic (d is short typecasted to double). During every run of the while (keepThreadRunning) { infinite loop, a new value for e should be calculated, which is later typecasted to short and passed to the AudioTrack. The problem is that e is not getting proper values in my case, and there is no output from the speakers. If I send the variable d to the AudioTrack, whatever input is spoken in to the microphone appears at the output (with a slight delay, but that is expected). If I try to write the e variable values to file, I am getting strange values. Since using String.valueOf(e) did not work out for me (each string character is considered as a 16-bit character and so 0 appears as <space>0, -1 appears as <space>-<space>1), I directly wrote the double value to file using RandomAccessFile.write Double and viewed the file in a hex viewer. It seems that there is some random value at the beginning of the file, after which a pattern emerges, which I am not sure why it is there. A screenshot of the hex file is shown below:

enter image description here

The pattern shown continues till the end of file. Why is this happening? Since there was no output I assumed at least everything should have been 0, but as can be seen from this figure it's not 0 either, instead it is 7F F8 00 00 00 00 00 00 repeated again and again. Please help me determine why this is happening.

PS: The boolean values isPlaying and applyDsp represent the state of two buttons that I have on the interface. When I press the applyDsp button on the interface, the speaker makes a very short and relatively loud "pop" sound, which I assume may be the reason for the random values in the beginning of the file containing the values of e shown above, but I am not sure about this, and I am not sure abput why that popping noise is there in the first place.

0

There are 0 best solutions below