前端如何将pcm转为wav音频?

在前端开发中,将PCM数据转换为WAV音频文件,你可以使用JavaScript的库如waveheader.js或自己手动添加WAV头信息到PCM数据前面。WAV文件主要由两部分组成:一个44字节的文件头(WAV header)和原始的PCM数据。

以下是一个简单的步骤说明如何手动将PCM数据转换为WAV文件:

  1. 创建WAV头

WAV头是一个44字节的数据块,它包含了音频文件的元信息,如采样率、位深度、通道数等。以下是一个典型的WAV头结构:

let wavHeader = new Uint8Array([
    85, 84, 70, 32, // "RIFF" chunk descriptor
    0, 0, 0, 0,       // Chunk size (36 + SubChunk2Size), to be filled later
    85, 86, 65, 86,   // "WAVE" format
    // "fmt " sub-chunk (Audio Format)
    102, 109, 116, 32, // Sub-chunk1ID, Contains the letters "fmt " 
    16, 0, 0, 0,        // Sub-chunk1Size = 16 for PCM = 0x10 = 16
    1, 0,                 // AudioFormat = 1 for PCM
    0, 1,                 // NumChannels = 1 for Mono, 2 for Stereo, etc.
    0, 0, 0, 0,         // SampleRate, to be filled later
    0, 0, 0, 0,         // ByteRate = SampleRate * NumChannels * BitsPerSample/8, to be filled later
    0, 0,                 // BlockAlign = NumChannels * BitsPerSample/8
    16, 0,                // BitsPerSample = 16 for PCM
    // "data" sub-chunk (Audio Data)
    100, 97, 116, 97,   // Subchunk2ID, Contains the letters "data"
    0, 0, 0, 0,          // Subchunk2Size = NumSamples * NumChannels * BitsPerSample/8, to be filled later
]);

注意:上述代码中的SampleRate, ByteRate, Subchunk2Size等字段需要根据你的PCM数据来填充。
2. 将PCM数据与WAV头合并

创建了一个包含WAV头的Uint8Array后,你需要将这个头与你的PCM数据合并。这可以通过创建一个新的Uint8Array并将两者连接起来实现。
3. 下载转换后的WAV文件

使用BlobURL.createObjectURL()来创建一个可以下载的链接。例如:

let blob = new Blob([wavHeader, pcmData], { type: 'audio/wav' });
let audioUrl = URL.createObjectURL(blob);
let a = document.createElement('a');
a.href = audioUrl;
a.download = 'output.wav';
a.click();
  1. 注意事项
    • 确保你的PCM数据的采样率、位深度和通道数与WAV头中的信息匹配。
    • 如果你的PCM数据是浮点数,确保在合并之前将其转换为整数(通常是16位)。
    • 考虑到跨浏览器兼容性和文件大小,通常使用16位PCM数据是一个好选择。
  2. 使用库

如果你不想手动处理WAV头,可以使用像waveheader.js这样的库来简化过程。这些库通常提供了更简洁的方法来将PCM数据封装为WAV文件。
6. 示例

为了完整性,这里是一个简单的示例,说明如何将PCM数据与WAV头合并并下载:

// 假设 pcmData 是一个包含PCM数据的 Uint8Array
let sampleRate = 44100; // 例如
let numChannels = 1; // 单声道,立体声则为2
let bitsPerSample = 16; // 16位PCM

// 填充WAV头中的相关字段
wavHeader[28] = (sampleRate & 0xff00) >> 8;
wavHeader[29] = (sampleRate & 0x00ff);
wavHeader[30] = ((sampleRate & 0xff0000) >> 16);
wavHeader[31] = ((sampleRate & 0x00ff00) >> 8);

let byteRate = sampleRate * numChannels * (bitsPerSample / 8);
wavHeader[32] = (byteRate & 0xff00) >> 8;
wavHeader[33] = (byteRate & 0x00ff);
wavHeader[34] = ((byteRate & 0xff0000) >> 16);
wavHeader[35] = ((byteRate & 0x00ff00) >> 8);

let subChunk2Size = pcmData.length;
wavHeader[40] = (subChunk2Size & 0xff000000) >> 24;
wavHeader[41] = (subChunk2Size & 0x00ff0000) >> 16;
wavHeader[42] = (subChunk2Size & 0x0000ff00) >> 8;
wavHeader[43] = (subChunk2Size & 0x000000ff);

// RIFF chunk size (excluding the first 8 bytes of RIFF chunk descriptor)
let chunkSize = 36 + subChunk2Size;
wavHeader[4] = (chunkSize & 0xff000000) >> 24;
wavHeader[5] = (chunkSize & 0x00ff0000) >> 16;
wavHeader[6] = (chunkSize & 0x0000ff00) >> 8;
wavHeader[7] = (chunkSize & 0x000000ff);

// 合并WAV头和PCM数据
let wavBlob = new Blob([wavHeader, pcmData], { type: 'audio/wav' });
let wavUrl = URL.createObjectURL(wavBlob);
let downloadLink = document.createElement('a');
downloadLink.href = wavUrl;
downloadLink.download = 'output.wav';
downloadLink.click();

请根据你的具体需求调整上述代码。

posted @   王铁柱6  阅读(93)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示