You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 09:31:13