java - 从字节数组wav文件中删除噪声

时间:2012-04-30 11:08:49

标签: java android audio fft lowpass-filter

有人能给我看一个从byte[]声音中消除白噪声的算法吗?我为Android的个人录音应用程序工作,我使用Android API进行录制。以下是用于将记录写入文件的方法(采用wav格式)。

 private AudioRecord.OnRecordPositionUpdateListener updateListener = new AudioRecord.OnRecordPositionUpdateListener()
 {
    public void onPeriodicNotification(AudioRecord recorder)
    {
        aRecorder.read(buffer, 0, buffer.length);
        try
        { 
            fWriter.write(buffer); // Write buffer to file
            payloadSize += buffer.length;
            if (bSamples == 16)
            {
                for (int i=0; i<buffer.length/2; i++)
                { // 16bit sample size
                    short curSample = getShort(buffer[i*2], buffer[i*2+1]);
                    if (curSample > cAmplitude)
                    { // Check amplitude
                        cAmplitude = curSample;
                    }
                }
            }
            else
            { // 8bit sample size
                for (int i=0; i<buffer.length; i++)
                {
                    if (buffer[i] > cAmplitude)
                    { // Check amplitude
                        cAmplitude = buffer[i];
                    }
                }
            }
        }
        catch (IOException e)
        {
            Log.e(AudioRecorder2.class.getName(), "Error occured in updateListener, recording is aborted");
        }
    }

    public void onMarkerReached(AudioRecord recorder)
    {}
};

我想应用一些转换来缓冲,以消除在录制回放过程中可以听到的白噪声。 如果有人知道某些低通滤波器的算法/链接(或任何可能有帮助的其他东西),请帮忙。

感谢。

3 个答案:

答案 0 :(得分:1)

如果你知道,你可以对样本取平均值: 采样频率(8,16,32,64,128)和 比特深度(8,16,32)和 录制的频道(单声道,立体声)。

.wav音频是以交替的通道写入的,或者以比特深度的大小交错排列。 (我认为它从左声道开始)

16kHz 16位是一个短[],每秒有16,000个条目音频

64kHZ 32位是int [],64,000“”

你可以平均从立体声到单声道的16位通道(短[偶数] +短[奇]] / 2

你可以平均16位频率128kHz到16kHz(8比1)短[0,2,4,6,8,10,12,14] / 8

平均低于16kHZ频率可能听起来更糟

根据音量的量化方式(模拟数字线性或对数a-law / u-law / linear),您可能需要尝试不同的方法。

答案 1 :(得分:0)

实现低通的最简单方法是平均多个样本。所以,如果您有n个样本,您可以这样做:

// your sample data array
int[] samples
//number of samples you want to average
int AVERAGE_SAMPLE_COUNT = 3;

for(int i=0; i<samples.length-AVERAGE_SAMPLE_COUNT; i++){
    //variable for storing the values of multiple samples
    int avgSample = 0;
    for(int a=0; a<AVERAGE_SAMPLE_COUNT; a++){
        //add up the current and the next n samples
        avgSample += samples[i+a]
    }
    //devide by the number of samples to average them
    avgSample /= AVERAGE_SAMPLE_COUNT;
    //replace first sample with the averaged value
    samples[i] = avgSample
}

正如您所看到的,唯一的缺陷可能是输出变短AVERAGE_SAMPLE_COUNT。您可以通过更改AVERAGE_SAMPLE_COUNT轻松尝试不同强度的算法。 此外,它正在就地工作,这意味着它会更改您的初始输入数据。

答案 2 :(得分:0)

另一种方法是在预处理阶段进行以下操作,

recorder.read(data, 0, data.length);
if(isAudible(data)) {
    // TODO further processing can go here
}

public static boolean isAudible(short[] data) {
    double rms = getRootMeanSquared(data);
    return (rms > 198 && 5600 > rms);
}

public static double getRootMeanSquared(short[] data) {
    double ms = 0;
    for (int i = 0; i < data.length; i++) {
        ms += data[i] * data[i];
    }
    ms /= data.length;
    return Math.sqrt(ms);
}