在Android中使用AudioTrack播放WAV文件

时间:2021-07-18 15:59:47

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 strange stuff. The file is saved on my phone's mini SD card and reading the contents doesn't seem to be a problem, but when I play the file (with parameters I'm only PRETTY SURE are right), I get a few seconds of white noise before the sound seems to resolve itself into something that just may be right.

我正在使用Android,试图让我的AudioTrack应用程序播放Windows .wav文件(Tada.wav)。坦率地说,它不应该这么难,但我听到很多奇怪的东西。该文件保存在手机的迷你SD卡上并且读取内容似乎不是问题,但是当我播放文件时(参数我只是PRETTY SURE是正确的),我得到几秒钟的白噪声在声音似乎解决自己成为可能正确的事情之前。

I have successfully recorded and played my own voice back on the phone -- I created a .pcm file according to the directions in this example:

我已经成功录制并在手机上播放了自己的声音 - 我根据此示例中的说明创建了一个.pcm文件:

http://emeadev.blogspot.com/2009/09/raw-audio-manipulation-in-android.html

(without the backwards masking)...

(没有向后掩盖)......

Anybody got some suggestions or awareness of an example on the web for playing a .wav file on an Android??

任何人都有一些建议或意识到网上的例子在Android上播放.wav文件?

Thanks, R.

5 个解决方案

#1


26  

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 []是SHORTS的数组。所以,readShort()方法似乎在这里有意义,因为数据是16位PCM ...但是,在Android上似乎是问题所在。我将该代码更改为以下内容:

     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......

在这个版本中,music []是一个BYTES数组。我还在告诉AudioTrack它是16位PCM数据,我的Android似乎没有将字节数组写入AudioTrack这样配置的问题......无论如何,它最终听起来是正确的,所以如果有人其他人想在他们的Android上播放Windows声音,出于某种原因,这就是解决方案。啊,恩迪安......

R.

#2


7  

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:

STOPPED只是一个“真实”发送回来作为重置暂停/播放按钮的信号。并在类初始化程序中:

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

上下文只是来自调用活动的“this”。你可以在SD卡等上使用FileInputStream。我的文件是res / raw

#3


5  

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.

在将剩余的文件数据转储到缓冲区之前,您是否正在跳过文件的前44个字节?前44个字节是WAVE标题,如果您尝试播放它们,它们听起来就像随机噪音。

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: 在Android中使用AudioTrack播放WAV文件

另外,您确定要创建的AudioTrack具有与您尝试播放的WAVE相同的属性(采样率,比特率,通道数等)吗? Windows实际上可以很好地在“文件属性”页面中向您提供此信息:

#4


2  

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.

正如Aaron C所说,你必须跳过最初的44个字节或(我更喜欢)读取前面44个字节的WAVE标题。通过这种方式,您可以知道WAVE包含的通道数,每个样本的位数,长度等。

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

在这里,您可以找到WAVE头解析器/编写器的良好实现。

#5


1  

Please don't perpetuate terrible parsing code. WAV parsing is trivial to implement http://soundfile.sapp.org/doc/WaveFormat/ and you will thank yourself by being able to parse things such as the sampling rate, bit depth, and number of channels.

请不要使可怕的解析代码永久化。 WAV解析对于实现http://soundfile.sapp.org/doc/WaveFormat/来说是微不足道的,你可以通过解析采样率,位深度和通道数等事情来感谢自己。

Also x86 and ARM (at least by default) are both little endian , so native-endian WAV files should be fine without any shuffling.

此外,x86和ARM(至少在默认情况下)都是小端,因此native-endian WAV文件应该没有任何改组。

#1


26  

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 []是SHORTS的数组。所以,readShort()方法似乎在这里有意义,因为数据是16位PCM ...但是,在Android上似乎是问题所在。我将该代码更改为以下内容:

     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......

在这个版本中,music []是一个BYTES数组。我还在告诉AudioTrack它是16位PCM数据,我的Android似乎没有将字节数组写入AudioTrack这样配置的问题......无论如何,它最终听起来是正确的,所以如果有人其他人想在他们的Android上播放Windows声音,出于某种原因,这就是解决方案。啊,恩迪安......

R.

#2


7  

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:

STOPPED只是一个“真实”发送回来作为重置暂停/播放按钮的信号。并在类初始化程序中:

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

上下文只是来自调用活动的“this”。你可以在SD卡等上使用FileInputStream。我的文件是res / raw

#3


5  

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.

在将剩余的文件数据转储到缓冲区之前,您是否正在跳过文件的前44个字节?前44个字节是WAVE标题,如果您尝试播放它们,它们听起来就像随机噪音。

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: 在Android中使用AudioTrack播放WAV文件

另外,您确定要创建的AudioTrack具有与您尝试播放的WAVE相同的属性(采样率,比特率,通道数等)吗? Windows实际上可以很好地在“文件属性”页面中向您提供此信息:

#4


2  

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.

正如Aaron C所说,你必须跳过最初的44个字节或(我更喜欢)读取前面44个字节的WAVE标题。通过这种方式,您可以知道WAVE包含的通道数,每个样本的位数,长度等。

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

在这里,您可以找到WAVE头解析器/编写器的良好实现。

#5


1  

Please don't perpetuate terrible parsing code. WAV parsing is trivial to implement http://soundfile.sapp.org/doc/WaveFormat/ and you will thank yourself by being able to parse things such as the sampling rate, bit depth, and number of channels.

请不要使可怕的解析代码永久化。 WAV解析对于实现http://soundfile.sapp.org/doc/WaveFormat/来说是微不足道的,你可以通过解析采样率,位深度和通道数等事情来感谢自己。

Also x86 and ARM (at least by default) are both little endian , so native-endian WAV files should be fine without any shuffling.

此外,x86和ARM(至少在默认情况下)都是小端,因此native-endian WAV文件应该没有任何改组。