如何在Android中将short[]数组写入.wav文件?
直接将short[]格式PCM数据导出为WAV文件的实现方案
你完全不需要通过“播放再录制”这种绕路的方式,直接利用WAV文件的结构特性,把AudioTrack使用的short[]格式PCM数据写入WAV文件即可——WAV本质就是标准文件头 + 原始PCM数据的组合,而你手里的short[]正好是16位PCM采样数据,完美匹配。
实现步骤
构建标准WAV文件头:WAV文件头固定为44字节,需要根据你的AudioTrack配置(采样率、声道数)填充对应参数:
- 采样率:和你初始化AudioTrack时的参数一致(比如44100Hz、48000Hz)
- 声道数:单声道填1,立体声填2
- 位深度:固定为16位(对应short类型)
写入文件:先把构建好的文件头写入目标文件,再将
short[]数据按小端字节顺序(符合WAV标准)转换成字节数组写入文件。
代码示例(Android/Java)
import java.io.FileOutputStream; import java.io.IOException; public class WavExporter { // 导出short[]格式PCM为WAV文件 public static void exportShortPcmToWav(short[] pcmData, int sampleRate, int channels, String outputPath) throws IOException { FileOutputStream fos = new FileOutputStream(outputPath); int bitsPerSample = 16; byte[] wavHeader = buildWavHeader(pcmData.length, sampleRate, channels, bitsPerSample); // 先写入WAV文件头 fos.write(wavHeader); // 将short类型PCM数据转换为小端字节数组并写入 byte[] pcmBytes = new byte[pcmData.length * 2]; for (int i = 0; i < pcmData.length; i++) { short sample = pcmData[i]; pcmBytes[i * 2] = (byte) (sample & 0xFF); pcmBytes[i * 2 + 1] = (byte) ((sample >> 8) & 0xFF); } fos.write(pcmBytes); fos.close(); } // 构建44字节的标准WAV文件头 private static byte[] buildWavHeader(int pcmSampleCount, int sampleRate, int channels, int bitsPerSample) { byte[] header = new byte[44]; int byteRate = sampleRate * channels * bitsPerSample / 8; int dataSize = pcmSampleCount * channels * bitsPerSample / 8; int fileSize = 36 + dataSize; // RIFF标识 header[0] = 'R'; header[1] = 'I'; header[2] = 'F'; header[3] = 'F'; // 文件总大小 header[4] = (byte) (fileSize & 0xFF); header[5] = (byte) ((fileSize >> 8) & 0xFF); header[6] = (byte) ((fileSize >> 16) & 0xFF); header[7] = (byte) ((fileSize >> 24) & 0xFF); // WAVE标识 header[8] = 'W'; header[9] = 'A'; header[10] = 'V'; header[11] = 'E'; // fmt子块标识 header[12] = 'f'; header[13] = 'm'; header[14] = 't'; header[15] = ' '; // fmt子块大小(PCM格式固定为16) header[16] = 16; header[17] = 0; header[18] = 0; header[19] = 0; // 音频格式(PCM格式固定为1) header[20] = 1; header[21] = 0; // 声道数 header[22] = (byte) channels; header[23] = 0; // 采样率 header[24] = (byte) (sampleRate & 0xFF); header[25] = (byte) ((sampleRate >> 8) & 0xFF); header[26] = (byte) ((sampleRate >> 16) & 0xFF); header[27] = (byte) ((sampleRate >> 24) & 0xFF); // 字节率 header[28] = (byte) (byteRate & 0xFF); header[29] = (byte) ((byteRate >> 8) & 0xFF); header[30] = (byte) ((byteRate >> 16) & 0xFF); header[31] = (byte) ((byteRate >> 24) & 0xFF); // 块对齐 header[32] = (byte) (channels * bitsPerSample / 8); header[33] = 0; // 位深度 header[34] = (byte) bitsPerSample; header[35] = 0; // data子块标识 header[36] = 'd'; header[37] = 'a'; header[38] = 't'; header[39] = 'a'; // PCM数据大小 header[40] = (byte) (dataSize & 0xFF); header[41] = (byte) ((dataSize >> 8) & 0xFF); header[42] = (byte) ((dataSize >> 16) & 0xFF); header[43] = (byte) ((dataSize >> 24) & 0xFF); return header; } }
使用说明
调用时直接传入你的short[]音频数据、AudioTrack使用的采样率、声道数,以及输出文件路径即可:
// 示例:单声道、44100Hz采样率的音频数据导出 try { WavExporter.exportShortPcmToWav(yourShortPcmData, 44100, 1, "/sdcard/Music/your_music.wav"); } catch (IOException e) { e.printStackTrace(); }
这种方式完全避免了播放录制的弊端:无需播放音频、导出速度极快、不会引入外界杂音,直接利用已有数据完成导出,是最直接高效的方案。
内容的提问来源于stack exchange,提问作者16-bit-apps
相关产品推荐
相关产品推荐

