React Native中如何将Uint8Array转换为.wav文件?
当然有可行的实现方案,核心是按照WAV文件格式规范,把BLE传来的原始音频数据(Uint8Array)加上正确的文件头,打包成完整的WAV文件。以下是具体步骤和代码示例:
实现步骤
1. 明确音频参数
首先必须确认BLE设备传输的音频数据对应的关键参数,这些是构建WAV文件的核心:
- 采样率(Sample Rate):比如8000Hz、16000Hz
- 位深(Bits Per Sample):通常是8位或16位
- 声道数(Num Channels):单声道(1)或立体声(2)
- 字节序(Endianness):WAV默认使用小端序(Little Endian),需要和设备输出的字节顺序匹配
2. 预处理原始数据
根据位深处理Uint8Array:
- 8位音频:无需转换,原始Uint8Array就是WAV数据段的直接内容(8位PCM是无符号整数)
- 16位音频:需要把连续的两个字节合并为一个16位有符号整数,转成
Int16Array后再转回Uint8Array(保持小端序)。示例代码:
function uint8ToInt16LE(uint8Array) { const int16Array = new Int16Array(uint8Array.length / 2); for (let i = 0; i < int16Array.length; i++) { int16Array[i] = (uint8Array[2*i+1] << 8) | uint8Array[2*i]; // 处理有符号转换:最高位为1时转为负数 if (int16Array[i] & 0x8000) { int16Array[i] = int16Array[i] - 0x10000; } } // 转回小端序的Uint8Array return new Uint8Array(int16Array.buffer); }
3. 构建WAV文件头
WAV文件由文件头和音频数据两部分组成,按照RIFF规范填充各个字段。以下是生成完整WAV文件的函数示例(以JavaScript为例):
function buildWavFile(audioParams, rawData) { const { sampleRate, bitsPerSample, numChannels } = audioParams; const byteRate = sampleRate * numChannels * (bitsPerSample / 8); const blockAlign = numChannels * (bitsPerSample / 8); const dataSize = rawData.length; // 计算整个WAV文件大小:44字节头 + 数据长度 const wavSize = 44 + dataSize; const wavBuffer = new ArrayBuffer(wavSize); const view = new DataView(wavBuffer); // 填充RIFF头 view.setUint8(0, 0x52); // 'R' view.setUint8(1, 0x49); // 'I' view.setUint8(2, 0x46); // 'F' view.setUint8(3, 0x46); // 'F' view.setUint32(4, wavSize - 8, true); // ChunkSize(小端序) view.setUint8(8, 0x57); // 'W' view.setUint8(9, 0x41); // 'A' view.setUint8(10, 0x56); // 'V' view.setUint8(11, 0x45); // 'E' // 填充fmt子块 view.setUint8(12, 0x66); // 'f' view.setUint8(13, 0x6D); // 'm' view.setUint8(14, 0x74); // 't' view.setUint8(15, 0x20); // ' ' view.setUint32(16, 16, true); // Subchunk1Size(PCM格式固定为16) view.setUint16(20, 1, true); // AudioFormat(PCM=1) view.setUint16(22, numChannels, true); // NumChannels view.setUint32(24, sampleRate, true); // SampleRate view.setUint32(28, byteRate, true); // ByteRate view.setUint16(32, blockAlign, true); // BlockAlign view.setUint16(34, bitsPerSample, true); // BitsPerSample // 填充data子块 view.setUint8(36, 0x64); // 'd' view.setUint8(37, 0x61); // 'a' view.setUint8(38, 0x74); // 't' view.setUint8(39, 0x61); // 'a' view.setUint32(40, dataSize, true); // Subchunk2Size // 写入原始音频数据 const dataView = new Uint8Array(wavBuffer, 44); dataView.set(rawData); return new Blob([wavBuffer], { type: 'audio/wav' }); }
4. 生成并保存WAV文件
调用上述函数,传入参数和处理后的原始数据,生成Blob后即可保存为文件:
// 示例参数:16kHz采样率、16位单声道 const audioParams = { sampleRate: 16000, bitsPerSample: 16, numChannels: 1 }; // 假设bleData是从BLE设备获取的Uint8Array let processedData = bleData; // 如果是16位音频,先执行转换 if (audioParams.bitsPerSample === 16) { processedData = uint8ToInt16LE(bleData); } // 生成WAV格式的Blob const wavBlob = buildWavFile(audioParams, processedData); // 浏览器环境下下载保存示例 const url = URL.createObjectURL(wavBlob); const a = document.createElement('a'); a.href = url; a.download = 'ble_record.wav'; a.click(); URL.revokeObjectURL(url);
注意事项
- 必须确保音频参数和BLE设备输出完全匹配,否则生成的WAV文件会出现杂音、播放速度异常等问题
- 如果设备传输的是压缩音频(非PCM格式),需要先解压为原始PCM数据再进行上述处理
- 移动端应用(如React Native、Flutter)可根据平台特性调整代码逻辑,核心都是构建WAV头+原始数据的组合结构
内容的提问来源于stack exchange,提问作者rerboi
相关产品推荐
相关产品推荐

