如何将UInt16格式音频数据转换为可正常播放的WAV文件
问题根因
你遇到的无法生成可播放WAV文件的核心原因有两点:
- Dart的
File.writeAsBytes方法仅接收Uint8List类型的字节序列作为输入,你直接传入Uint16List不会自动完成类型转换和字节对齐,写入的文件内容不符合WAV格式规范,因此无法被播放器识别。 - 如果你的UInt16格式TXT文件中仅存储纯16位PCM采样数据、没有附带WAV文件头,也会导致播放器无法识别音频格式。
正确实现方案
场景1:UInt16 TXT中已包含完整WAV文件的全量字节(和你可用的UInt8 TXT结构一致)
仅需补充Uint16List到Uint8List的转换步骤即可:
var bytes = await rootBundle.loadString('assets/wav/audio_01_Uint16.txt'); // 原代码中此处不需要加await,split为同步方法,且返回值为List<String>不是List<int> List<String> strList = bytes.split(', '); List<int> intList = strList.map((s) => int.parse(s)).toList(); Uint16List uint16List = Uint16List.fromList(intList); // *核心转换*:通过buffer将Uint16List转为符合要求的Uint8List Uint8List wavBytes = uint16List.buffer.asUint8List(); await File('$tempPath/audio_01_Uint16.wav').writeAsBytes(wavBytes);
场景2:UInt16 TXT中仅存储纯PCM采样数据,无WAV头
需要先构造标准WAV文件头,再拼接采样数据后写入:
var bytes = await rootBundle.loadString('assets/wav/audio_01_Uint16.txt'); List<String> strList = bytes.split(', '); List<int> intList = strList.map((s) => int.parse(s)).toList(); Uint16List uint16List = Uint16List.fromList(intList); // 请根据你的音频实际参数修改以下配置:示例为44100采样率、双声道、16位深PCM int sampleRate = 44100; int channels = 2; int bitDepth = 16; int byteRate = sampleRate * channels * bitDepth ~/ 8; int blockAlign = channels * bitDepth ~/ 8; int dataSize = uint16List.length * 2; int fileSize = 36 + dataSize; // 构造44字节标准WAV头 Uint8List header = Uint8List(44); header.setRange(0, 4, [0x52, 0x49, 0x46, 0x46]); // RIFF标识 header.buffer.asByteData().setUint32(4, fileSize, Endian.little); // 文件总大小 header.setRange(8, 12, [0x57, 0x41, 0x56, 0x45]); // WAVE标识 header.setRange(12, 16, [0x66, 0x6D, 0x74, 0x20]); // fmt块标识 header.buffer.asByteData().setUint32(16, 16, Endian.little); // fmt块长度 header.buffer.asByteData().setUint16(20, 1, Endian.little); // 音频格式(PCM=1) header.buffer.asByteData().setUint16(22, channels, Endian.little); // 声道数 header.buffer.asByteData().setUint32(24, sampleRate, Endian.little); // 采样率 header.buffer.asByteData().setUint32(28, byteRate, Endian.little); // 字节传输率 header.buffer.asByteData().setUint16(32, blockAlign, Endian.little); // 块对齐单位 header.buffer.asByteData().setUint16(34, bitDepth, Endian.little); // 采样位深 header.setRange(36, 40, [0x64, 0x61, 0x74, 0x61]); // data块标识 header.buffer.asByteData().setUint32(40, dataSize, Endian.little); // 音频数据长度 // 拼接头和音频数据 Uint8List wavBytes = Uint8List(header.length + dataSize); wavBytes.setRange(0, header.length, header); wavBytes.setRange(header.length, wavBytes.length, uint16List.buffer.asUint8List()); // 写入文件 await File('$tempPath/audio_01_Uint16.wav').writeAsBytes(wavBytes);
内容的提问来源于stack exchange,提问作者Shree K Adhikari
相关产品推荐
相关产品推荐

