如何通过将 java(android) 中的 fft 数据置零来过滤音频
how to filter audio by zeroing fft data in java(android)
我正在为 android platform.in 开发基于音频的应用程序,此代码首先我以 wav 格式录制我的声音然后我得到 fft(在 fftbegir 方法中)现在我想用归零的 fft 数据过滤我的声音在 0-4khz 然后执行 ifft 但是当我播放新的 wav 文件时我可以听到非常糟糕的声音和很多噪音。fft class 在这里 http://introcs.cs.princeton.edu/java/97data/FFT.java.html 和这里是我的代码:
private void filter(Complex[] x, int size) throws IOException {
double d, b;
String strI;
byte[] bytes = new byte[2];
int i = 0;
double k = -3.14159;
Complex[] f = new Complex[size];
Complex[] iff;
byte[] ddd;
double[] kkk = new double[size];
FFT q = new FFT();
short shor;
double data9[] = new double[size];
d = 2 * 3.14159 / size;
totalAudioLen = size;
totalDataLen = totalAudioLen + 36;
while (i < size) {//////to make its lenght length power of 2
data9[i] = k;
k = k + d;
i++;
}
i = 0;
while (i < (size / 2) - 2000) {
f[i] = new Complex(x[i].re(), x[i].im());
i++;
}
while (i < (size / 2) + 2000) { ///i want to remov 2000 sample of fft
f[i] = new Complex(0, 0);
i++;
}
while (i < size) {
f[i] = new Complex(x[i].re(), x[i].im());
i++;
}
iff = q.ifft(f);
try {
out9 = new FileOutputStream(getridemal());
out10 = new FileOutputStream(getwavfilter());
out11 = new FileOutputStream(getkhodesh());
WriteWaveFileHeader(out10, totalAudioLen, totalDataLen,
longSampleRate, channels, byteRate);
for (i = 0; i < size; i++) {
b = iff[i].re();
shor = (short) (b * 32768.0);
bytes = ByteConvert.convertToByteArray(shor);
out10.write(bytes, 0, 2);
}
} finally {
out9.close();
out10.close();
out11.close();
}
}
private void fftbegir(String input, String output) {
double[] data8;
int i = 0;
int r, k, l;
double b;
int m = 2;
try {
in5 = new FileInputStream(input);
out5 = new FileOutputStream(output);
AppLog.logString("File size: " + totalDataLen);
totalAudioLen = in5.getChannel().size();
data8 = SoundDataUtils.load16BitPCMRawDataFileAsDoubleArray();
l = data8.length;
while (l > m) {
m = m * 2;
}
Complex[] x = new Complex[m];
while (i < l) {
x[i] = new Complex(data8[i], 0);
i++;
}
in5.close();
i--;
for (i = l; i < m; i++) {
x[i] = new Complex(0, 0);
}
FFT f = new FFT();
Complex[] y = f.fft(x);
filter(y, m);
out5.close();
}
}
谢谢:)
您正在执行的频域滤波效果不佳。
虽然将逆 FFT 应用于 FFT 的结果会产生相同的样本(也就是说,它是可逆的),但当修改系数时,这不再适用。
这里(至少)有几个问题:
- 从通带到阻带的急剧过渡导致的Gibbs Phenomemum
- 事实上,FFT 首先是一个相当糟糕的带通滤波器。阻带中的频率分量出现在几个相邻的频带中,因此保留在信号中。
- 每个 FFT bin 包含实部和虚部。
(0,0)
的复数值具有 0
的大小,但也会在此过程中丢失相位信息。
你最好使用 IIR 带阻滤波器,它在时域中运行。除了按预期工作之外,计算成本也低得多。
我正在为 android platform.in 开发基于音频的应用程序,此代码首先我以 wav 格式录制我的声音然后我得到 fft(在 fftbegir 方法中)现在我想用归零的 fft 数据过滤我的声音在 0-4khz 然后执行 ifft 但是当我播放新的 wav 文件时我可以听到非常糟糕的声音和很多噪音。fft class 在这里 http://introcs.cs.princeton.edu/java/97data/FFT.java.html 和这里是我的代码:
private void filter(Complex[] x, int size) throws IOException {
double d, b;
String strI;
byte[] bytes = new byte[2];
int i = 0;
double k = -3.14159;
Complex[] f = new Complex[size];
Complex[] iff;
byte[] ddd;
double[] kkk = new double[size];
FFT q = new FFT();
short shor;
double data9[] = new double[size];
d = 2 * 3.14159 / size;
totalAudioLen = size;
totalDataLen = totalAudioLen + 36;
while (i < size) {//////to make its lenght length power of 2
data9[i] = k;
k = k + d;
i++;
}
i = 0;
while (i < (size / 2) - 2000) {
f[i] = new Complex(x[i].re(), x[i].im());
i++;
}
while (i < (size / 2) + 2000) { ///i want to remov 2000 sample of fft
f[i] = new Complex(0, 0);
i++;
}
while (i < size) {
f[i] = new Complex(x[i].re(), x[i].im());
i++;
}
iff = q.ifft(f);
try {
out9 = new FileOutputStream(getridemal());
out10 = new FileOutputStream(getwavfilter());
out11 = new FileOutputStream(getkhodesh());
WriteWaveFileHeader(out10, totalAudioLen, totalDataLen,
longSampleRate, channels, byteRate);
for (i = 0; i < size; i++) {
b = iff[i].re();
shor = (short) (b * 32768.0);
bytes = ByteConvert.convertToByteArray(shor);
out10.write(bytes, 0, 2);
}
} finally {
out9.close();
out10.close();
out11.close();
}
}
private void fftbegir(String input, String output) {
double[] data8;
int i = 0;
int r, k, l;
double b;
int m = 2;
try {
in5 = new FileInputStream(input);
out5 = new FileOutputStream(output);
AppLog.logString("File size: " + totalDataLen);
totalAudioLen = in5.getChannel().size();
data8 = SoundDataUtils.load16BitPCMRawDataFileAsDoubleArray();
l = data8.length;
while (l > m) {
m = m * 2;
}
Complex[] x = new Complex[m];
while (i < l) {
x[i] = new Complex(data8[i], 0);
i++;
}
in5.close();
i--;
for (i = l; i < m; i++) {
x[i] = new Complex(0, 0);
}
FFT f = new FFT();
Complex[] y = f.fft(x);
filter(y, m);
out5.close();
}
}
谢谢:)
您正在执行的频域滤波效果不佳。
虽然将逆 FFT 应用于 FFT 的结果会产生相同的样本(也就是说,它是可逆的),但当修改系数时,这不再适用。
这里(至少)有几个问题:
- 从通带到阻带的急剧过渡导致的Gibbs Phenomemum
- 事实上,FFT 首先是一个相当糟糕的带通滤波器。阻带中的频率分量出现在几个相邻的频带中,因此保留在信号中。
- 每个 FFT bin 包含实部和虚部。
(0,0)
的复数值具有0
的大小,但也会在此过程中丢失相位信息。
你最好使用 IIR 带阻滤波器,它在时域中运行。除了按预期工作之外,计算成本也低得多。