在Android中使用AudioTrack播放WAV文件
我正在使用Android,试图让我的AudioTrack应用程序播放一个Windows.wav文件(Tada.wav)。坦白地说,这不应该这么难,但我听到了很多奇怪的东西。该文件保存在我手机的迷你SD卡上,读取内容似乎没有问题,但当我播放该文件时(我只确定参数是正确的),我会听到几秒钟的白噪声,然后声音似乎会自行分解成正确的声音 我已经成功地在手机上录制并播放了自己的语音--我根据本例中的说明创建了一个.pcm文件: (没有向后掩蔽) 有没有人对在Android上播放.wav文件的web示例有一些建议或了解 谢谢,在Android中使用AudioTrack播放WAV文件,android,wav,audio-streaming,Android,Wav,Audio Streaming,我正在使用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之间的区别。如何知道音乐[]长度以进行序列化?基本上,就是“足够大”。如果您知道要发送的文件,请使用略大于其大小的值,否则你或多或少得从屁股里掏出一个数字。谢谢你,在我试过的所有答案中,这一个给出了最好的结果。虽然在曲目开始时,我仍然会听到一些声音的咔嗒声……我在开始和结束时都会听到咔嗒声,而且播放的声音也超过了文件的结尾,继续播放任何音频文件中都没有的声音。奇怪的音频以慢动作播放。问题可能是什么。如果您指定了您认为糟糕的解析代码以及原因,那么您的答案会更有用。