均衡器,BiQuad过滤器噼啪声

时间:2014-01-28 18:51:50

标签: java android audio decoder equalizer

我正在编写一个媒体播放器Android应用程序。

我想使用AudioTrack类,因为我想使用一个超过5个波段的均衡器。

我的问题是,我解码.mp3文件并使用AudioTrack播放示例。这很好用,但是当我使用BiQuad peakEq滤波器时,我的轨道在我想要提升的频率处噼啪作响。

这是我的代码:

Player.java:

 public class Player {

        private static final String TAG = Player.class.getSimpleName();

        public short[] buffer;
        public boolean firstStart = false;
        public static volatile int position = 0;

        public static short[] decode(String path, int startMs, int maxMs)
                throws IOException, DecoderException {
            short[] pcm = new short[16070400];
            int position = 0;
            float totalMs = 0;
            boolean seeking = true;
            File file = new File(path);
            InputStream inputStream = new BufferedInputStream(new FileInputStream(
                    file), (8 * 1024));
            try {
                Bitstream bitstream = new Bitstream(inputStream);
                Decoder decoder = new Decoder();
                boolean done = false;
                while (!done) {
                    Header frameHeader = bitstream.readFrame();
                    if (frameHeader == null) {
                        done = true;
                    } else {
                        totalMs += frameHeader.ms_per_frame();
                        if (totalMs >= startMs) {
                            seeking = false;
                        }
                        if (!seeking) {
                            SampleBuffer output = (SampleBuffer) decoder
                                    .decodeFrame(frameHeader, bitstream);
                            if (output.getSampleFrequency() != 44100
                                    || output.getChannelCount() != 2) {
                                throw new DecoderException(
                                        "mono or non-44100 MP3 not supported", null);
                            }
                            short[] buffer = output.getBuffer();
                            for (int i = 0; i < buffer.length; i++) {
                                pcm[position] = buffer[i];
                                position++;
                            }
                        }
                        if (totalMs >= (startMs + maxMs)) {
                            done = true;
                        }
                    }
                    bitstream.closeFrame();
                }
                Log.i(TAG, "position " + position);
                return pcm;
            } catch (BitstreamException e) {
                throw new IOException("Bitstream error: " + e);
            } catch (DecoderException e) {
                Log.w(TAG, "Decoder error", e);
                throw new DecoderException(maxMs, e);
            } finally {
            }
        }

        private void fillBuffer(short[] samples) {

            BiQuad filter = new BiQuad(FilterType.PEAK, (63.0 / 44100.0), 0.707, 5.0);

            for (int i = 0; i < buffer.length; i++) {
                buffer[i] = (short) filter.process(buffer[i]);
            }
        }

        public void playWithAudioTrack() throws IllegalArgumentException,
                SecurityException, IllegalStateException, IOException,
                DecoderException {

            new Thread(new Runnable() {

                @Override
                public void run() {

                    try {
                        String path = "/storage/sdcard0/Music/lordi.mp3";
                        MediaPlayer mPlayer = new MediaPlayer();
                        mPlayer.setDataSource(path);
                        mPlayer.prepare();
                        int durationMs = mPlayer.getDuration();

                        if (!firstStart) {
                            buffer = decode(path, 0, durationMs);
                        }

                        fillBuffer(buffer);

                        int minSize = AudioTrack.getMinBufferSize(44100,
                                AudioFormat.CHANNEL_OUT_STEREO,
                                AudioFormat.ENCODING_PCM_16BIT);
                        AudioTrack track = new AudioTrack(
                                AudioManager.STREAM_MUSIC, 44100,
                                AudioFormat.CHANNEL_OUT_STEREO,
                                AudioFormat.ENCODING_PCM_16BIT, minSize,
                                AudioTrack.MODE_STREAM);

                        track.play();

                        for (int i = 0; i < buffer.length; i++) {
                            track.write(buffer, i, buffer.length);
                        }

                        track.release();
                        firstStart = true;

                    } catch (IllegalArgumentException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (SecurityException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IllegalStateException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    // TODO Auto-generated method stub
                    catch (DecoderException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } finally {

                    }
                }
            }).start();
        }
    }

这里是BuQuad.java:

public class BiQuad
{   


 FilterType filterType;

    double a0, a1, a2, b1, b2;  

    double Fc, Q, peakGain;

    double z1, z2;



    public enum FilterType
    {
        LOWPASS,
        HIGHPASS,
        BANDPASS,
        NOTCH,
        PEAK,
        LOWSHELF,
        HIGHSHELF;
    };

    public float process(float in)
    {
        double out = in * a0 + z1;
        z1 = in * a1 + z2 - b1 * out;
        z2 = in * a2 - b2 * out;
        return (float)out;
    }


    public BiQuad()
    {
        filterType = FilterType.LOWPASS;
        a0 = 1.0f;
        a1 = a2 = b1 = b2 = 0.0f;
        Fc = 0.50f;
        Q = 0.707f;
        peakGain = 0.0f;
        z1 = z2 = 0.0f;
    }

    public BiQuad(FilterType filterType, double Fc, double Q, double peakGainDB)
    {
         setBiquad(filterType, Fc, Q, peakGainDB);
         z1 = z2 = 0.0f;
    }


    public void setType(FilterType filterType) {
        this.filterType = filterType;
        calcBiquad();
    }

    public void setQ(double Q) {
        this.Q = Q;
        calcBiquad();
    }

    public void setFc(double Fc) {
        this.Fc = Fc;
        calcBiquad();
    }

    public void setPeakGain(double peakGainDB) {
        this.peakGain = peakGainDB;
        calcBiquad();
    }

    public void setBiquad(FilterType filterType, double Fc, double Q, double peakGainDB) {
        this.filterType = filterType;
        this.Q = Q;
        this.Fc = Fc;
        setPeakGain(peakGainDB);
    }

    public void calcBiquad() {
        double norm;
        double V = Math.pow(10, Math.abs(peakGain) / 20.0);
        double K = Math.tan(Math.PI * Fc);
        switch (this.filterType) {
            case LOWPASS:
                norm = 1 / (1 + K / Q + K * K);
                a0 = K * K * norm;
                a1 = 2 * a0;
                a2 = a0;
                b1 = 2 * (K * K - 1) * norm;
                b2 = (1 - K / Q + K * K) * norm;
                break;

            case HIGHPASS:
                norm = 1 / (1 + K / Q + K * K);
                a0 = 1 * norm;
                a1 = -2 * a0;
                a2 = a0;
                b1 = 2 * (K * K - 1) * norm;
                b2 = (1 - K / Q + K * K) * norm;
                break;

            case BANDPASS:
                norm = 1 / (1 + K / Q + K * K);
                a0 = K / Q * norm;
                a1 = 0;
                a2 = -a0;
                b1 = 2 * (K * K - 1) * norm;
                b2 = (1 - K / Q + K * K) * norm;
                break;

            case NOTCH:
                norm = 1 / (1 + K / Q + K * K);
                a0 = (1 + K * K) * norm;
                a1 = 2 * (K * K - 1) * norm;
                a2 = a0;
                b1 = a1;
                b2 = (1 - K / Q + K * K) * norm;
                break;

            case PEAK:
                if (peakGain >= 0) {    // boost
                    norm = 1 / (1 + 1/Q * K + K * K);
                    a0 = (1 + V/Q * K + K * K) * norm;
                    a1 = 2 * (K * K - 1) * norm;
                    a2 = (1 - V/Q * K + K * K) * norm;
                    b1 = a1;
                    b2 = (1 - 1/Q * K + K * K) * norm;
                }
                else {    // cut
                    norm = 1 / (1 + V/Q * K + K * K);
                    a0 = (1 + 1/Q * K + K * K) * norm;
                    a1 = 2 * (K * K - 1) * norm;
                    a2 = (1 - 1/Q * K + K * K) * norm;
                    b1 = a1;
                    b2 = (1 - V/Q * K + K * K) * norm;
                }
                break;
            case LOWSHELF:
                if (peakGain >= 0) {    // boost
                    norm = 1 / (1 + Math.sqrt(2.0) * K + K * K);
                    a0 = (1 + Math.sqrt(2.0*V) * K + V * K * K) * norm;
                    a1 = 2 * (V * K * K - 1) * norm;
                    a2 = (1 - Math.sqrt(2.0*V) * K + V * K * K) * norm;
                    b1 = 2 * (K * K - 1) * norm;
                    b2 = (1 - Math.sqrt(2.0) * K + K * K) * norm;
                }
                else {    // cut
                    norm = 1 / (1 + Math.sqrt(2.0*V) * K + V * K * K);
                    a0 = (1 + Math.sqrt(2.0) * K + K * K) * norm;
                    a1 = 2 * (K * K - 1) * norm;
                    a2 = (1 - Math.sqrt(2.0) * K + K * K) * norm;
                    b1 = 2 * (V * K * K - 1) * norm;
                    b2 = (1 - Math.sqrt(2.0*V) * K + V * K * K) * norm;
                }
                break;
            case HIGHSHELF:
                if (peakGain >= 0) {    // boost
                    norm = 1 / (1 + Math.sqrt(2.0) * K + K * K);
                    a0 = (V + Math.sqrt(2.0*V) * K + K * K) * norm;
                    a1 = 2 * (K * K - V) * norm;
                    a2 = (V - Math.sqrt(2.0*V) * K + K * K) * norm;
                    b1 = 2 * (K * K - 1) * norm;
                    b2 = (1 - Math.sqrt(2.0) * K + K * K) * norm;
                }
                else {    // cut
                    norm = 1 / (V + Math.sqrt(2.0*V) * K + K * K);
                    a0 = (1 + Math.sqrt(2.0) * K + K * K) * norm;
                    a1 = 2 * (K * K - 1) * norm;
                    a2 = (1 - Math.sqrt(2.0) * K + K * K) * norm;
                    b1 = 2 * (K * K - V) * norm;
                    b2 = (V - Math.sqrt(2.0*V) * K + K * K) * norm;
                }
                break;
        }
    }
}

我不知道问题出在哪里......

我希望有人可以帮助我!

1 个答案:

答案 0 :(得分:0)

我没有真正检查后面的数学计算(只是对这个主题不太了解)。我刚刚认识到的是,大多数计算都没有检查值的溢出。 这将以某种方式与你的解释相匹配,它适用于0dB设置和降低放大率。