plectrum

Plectrum: instrument tuner for Android
Log | Files | Refs | README | LICENSE

AndroidAudioPlayer.java (5088B)


      1 package be.tarsos.dsp.io.android;
      2 
      3 import android.media.AudioFormat;
      4 import android.media.AudioManager;
      5 import android.media.AudioTrack;
      6 import android.util.Log;
      7 
      8 import be.tarsos.dsp.AudioEvent;
      9 import be.tarsos.dsp.AudioProcessor;
     10 import be.tarsos.dsp.io.TarsosDSPAudioFloatConverter;
     11 import be.tarsos.dsp.io.TarsosDSPAudioFormat;
     12 
     13 /**
     14  * Plays audio from an {@link be.tarsos.dsp.AudioDispatcher} or {@link be.tarsos.dsp.AudioGenerator}
     15  * on an Android {@link AudioTrack}. This class only supports mono, 16 bit PCM. Depending on your device,
     16  * some sample rates could not be supported. This class uses the method that writes floats
     17  * to {@link android.media.AudioTrack} which is only introduced in Android API Level 21.
     18  *
     19  * @author Alex Mikhalev
     20  * @author Joren Six
     21  * @see AudioTrack
     22  */
     23 public class AndroidAudioPlayer implements AudioProcessor {
     24     /**
     25      * The default stream type to use.
     26      */
     27     public static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_MUSIC;
     28     private static final String TAG = "AndroidAudioPlayer";
     29 
     30     private final AudioTrack audioTrack;
     31 
     32 
     33     /**
     34      * Constructs a new AndroidAudioPlayer from an audio format, default buffer size and stream type.
     35      *
     36      * @param audioFormat The audio format of the stream that this AndroidAudioPlayer will process.
     37      *                    This can only be 1 channel, PCM 16 bit.
     38      * @param bufferSizeInSamples  The requested buffer size in samples.
     39      * @param streamType  The type of audio stream that the internal AudioTrack should use. For
     40      *                    example, {@link AudioManager#STREAM_MUSIC}.
     41      * @throws IllegalArgumentException if audioFormat is not valid or if the requested buffer size is invalid.
     42      * @see AudioTrack
     43      */
     44     public AndroidAudioPlayer(TarsosDSPAudioFormat audioFormat, int bufferSizeInSamples, int streamType) {
     45         if (audioFormat.getChannels() != 1) {
     46             throw new IllegalArgumentException("TarsosDSP only supports mono audio channel count: " + audioFormat.getChannels());
     47         }
     48 
     49         // The requested sample rate
     50         int sampleRate = (int) audioFormat.getSampleRate();
     51 
     52         //The buffer size in bytes is twice the buffer size expressed in samples if 16bit samples are used:
     53         int bufferSizeInBytes = bufferSizeInSamples * audioFormat.getSampleSizeInBits()/8;
     54 
     55         // From the Android API about getMinBufferSize():
     56         // The total size (in bytes) of the internal buffer where audio data is read from for playback.
     57         // If track's creation mode is MODE_STREAM, you can write data into this buffer in chunks less than or equal to this size,
     58         // and it is typical to use chunks of 1/2 of the total size to permit double-buffering. If the track's creation mode is MODE_STATIC,
     59         // this is the maximum length sample, or audio clip, that can be played by this instance. See getMinBufferSize(int, int, int) to determine
     60         // the minimum required buffer size for the successful creation of an AudioTrack instance in streaming mode. Using values smaller
     61         // than getMinBufferSize() will result in an initialization failure.
     62         int minBufferSizeInBytes = AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_MONO,  AudioFormat.ENCODING_PCM_16BIT);
     63         if(minBufferSizeInBytes > bufferSizeInBytes){
     64             throw new IllegalArgumentException("The buffer size should be at least " + (minBufferSizeInBytes/(audioFormat.getSampleSizeInBits()/8)) + " (samples) according to  AudioTrack.getMinBufferSize().");
     65         }
     66 
     67         //http://developer.android.com/reference/android/media/AudioTrack.html#AudioTrack(int, int, int, int, int, int)
     68         audioTrack = new AudioTrack(streamType, sampleRate, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes,AudioTrack.MODE_STREAM);
     69 
     70         audioTrack.play();
     71     }
     72 
     73     /**
     74      * Constructs a new AndroidAudioPlayer from an audio format.
     75      *
     76      * @param audioFormat The audio format that this AndroidAudioPlayer will process.
     77      * @see AndroidAudioPlayer#AndroidAudioPlayer(TarsosDSPAudioFormat, int, int)
     78      */
     79     public AndroidAudioPlayer(TarsosDSPAudioFormat audioFormat) {
     80         this(audioFormat, 4096, DEFAULT_STREAM_TYPE);
     81     }
     82 
     83     /**
     84      * {@inheritDoc}
     85      */
     86     @Override
     87     public boolean process(AudioEvent audioEvent) {
     88         int overlapInSamples = audioEvent.getOverlap();
     89         int stepSizeInSamples = audioEvent.getBufferSize() - overlapInSamples;
     90         byte[] byteBuffer = audioEvent.getByteBuffer();
     91 
     92         //int ret = audioTrack.write(audioEvent.getFloatBuffer(),overlapInSamples,stepSizeInSamples,AudioTrack.WRITE_BLOCKING);
     93         int ret = audioTrack.write(byteBuffer,overlapInSamples*2,stepSizeInSamples*2);
     94         if (ret < 0) {
     95             Log.e(TAG, "AudioTrack.write returned error code " + ret);
     96         }
     97         return true;
     98     }
     99 
    100     /**
    101      * {@inheritDoc}
    102      */
    103     @Override
    104     public void processingFinished() {
    105         audioTrack.flush();
    106         audioTrack.stop();
    107         audioTrack.release();
    108     }
    109 }