2014-07-16 4 views
3

Android 앱에서 작업 중이며 짧은 소리 (~ 2 초)를 연주하고 싶습니다. Soundpool을 시도했지만 사운드가 이미 재생 중인지 확인할 수 없기 때문에 실제로는 적합하지 않습니다. 그래서 AudioTrack을 사용하기로 결정했습니다.Android : AudioTrack이 시작시 딸깍 소리가납니다.

소리가 나기 시작하면 대부분 "소리가납니다"라는 소리가납니다. 오디오 파일을 검사했는데 깨끗합니다.

스트리밍 모드에서 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에 audiotrack을 구현하는 방법을 보여줄 수 있습니까? 감사합니다.

답변

1

마지막으로, 많은 실험을 거쳐 클릭 노이즈없이 작동 시켰습니다. 여기

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 기능을 사용하는 것입니다 건너 (필자는 getChannel().size() 방법은 FileInputStream의 유형과 작동 이후의 InputStream의 크기를 읽을 수없는, unfortunaly) 내 코드입니다 오디오 파일의 시작 부분을 건너 뜁니다. (아마 헤더 일 수도 있고, 내가 모르는 부분 일 수도 있습니다.) 이 코드 부분이 도움이되기를 바랍니다. 원시 ressource를로드하는 방법을 찾지 않고 정적 모드 코드 샘플을 찾으려고 너무 많은 시간을 보냈습니다.

편집 :이 솔루션을 다양한 장치에서 테스트 한 결과 어차피 딸깍하는 소리가 들리는 것으로 보입니다.

+0

wav 파일에서 재생 하시겠습니까? 그런 다음 헤더가 (대부분) 그 크기이기 때문에 처음 44 바이트를 건너 뛰는 것으로 충분할 것입니다. 스트림에 이미있는 바이트를 건너 뛰는 것이 더 좋습니다. inputStream.skip (44) – Chris623

+0

내 대답과 해결책이 표시되고 받아 들여진 응답 틱을 이동해야합니다.) –

1

오디오 "팝"의 일반적인 원인은 제로 크로스 오버 포인트에서 시작/정지 사운드가 아닌 렌더링 프로세스 때문입니다 (최소/최대 -1에서 +1 교차가 0이라고 가정). 스피커 또는 귀 봉우리와 같은 트랜스 듀서는이 제로 크로스에 매핑되는 (사운드 입력 없음) 상태입니다. 오디오 렌더링 프로세스가이 제로에서 시작/중지하지 못하면 트랜스 듀서는 불가능을합니다. 즉 순간적으로 휴식 상태에서 최소/최대 이동 범위 (또는 비자 그 반대의 경우에는 "팝"이 나타납니다).

+0

그래서 오프셋으로 트랙을 재생해야합니까? – Bartho

+0

일부 표준 도구를 사용하여 동일한 오디오 트랙을 수동으로 재생 ... 팝 소리가 들립니까? –

+0

사운드 풀 플레이어에서 나는이 팝을 가지고 있지 않았다 (더 높은 레벨의 플레이어이기 때문에보다 잘 구성되어야 함). 해결책을 찾았고 대답으로 썼습니다. – Bartho

1

"setPlaybackHeadPosition"이 작동하려면 먼저 재생하고 일시 중지해야합니다. 트랙이 정지되거나 시작되지 않으면 작동하지 않습니다. 날 믿어. 이것은 바보입니다. 하지만 작동합니다 :

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

Scott Stensland의 추론이 내 문제에 적합하다는 것을 알았습니다 (감사합니다!).

샘플 배열의 시작 부분에 죽은 단순 선형 페이드 인 필터를 실행하여 팝을 제거했습니다. 필터는 샘플 값을 0에서 시작하고 진폭이 원래 값으로 천천히 증가하도록합니다. 항상 제로 크로스 오버 포인트에서 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]); 
     } 
    } 
} 
관련 문제