在Android中使用AudioTrack播放WAV文件

在Android中使用AudioTrack播放WAV文件,android,wav,audio-streaming,Android,Wav,Audio Streaming,我正在使用Android,试图让我的AudioTrack应用程序播放一个Windows.wav文件(Tada.wav)。坦白地说,这不应该这么难,但我听到了很多奇怪的东西。该文件保存在我手机的迷你SD卡上,读取内容似乎没有问题,但当我播放该文件时(我只确定参数是正确的),我会听到几秒钟的白噪声,然后声音似乎会自行分解成正确的声音 我已经成功地在手机上录制并播放了自己的语音--我根据本例中的说明创建了一个.pcm文件: (没有向后掩蔽) 有没有人对在Android上播放.wav文件的web示例有

我正在使用Android,试图让我的AudioTrack应用程序播放一个Windows.wav文件(Tada.wav)。坦白地说,这不应该这么难,但我听到了很多奇怪的东西。该文件保存在我手机的迷你SD卡上,读取内容似乎没有问题,但当我播放该文件时(我只确定参数是正确的),我会听到几秒钟的白噪声,然后声音似乎会自行分解成正确的声音

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

(没有向后掩蔽)

有没有人对在Android上播放.wav文件的web示例有一些建议或了解

谢谢,
R.

在将文件的其余数据转储到缓冲区之前,是否跳过文件的前44个字节?前44个字节是波头,如果你试图播放它们,它们听起来就像随机噪音

另外,您是否确定您正在创建的音轨具有与您尝试播放的波相同的属性(采样率、比特率、通道数等)?Windows在“文件属性”页面中为您提供这些信息方面做得很好:

我无意中找到了答案(坦率地说,我尝试了&^@!我认为这是行不通的),以防有人感兴趣。。。在我的原始代码(源于原始文章链接中的示例)中,数据是从文件中读取的,如下所示:

    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
在这个版本中,music[]是一组短片。因此,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
在此版本中,music[]是一个字节数组。我仍然在告诉音轨,它是16位PCM数据,我的Android在将字节数组写入这样配置的音轨时似乎没有问题。。。无论如何,这听起来是对的,所以如果有人想在他们的Android上播放Windows声音,出于某种原因,这就是解决方案。啊,Endianness

R.

正如所说,您必须跳过最初的44个字节,或者(我更喜欢)读取作为WAVE头的前44个字节。通过这种方式,您可以知道有多少通道、每个采样的位、长度等。。。波浪包含了水


你可以找到一个很好的WAVE头解析器/编写器的实现。

我找到了很多关于这个问题的长答案。考虑到所有的剪切和粘贴,我的最终解决方案几乎不是我的,归结为:

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(停止)只是一个“真”值,作为重置暂停/播放按钮的信号发送回。 在类初始值设定项中:

public Mp3Track(Context context) {
    mContext = context;
    minBufferSize = AudioTrack.getMinBufferSize(44100,
        AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
}
上下文就是调用活动中的“this”。
您可以在SD卡上使用FileInputStream等。我的文件是res/raw

格式的。请不要保存糟糕的解析代码。WAV解析实现起来很简单 您将感谢自己能够解析诸如采样率、位深度和通道数之类的内容

此外,x86和ARM(至少在默认情况下)都是little-endian,因此本机endian WAV文件在没有任何乱序的情况下应该可以使用。

示例WAV文件:

示例代码:

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;
    }
}

只需确认您在
AudioTrack
构造函数中是否有
AudioTrack.MODE\u STREAM
而不是
AudioTrack.MODE\u STATIC

AudioTrack at = new AudioTrack(
  AudioManager.STREAM_MUSIC,
  sampleRate,
  AudioFormat.CHANNEL_IN_STEREO,
  AudioFormat.ENCODING_PCM_16BIT,
  // buffer length in bytes
  outputBufferSize,
  AudioTrack.MODE_STREAM
);

我尝试过各种跳过头球的组合,但我想不出来——运气不好。白噪声的持续时间远远超过44比特。Tada.wav是一个168kbyte的文件,所以“播放”文件头应该不会引起注意,对吧?没错,文件头会在很短的时间内产生垃圾。你确定你正在创建的音轨与你试图播放的波形具有相同的属性(采样率、比特率、通道数等)?我有一个十六进制编辑器,我确信我正确地从标题中获取了数字。我有点惊讶,我没能在互联网上找到某种wav文件分析器。我被难倒了,Windows Media player当然可以播放该文件……如果您想检查您的值,Windows的文件属性页实际上可以很好地向您提供这些信息。请记住,wav头并不总是44字节。对于32位浮点数据,数据头为58字节。这应该是可接受的答案,因为它回答了问题。;)我可以发誓我在这里留下了一句“谢谢你,加里”,但现在不在了。。。谢谢你,加里!!这似乎是在主题上:在读取WAV格式时使用Java的short和byte之间的区别。如何知道音乐[]长度以进行序列化?基本上,就是“足够大”。如果您知道要发送的文件,请使用略大于其大小的值,否则你或多或少得从屁股里掏出一个数字。谢谢你,在我试过的所有答案中,这一个给出了最好的结果。虽然在曲目开始时,我仍然会听到一些声音的咔嗒声……我在开始和结束时都会听到咔嗒声,而且播放的声音也超过了文件的结尾,继续播放任何音频文件中都没有的声音。奇怪的音频以慢动作播放。问题可能是什么。如果您指定了您认为糟糕的解析代码以及原因,那么您的答案会更有用。