0

我整天都在摸索这个问题,现在已经没有想法了,所以我把这个贴在这里

我正在尝试使用NLMS 算法
在 Android 中实现反馈抑制器, 我使用 AudioRecord 从 MIC 和 AudioTrack 获取音频样本来播放它。我一次读入 1 个样本作为短变量,将其转换为双精度,通过我的算法,将其转换回短变量并将其发送给扬声器。但是,我在中间变量中得到了奇怪的值,并且无法理解它为什么会发生。这是代码:

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;  

我刚刚包含了包含执行 NLMS 以使其简短的线程的那部分代码。因为SIZE_OF_RECORD_ARRAY是 1,所以lin变量 innum = record.read(lin, 0, SIZE_OF_RECORD_ARRAY);将始终是一个short只有一个元素的数组。(实际上,上面代码中可能遇到的双精度或短数组只会有一个元素)。这条线e = d - y是这里的关键。d 是我从麦克风获得的值(d 是短类型转换为 double)。在while (keepThreadRunning) {无限循环的每次运行期间,应计算 e 的新值,然后将其类型转换为 short 并传递给 AudioTrack。问题是e在我的情况下没有得到正确的值,并且扬声器没有输出。如果我发送变量d对于 AudioTrack,无论对麦克风说什么输入都会出现在输出端(稍有延迟,但这是意料之中的)。如果我尝试将e变量值写入文件,我会得到奇怪的值。由于 usingString.valueOf(e)对我来说不起作用(每个字符串字符被视为 16 位字符,因此0显示为<space>0-1显示为<space>-<space>1),我直接使用 RandomAccessFile.write Double 将双精度值写入文件并在十六进制查看器中查看文件. 文件开头似乎有一些随机值,之后出现了一个模式,我不确定它为什么会在那里。十六进制文件的屏幕截图如下所示:

在此处输入图像描述

显示的模式一直持续到文件末尾。为什么会这样?由于没有输出,我假设至少所有内容都应该为 0,但从该图中可以看出,它也不是 0,而是7F F8 00 00 00 00 00 00一次又一次地重复。请帮助我确定为什么会发生这种情况。

PS:布尔值isPlayingapplyDsp代表我在界面上的两个按钮的状态。当我按下applyDsp界面上的按钮时,扬声器会发出很短且相对响亮的“pop”声,我认为这可能是文件开头包含e上面显示的值的随机值的原因,但我是不确定这一点,我不确定为什么首先会出现爆裂声。

4

0 回答 0