Android IIR低通滤波器噪音

时间:2016-04-17 12:23:29

标签: android audio filtering signal-processing waveform

我让合成器能够生成三种基本类型的声音并对其进行过滤。对于过滤,我使用了TarsosDSP中的代码。

然而,声音的过滤是正确的,但是有很多噪音,这比声音本身更响亮。 我没有对代码进行任何重大更改,只添加了转换浮点数 - >简而言之,因为我使用Audiotrack的短裤缓冲区。

以下是代码:

int amp = 32767;
double phase = 0.0;
float cutOffFrequency = 200;

protected void onCreate(Bundle savedInstanceState) {
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        AudioManager myAudioMgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        String nativeParam = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
        sampleRate = Integer.parseInt(nativeParam);
        nativeParam = myAudioMgr.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
        bufSize = Integer.parseInt(nativeParam);
    }
    else {
        sampleRate = 44100;
        bufSize = AudioTrack.getMinBufferSize(sampleRate,
                AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
    }

    audioOutput = new AudioOutput();
    audioOutput.Start(sampleRate, bufSize);

    samples = new short[bufSize];

    playTask.execute();
}

class PlayTask extends AsyncTask<Object, Void, Void> {
    @Override
    protected Void doInBackground(Object[] params) {
        android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);

        while (!this.isCancelled()) {
            phase = 0.0;
            while (touched) {
                generateTone();
                generateFilter();
                audioOutput.write(samples, 0, samples.length);
            }
        }
        return null;
    }
}

private void generateTone() {
    double phaseIncrement = (2 * Math.PI) / sampleRate;
    switch (currentShape) {
        case SINE:
            for (int i = 0; i < bufSize; i++) {
                samples[i] = (short) (amp * Math.sin(phase));
                phase += phaseIncrement * freq;
                if (phase > 2 * Math.PI)
                    phase -= 2 * Math.PI;
            }
            break;
        case SAWTOOTH:
            for (int i = 0; i < bufSize; i++) {
                samples[i] = (short) (amp * (phase - amp));
                phase += phaseIncrement * freq;
                if (phase > 2 * Math.PI)
                    phase -= 2 * Math.PI;
            }
            break;
        case SQUARE:
            for (int i = 0; i < bufSize; i++) {
                if (phase < Math.PI)
                    samples[i] = (short) amp;
                else
                    samples[i] = (short) -amp;
                phase += phaseIncrement * freq;
                if (phase > 2 * Math.PI)
                    phase -= 2 * Math.PI;
            }
            break;
    }
}

private void generateFilter() {
        LowPassFilter lpf = new LowPassFilter(cutOffFrequency, sampleRate);
        samples = lpf.process(samples);
}

public class AudioOutput {

    public void Start(int sampleRate, int bufferSize) {
        Stop();
        mFrameRate = sampleRate;
        mAudioTrack = createAudioTrack(bufferSize);

        mAudioTrack.play();
    }

    private AudioTrack createAudioTrack(int buffsize) {
        return new AudioTrack(AudioManager.STREAM_MUSIC,
                mFrameRate, AudioFormat.CHANNEL_OUT_MONO,
                AudioFormat.ENCODING_PCM_16BIT, buffsize,
                AudioTrack.MODE_STREAM);
    }

    public int write(short[] buffer, int offset, int length) {
        return write = mAudioTrack.write(buffer, offset, length);
    }

    public void Stop() {
        if (mAudioTrack != null) {
            mAudioTrack.stop();
            mAudioTrack.release();
            mAudioTrack = null;
        }
    }
}

public class LowPassFilter extends IIRFilter {

    public LowPassFilter(float freq, int sampleRate) {
        super(freq > 60 ? freq : 60, sampleRate);
    }

    @Override
    protected void calcCoeff() {
        float freqFrac = getFrequency() / getSampleRate();
        float x = (float) Math.exp(-14.445 * freqFrac);
        a = new float[] { (float) Math.pow(1 - x, 4) };
        b = new float[] { 4 * x, -6 * x * x, 4 * x * x * x, -x * x * x * x };
    }
}

public abstract class IIRFilter {

    /** The b coefficients. */
    protected float[] b;

    /** The a coefficients. */
    protected float[] a;

    /**
     * The input values to the left of the output value currently being
     * calculated.
     */
    protected float[] in;

    /** The previous output values. */
    protected float[] out;

    private float frequency;

    private float sampleRate;

    public IIRFilter(float cutOffFreq, int sampleRate) {
        this.sampleRate = sampleRate;
        this.frequency = cutOffFreq;
        calcCoeff();
        in = new float[a.length];
        out = new float[b.length];
    }

    public void setFrequency(float freq){
        this.frequency = freq;
        calcCoeff();
    }

    public float getFrequency() {
        return frequency;
    }

    public float getSampleRate(){
        return sampleRate;
    }

    private float[] getFloatBuffer(short[] buffer) {
        float[] floaters = new float[buffer.length];
        for (int i = 0; i < buffer.length; i++) {
            floaters[i] = buffer[i];
        }
        return floaters;
    }

    private short[] getShortBuffer(float[] buffer) {
        short[] shorts = new short[buffer.length];
        for (int i = 0; i < buffer.length; i++) {
            shorts[i] = (short)buffer[i];
        }
        return shorts;
    }

    protected abstract void calcCoeff() ;

    public short[] process(short[] input) {
        float[] audioFloatBuffer = getFloatBuffer(input);

        for (int i = 0; i < audioFloatBuffer.length; i++) {
            //shift the in array
            System.arraycopy(in, 0, in, 1, in.length - 1);
            in[0] = audioFloatBuffer[i];

            //calculate y based on a and b coefficients
            //and in and out.
            float y = 0;
            for(int j = 0 ; j < a.length ; j++){
                y += a[j] * in[j];
            }
            for(int j = 0 ; j < b.length ; j++){
                y += b[j] * out[j];
            }
            //shift the out array
            System.arraycopy(out, 0, out, 1, out.length - 1);
            out[0] = y;

            audioFloatBuffer[i] = y;
        }
        return getShortBuffer(audioFloatBuffer);
    }
}

这里记录波形,图案随频率变化,频率越低越快。

Waveform

低通滤波器本身应该是正确的,用matlab检查。

Link to wavefile

0 个答案:

没有答案