我整天都在摸索这个问题,现在已经没有想法了,所以我把这个贴在这里
我正在尝试使用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:布尔值isPlaying
和applyDsp
代表我在界面上的两个按钮的状态。当我按下applyDsp
界面上的按钮时,扬声器会发出很短且相对响亮的“pop”声,我认为这可能是文件开头包含e
上面显示的值的随机值的原因,但我是不确定这一点,我不确定为什么首先会出现爆裂声。