2014-04-27 3 views
1

계속적인 사인파 스트림을 재생하려고합니다. 버튼을 길게 누르면 사인파의 주파수가 변경됩니다. 버튼을 놓으면 정상 주파수로 돌아갑니다.AudioTrack에서 예기치 않은 소리가 출력됩니다.

다음 코드를 실행하면 출력 사운드에 순수 사인 톤이 아닌 정기적 인 클릭 (약 음압 변화) (초당 약 5 번의 클릭)이 발생합니다.

재미있는 행동은 C5 버튼을 누르고있을 때 아무런 클릭이 발생하지 않는다는 것입니다. 그러나 C4 버튼을 길게 누르면 클릭 수가 계속 유지됩니다.

이 문제의 근본 원인은 무엇입니까? 당신이 사인파 전체 samples 버퍼를 채우는 것 같은

public class MainActivity extends Activity { 
Thread t; 
private Button buttonC4, buttonC5; 

float buttonC4_val = 0; 
float buttonC5_val = 0; 

int sr = 44100; 
boolean isRunning = true; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    // button initialization 
    buttonC4 = (Button) this.findViewById(R.id.button_c4); 
    buttonC5 = (Button) this.findViewById(R.id.button_c5); 

    buttonC4.setOnTouchListener(new OnTouchListener() { 
     @Override 
     public boolean onTouch(View v, MotionEvent event) { 
      switch(event.getAction()) 
      { 
      case MotionEvent.ACTION_DOWN: 
       //insert code here 
       buttonC4_val = 300; 
       buttonC4.setText("You Clicked ME!!!"); 
       return true; 
      case MotionEvent.ACTION_UP: 
       //insert code here 
       buttonC4_val = 0; 
       buttonC4.setText("C4"); 
       return true; 
      } 
      return false; 
     } 
    }); 

    buttonC5.setOnTouchListener(new OnTouchListener() { 
     @Override 
     public boolean onTouch(View v, MotionEvent event) { 
      switch(event.getAction()) 
      { 
      case MotionEvent.ACTION_DOWN: 
       //insert code here 
       buttonC5_val = 500; 
       buttonC5.setText("You Clicked ME!!!"); 
       return true; 
      case MotionEvent.ACTION_UP: 
       //insert code here 
       buttonC5_val = 0; 
       buttonC5.setText("C5"); 
       return true; 
      } 
      return false; 
     } 
    }); 

    t = new Thread() { 
     public void run() { 
      setPriority(Thread.MAX_PRIORITY); 

    int bufferSize = AudioTrack.getMinBufferSize(sr, 
      AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT); 

    AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sr, 
      AudioFormat.CHANNEL_OUT_MONO, 
      AudioFormat.ENCODING_PCM_16BIT, 
      bufferSize, 
      AudioTrack.MODE_STREAM); 

    audioTrack.play(); 

    // synthesis loop 
    while(isRunning){     
      double upFreq = (double) buttonC4_val + (double) buttonC5_val; 
     short samples[] = new short[bufferSize]; 
      int amp = 10000; 
      double twopi = 8.*Math.atan(1.); 
      double fr = 440.f; 
      double ph = 0.0;     
      fr = 440 + upFreq; 

      for(int i=0; i < bufferSize; i++){ 
     samples[i] = (short) (amp*Math.sin(ph)); 
     ph += twopi*fr/sr; 
      } 

     audioTrack.write(samples, 0, bufferSize); 
      } 
    audioTrack.stop(); 
    audioTrack.release(); 
     } 
    }; 
    t.start(); 
} 
} 

답변

2

같습니다 - bufferSize 당신이 웨이브를 통해 부분적으로 될거야 후 발생하고있는 주파수의 배수가 아닌 경우 때 다음 샘플이 재생되기 시작합니다. 그게 팝의 원인 일 수 있습니다.

Amazing diagram

당신은 bufferSize을 변경하고이 터지는의 주파수를 변경하는 경우보고하여이를 테스트 할 수 있습니다. 버퍼가 커지면 이러한 샘플 불일치가 자주 발생하지 않아야하므로 터지는 빈도를 줄여야합니다.

용액 마지막 0 교차점의 버퍼의 위치를 ​​교체 bufferSize

audioTrack.write(samples, 0, bufferSize); 

변경하는 것이다.