跳到主要内容

16-bit PCM 音频格式转换

2025年02月15日
柏拉文
越努力,越幸运

一、认识


16-bit PCM 音频格式转换: 将经过 16kHz 将采样的 浮点音频数据 转换为 16-bit PCM 格式。这是为了将音频数据转化为更加通用、标准的格式,便于存储、传输或进一步处理。另外, 16-bit PCM 能够表示从 -3276832767 的整数范围,这足以容纳大部分音频信号的动态范围, 也是最常见的音频存储格式之一, 提供了足够的精度来处理大多数音频录制和播放任务。而且, 使用 16-bit PCM 格式相比于浮点数格式(如 32-bit float)能够显著减少存储空间和带宽需求,并且在处理音频时具有较好的性能,尤其是在低延迟和实时处理场景中。具体思路为: 将浮动的音频信号(通常在范围 -11 之间)映射到 16 位整数的音频格式。具体转换逻辑为: 根据输入的浮点音频数据计算出转换后的 16-bit 数据所需的字节数长度, 这个长度创建一个新的 ArrayBuffer,这个缓冲区将用来存储最终的 16-bit PCM 数据。ArrayBuffer 是一种用于存储原始二进制数据的对象。在根据 ArrayBuffer 创建一个 DataView 对象, 允许你以不同的数据类型读取和写入 ArrayBuffer 中的数据。遍历输入的浮点音频数据, 并将每个样本值转换为 16-bit PCM 格式, 注意, 每次迭代, offset 增加 2,因为每个 16-bit PCM 样本占 2 字节。遍历过程中, 首先将输入的浮动音频数据限制在 -11 的范围内, 这样做是为了确保音频信号不会超过正常的范围,避免发生溢出。通过 dataView.setInt16 将一个 16-bit 整数值写入到 ArrayBuffer 中指定的偏移位置 offsets < 0 ? s * 0x8000 : s * 0x7fff: 表示如果 s 为负数,乘以 0x8000(即 32768);如果 s 为正数,乘以 0x7fff(即 32767)。这将浮点数映射到 16-bit PCM 范围内的整数值。浮点数被乘以 32767-32768 来保证其能够正确表示在 16-bit PCM 的有符号整数范围内。true 表示使用小端字节序(little-endian),这在许多音频格式(如 WAV)中是常见的字节顺序。

二、实现


function to16BitPCM(input) {
const dataLength = input.length * (16 / 8);
const dataBuffer = new ArrayBuffer(dataLength);
const dataView = new DataView(dataBuffer);
let offset = 0;
for (let i = 0; i < input.length; i++, offset += 2) {
const s = Math.max(-1, Math.min(1, input[i]));
dataView.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7fff, true);
}
return dataView;
}