views:

269

answers:

0

Ok so I have a frequency generator which uses AudioTrack to send PCM data to the hardware. Here's the code I'm using for that:

private class playSoundTask extends AsyncTask<Void, Void, Void> {
  float frequency;
  float increment;
  float angle = 0;
  short samples[] = new short[1024];

  @Override
  protected void onPreExecute() {
   int minSize = AudioTrack.getMinBufferSize( 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT );        
   track = new AudioTrack( AudioManager.STREAM_MUSIC, 44100, 
     AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, 
     minSize, AudioTrack.MODE_STREAM);
   track.play();
  }

  @Override
  protected Void doInBackground(Void... params) {
   while( Main.this.isPlaying)
   {
    for( int i = 0; i < samples.length; i++ )
    {
     frequency = (float)Main.this.slider.getProgress();
     increment = (float)(2*Math.PI) * frequency / 44100;
     samples[i] = (short)((float)Math.sin( angle )*Short.MAX_VALUE);
     angle += increment;
    }

    track.write(samples, 0, samples.length);
   }
   return null;
  }
 }

The frequency is tied to a slide bar, and the correct value is being reported in the sample generation loop. Everything is fine and dandy when I start the app. When you drag your finger along the slide bar you get a nice sweeping sound. But after around 10 seconds of playing around with it, the audio starts to get jumpy. Instead of a smooth sweep, it's staggered, and only changes tone around every 1000 Hz or so. Any ideas on what could be causing this?

Here's all the code in case the problem lies somewhere else:

    public class Main extends Activity implements OnClickListener, OnSeekBarChangeListener {
 AudioTrack track;
 SeekBar slider;
 ImageButton playButton;
 TextView display; 

 boolean isPlaying=false;

 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);

  display = (TextView) findViewById(R.id.display);
  display.setText("5000 Hz");

  slider = (SeekBar) findViewById(R.id.slider);
  slider.setMax(20000);
  slider.setProgress(5000);
  slider.setOnSeekBarChangeListener(this);


  playButton = (ImageButton) findViewById(R.id.play);
  playButton.setOnClickListener(this);

 }

 private class playSoundTask extends AsyncTask<Void, Void, Void> {
  float frequency;
  float increment;
  float angle = 0;
  short samples[] = new short[1024];

  @Override
  protected void onPreExecute() {
   int minSize = AudioTrack.getMinBufferSize( 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT );        
   track = new AudioTrack( AudioManager.STREAM_MUSIC, 44100, 
     AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, 
     minSize, AudioTrack.MODE_STREAM);
   track.play();
  }

  @Override
  protected Void doInBackground(Void... params) {
   while( Main.this.isPlaying)
   {
    for( int i = 0; i < samples.length; i++ )
    {
     frequency = (float)Main.this.slider.getProgress();
     increment = (float)(2*Math.PI) * frequency / 44100;
     samples[i] = (short)((float)Math.sin( angle )*Short.MAX_VALUE);
     angle += increment;
    }

    track.write(samples, 0, samples.length);
   }
   return null;
  }
 }



 @Override
 public void onProgressChanged(SeekBar seekBar, int progress,
   boolean fromUser) {
  display.setText(""+progress+" Hz");
 }

 public void onClick(View v) {
  if (isPlaying) {
   stop();
  } else {
   start();
  }
 }

 public void stop() {
  isPlaying=false;
  playButton.setImageResource(R.drawable.play);
 }

 public void start() {
  isPlaying=true;
  playButton.setImageResource(R.drawable.stop);
  new playSoundTask().execute();
 }

 @Override
 protected void onResume() {
  super.onResume();

 }

 @Override
 protected void onStop() {
  super.onStop();
  //Store state
  stop();

 }


 @Override
 public void onStartTrackingTouch(SeekBar seekBar) {
  // TODO Auto-generated method stub

 }


 @Override
 public void onStopTrackingTouch(SeekBar seekBar) {
  // TODO Auto-generated method stub

 }
}