2014-01-28 116 views
0

我正在編程一個媒體播放器的Android應用程序。均衡器,BiQuad濾波器劈啪

我想使用AudioTrack類,因爲我想使用具有5個以上波段的均衡器。

我的問題是,我將解碼.mp3文件並使用AudioTrack播放示例。這很好,但是當我使用BiQuad peakEq過濾器時,我的音軌在我想要增強的頻率處發出crack啪聲。

這裏是我的代碼:

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; 
     } 
    } 
} 

我不知道是什麼問題...

我希望這裏有人能請幫幫我!

回答

0

我沒有真正檢查後面的數學計算(只是不太瞭解這個主題)。我剛剛認識到的是,大多數計算不檢查值的溢出。 這將以某種方式與您的解釋相匹配,即它適用於0dB設置和降低放大率。