2014-07-16 58 views
3

我正在開發一個Android應用程序,我想播放一些簡短的聲音(〜2s)。我試過Soundpool,但它並不適合我,因爲它無法檢查聲音是否已在播放。所以我決定使用AudioTrack。Android:AudioTrack在開始時發出咔噠聲

它工作的很好,但大部分時間,當它開始播放聲音時,會發出「咔嗒」聲。 我檢查了我的audiofiles,他們很乾淨。

我在流模式下使用audiotrack。我發現靜態模式對於短暫的聲音更好,但經過多次搜索後,我仍然不明白如何使其工作。 我也讀過點擊噪音可能是由wav文件的標題引起的,所以如果我用setPlaybackHeadPosition(int positionInFrames)函數(這應該只在靜態模式下工作)跳過此標題,聲音可能會消失

這裏是我的代碼(所以問題是在開始滴答的噪音)

int minBufferSize = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, 
      AudioFormat.ENCODING_PCM_16BIT); 
    audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, 
     AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STREAM); 
audioTrack.play(); 
      int i = 0; 
      int bufferSize = 2048; //don't really know which value to put 
      audioTrack.setPlaybackRate(88200); 

      byte [] buffer = new byte[bufferSize]; 
//there we open the wav file > 
      InputStream inputStream = getResources().openRawResource(R.raw.abordage); 
      try { 
       while((i = inputStream.read(buffer)) != -1) 
        audioTrack.write(buffer, 0, i); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      try { 
       inputStream.close(); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

有沒有人有解決方案,以避免噪音?我試過this,有時可以但不是每次都有效。有人能告訴我如何在MODE_STATIC中實現音頻記錄嗎? 謝謝

回答

1

最後,經過大量的實驗後,我沒有發出咔嗒聲就可以工作。這裏是我的代碼(unfortunaly,因爲getChannel().size()方法只用的FileInputStream類型的作品我無法讀取InputStream的大小)

try{ 
    long totalAudioLen = 0; 
    InputStream inputStream = getResources().openRawResource(R.raw.abordage); // open the file 
    totalAudioLen = inputStream.available(); 
    byte[] rawBytes = new byte[(int)totalAudioLen]; 
    AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, 
             44100, 
             AudioFormat.CHANNEL_CONFIGURATION_MONO, 
             AudioFormat.ENCODING_PCM_16BIT, 
            (int)totalAudioLen, 
            AudioTrack.MODE_STATIC); 
    int offset = 0; 
    int numRead = 0; 

    track.setPlaybackHeadPosition(100); // IMPORTANT to skip the click 
    while (offset < rawBytes.length 
       && (numRead=inputStream.read(rawBytes, offset, rawBytes.length-offset)) >= 0) { 
      offset += numRead; 
    } //don't really know why it works, it reads the file 
    track.write(rawBytes, 0, (int)totalAudioLen); //write it in the buffer? 
    track.play(); // launch the play 
    track.setPlaybackRate(88200); 
    inputStream.close(); 
    } 
    catch (FileNotFoundException e) { 

     Log.e(TAG, "Error loading audio to bytes", e); 
    } catch (IOException e) { 
     Log.e(TAG, "Error loading audio to bytes", e); 
    } catch (IllegalArgumentException e) { 
     Log.e(TAG, "Error loading audio to bytes", e); 
    } 

因此解決的辦法跳過滴答聲是使用MODE_STATICsetPlaybackHeadPosition功能跳過音頻文件的開頭(這可能是頭文件,或者我不知道是什麼)。 我希望這部分代碼能夠幫助某人,我花了太多時間試圖找到一個靜態模式代碼示例,卻沒有找到加載原始資源的方法。

編輯:在各種設備上測試此解決方案後,似乎無論如何它們都有卡嗒聲。

+0

你在播放wav文件嗎?然後,從頭部(大部分)大小開始,跳過前44個字節就足夠了。更好的辦法是跳過流中已有的字節:inputStream.skip(44) – Chris623

+0

您應該看到我的答案和解決方案並移動接受的答案tick;) –

1

音頻「流行」的一個常見原因是由於渲染過程沒有在零交叉點開始/停止聲音(假設-1到+1交叉的最小/最大值爲0)。諸如揚聲器或耳塞之類的傳感器處於靜止狀態(沒有聲音輸入),它映射到零交叉處。如果音頻渲染過程無法從/到這個零點開始/停止,傳感器被要求做不可能的事情,即在其最小/最大移動範圍內瞬時從靜止狀態轉移到某個非零位置(或簽證相反如果你在最後得到一個「流行」)。

+0

所以我必須開始播放帶偏移量的曲目嗎? – Bartho

+0

使用某些標準工具手動播放相同的音軌...您是否還聽到流行音樂? –

+0

隨着soundpool播放器我沒有這個流行(這是一個更高級別的球員,所以它必須更好的配置)。 我找到了解決方案,並將其寫入答案:) – Bartho

1

要使「setPlaybackHeadPosition」正常工作,您必須先播放並暫停。如果您的曲目已停止或未啓動,則它不起作用。相信我。這是愚蠢的。但是,它的工作原理:

track.play(); 
track.pause(); 
track.setPlaybackHeadPosition(100); 
// then continue with track.write, track.play, etc. 
0

我發現斯科特Stensland的推理裝修我的問題(感謝!)。

我通過在示例數組的開頭處運行死亡簡單線性淡入濾波器來消除了彈出窗口。濾波器使採樣值從0開始,並緩慢地增加幅度至其原始值。通過在零交叉點始終以零值開始流行,永遠不會出現流行。

類似的淡出濾波器應用於樣本數組的末尾。過濾器的持續時間很容易調整。

import android.util.Log; 

public class FadeInFadeOutFilter 
{ 
    private static final String TAG = FadeInFadeOutFilter.class.getSimpleName(); 

    private final int filterDurationInSamples; 

    public FadeInFadeOutFilter (int filterDurationInSamples) 
    { 
     this.filterDurationInSamples = filterDurationInSamples; 
    } 

    public void filter (short[] audioShortArray) 
    { 
     filter(audioShortArray, audioShortArray.length); 
    } 

    public void filter (short[] audioShortArray, int audioShortArraySize) 
    { 
     if (audioShortArraySize/2 <= filterDurationInSamples) { 
      Log.w(TAG, "filtering audioShortArray with less samples filterDurationInSamples; untested, pops or even crashes may occur. audioShortArraySize="+audioShortArraySize+", filterDurationInSamples="+filterDurationInSamples); 
     } 
     final int I = Math.min(filterDurationInSamples, audioShortArraySize/2); 

     // Perform fade-in and fade-out simultaneously in one loop. 
     final int fadeOutOffset = audioShortArraySize - filterDurationInSamples; 
     for (int i = 0 ; i < I ; i++) { 
      // Fade-in beginning. 
      final double fadeInAmplification = (double)i/I; // Linear ramp-up 0..1. 
      audioShortArray[i] = (short)(fadeInAmplification * audioShortArray[i]); 

      // Fade-out end. 
      final double fadeOutAmplification = 1 - fadeInAmplification; // Linear ramp-down 1..0. 
      final int j = i + fadeOutOffset; 
      audioShortArray[j] = (short)(fadeOutAmplification * audioShortArray[j]); 
     } 
    } 
}