Using AudioTrack in Android to play a WAV file

后端 未结 7 955
别跟我提以往
别跟我提以往 2020-12-01 05:50

I\'m working with Android, trying to make my AudioTrack application play a Windows .wav file (Tada.wav). Frankly, it shouldn\'t be this hard, but I\'m hearing a lot of stra

相关标签:
7条回答
  • 2020-12-01 05:54

    I found a lot of long answers to this question. My final solution, which given all the cutting and pasting is hardly mine, comes down to:

    public boolean play() {
    
        int i = 0;
        byte[] music = null;
        InputStream is = mContext.getResources().openRawResource(R.raw.noise);
    
        at = new AudioTrack(AudioManager.STREAM_MUSIC, 44100,
            AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
            minBufferSize, AudioTrack.MODE_STREAM);
    
        try{
            music = new byte[512];
            at.play();
    
            while((i = is.read(music)) != -1)
                at.write(music, 0, i);
    
        } catch (IOException e) {
            e.printStackTrace();
        }
    
        at.stop();
        at.release();
        return STOPPED;
    }
    

    STOPPED is just a "true" sent back as a signal to reset the pause/play button. And in the class initializer:

    public Mp3Track(Context context) {
        mContext = context;
        minBufferSize = AudioTrack.getMinBufferSize(44100,
            AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
    }
    

    Context is just "this" from the calling activity. You can use a FileInputStream on the sdcard, etc. My files are in res/raw

    0 讨论(0)
  • 2020-12-01 05:55

    Sample wav file:
    http://www.mauvecloud.net/sounds/pcm1644m.wav

    Sample Code:

    public class AudioTrackPlayer {
        Context mContext;
        int minBufferSize;
        AudioTrack at;
        boolean STOPPED;
    
        public AudioTrackPlayer(Context context) {
            Log.d("------","init");
            mContext = context;
            minBufferSize = AudioTrack.getMinBufferSize(44100,
                    AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
        }
    
        public boolean play() {
            Log.d("------","play");
            int i = 0;
            byte[] music = null;
            InputStream is = mContext.getResources().openRawResource(R.raw.pcm1644m);
    
            at = new AudioTrack(AudioManager.STREAM_MUSIC, 44100,
                    AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
                    minBufferSize, AudioTrack.MODE_STREAM);
            try {
                music = new byte[512];
                at.play();
    
                while ((i = is.read(music)) != -1)
                    at.write(music, 0, i);
    
            } catch (IOException e) {
                e.printStackTrace();
            }
            at.stop();
            at.release();
            return STOPPED;
        }
    }
    
    0 讨论(0)
  • 2020-12-01 06:01

    As said by Aaron C, you have to skip initial 44 bytes or (as I prefer) read first 44 bytes that are the WAVE header. In this way you know how many channels, bits per sample, length, etc... the WAVE contains.

    Here you can find a good implementation of a WAVE header parser/writer.

    0 讨论(0)
  • 2020-12-01 06:03

    Just confirm if you have AudioTrack.MODE_STREAM and not AudioTrack.MODE_STATIC in the AudioTrack constructor:

    AudioTrack at = new AudioTrack(
      AudioManager.STREAM_MUSIC,
      sampleRate,
      AudioFormat.CHANNEL_IN_STEREO,
      AudioFormat.ENCODING_PCM_16BIT,
      // buffer length in bytes
      outputBufferSize,
      AudioTrack.MODE_STREAM
    );
    
    0 讨论(0)
  • 2020-12-01 06:09

    I stumbled on the answer (frankly, by trying &^@! I didn't think would work), in case anybody's interested... In my original code (which is derived from the example in the link in the original post), the data is read from the file like so:

        InputStream             is  = new FileInputStream       (file);
        BufferedInputStream     bis = new BufferedInputStream   (is, 8000);
        DataInputStream         dis = new DataInputStream       (bis);      //  Create a DataInputStream to read the audio data from the saved file
    
        int i = 0;                                                          //  Read the file into the "music" array
        while (dis.available() > 0)
        {
            music[i] = dis.readShort();                                     //  This assignment does not reverse the order
            i++;
        }
    
        dis.close();                                                        //  Close the input stream
    

    In this version, music[] is array of SHORTS. So, the readShort() method would seem to make sense here, since the data is 16-bit PCM... However, on the Android that seems to be the problem. I changed that code to the following:

         music=new byte[(int) file.length()];//size & length of the file
        InputStream             is  = new FileInputStream       (file);
        BufferedInputStream     bis = new BufferedInputStream   (is, 8000);
        DataInputStream         dis = new DataInputStream       (bis);      //  Create a DataInputStream to read the audio data from the saved file
    
        int i = 0;                                                          //  Read the file into the "music" array
        while (dis.available() > 0)
        {
            music[i] = dis.readByte();                                      //  This assignment does not reverse the order
            i++;
        }
    
        dis.close();                                                        //  Close the input stream
    

    In this version, music[] is an array of BYTES. I'm still telling the AudioTrack that it's 16-bit PCM data, and my Android doesn't seem to have a problem with writing an array of bytes into an AudioTrack thus configured... Anyway, it finally sounds right, so if anyone else wants to play Windows sounds on their Android, for some reason, that's the solution. Ah, Endianness......

    R.

    0 讨论(0)
  • 2020-12-01 06:12

    Are you skipping the first 44 bytes of the file before you dump the rest of the file's data into the buffer? The first 44 bytes are the WAVE header and they would sound like random noise if you tried to play them.

    Also, are you sure you are creating the AudioTrack with the same properties as the WAVE you are trying to play (sample rate, bit rate, number of channels, etc)? Windows actually does a good job of giving this information to you in the File Properties page: alt text

    0 讨论(0)
提交回复
热议问题