将 32 位浮点数转换为 16 位 PCM 范围

Posted

技术标签:

【中文标题】将 32 位浮点数转换为 16 位 PCM 范围【英文标题】:Convert 32-bit Floating Points to 16-bit PCM range 【发布时间】:2017-05-09 22:49:13 【问题描述】:

我有一些由 javascript html5 网络音频 api 生成的数据。它生成Float32Array,一个 32 位浮点数组,介于 -1 和 1 之间。我使用 websocket 将数据流式传输到我的服务器。

我需要将 32 位浮点数转换为介于 -32768 和 +32767(16 位有符号整数)之间的 16 位 PCM 范围。这样就可以将数据用作 wav 文件。

我在转换时遇到问题。我怀疑答案是使用 struct 模块,但我无法获得正确的格式。

【问题讨论】:

struct 模块不能直接在这些类型之间进行转换。它只能将 32 位浮点值解包为 Python 浮点数,并将 Python int 打包为 16 位整数。它也不会进行您需要的范围转换。 【参考方案1】:

这是一个 Python 2.7 示例程序,它读取包含原始 32 位浮点音频样本的文件并创建一个 WAV 文件,其中包含这些样本转换后的 16 位有符号整数样本:

import sys
import array
import struct
import wave

def convert(fin, fout, chunk_size = 1024 * 1024):
    chunk_size *= 4    # convert from samples to bytes

    waveout = wave.open(fout, "wb")
    waveout.setparams((1, 2, 44100, 0, "NONE", ""))

    while True:
        raw_floats = fin.read(chunk_size)
        if raw_floats == "":
            return
        floats = array.array('f', raw_floats)
        samples = [sample * 32767
                   for sample in floats]
        raw_ints = struct.pack("<%dh" % len(samples), *samples)
        waveout.writeframes(raw_ints)

convert(open(sys.argv[1], "rb"), open(sys.argv[2], "wb"))

代码使用array.array 将32 位浮点样本转换为Python 浮点数,因为它应该比struct.unpack 快一点。它还使用本机机器字节顺序,就像Float32Array 一样。无法使用array.array 创建 16 位整数样本,因为无论本机机器顺序如何,它们都需要使用小端字节序。范围转换由简单的 Python 代码处理。

【讨论】:

感谢您的帮助。我已将代码简化为:gist.github.com/richtier/6b05b2bb3ceff20f3d9557227b8789c6,但是当我使用此处定义的字节时:pastebin.com/raw/yCQ8Bg5w 我得到错误struct.error: required argument is not an integer 此时samples 看起来像例如[505.00430237688124, 487.5382216461003, 471.0005183443427, 440.09429602883756],这是有道理的因为samples 仍然是一个浮动列表 @rikAtee 你用的是什么版本的 Python? 3.5.2 在单独的注释中添加以下内容时,我认为它开始表现自己:samples = [int(sample * 32767) for sample in floats] 是的,我使用的是 2.7,似乎没有那么挑剔。使用int(sample * 32767) 应该可以解决问题。

以上是关于将 32 位浮点数转换为 16 位 PCM 范围的主要内容,如果未能解决你的问题,请参考以下文章

SSE 内在函数:将 32 位浮点数转换为 UNSIGNED 8 位整数

浮点数的十六进制表示

AVX 将 64 位整数转换为 64 位浮点数

用脚编码音频:将 32 位浮点数转换为 mp3

32 位到 16 位浮点转换

比较一个 32 位浮点数和一个 32 位整数而不强制转换为双精度,当任何一个值都可能太大而无法完全适合另一种类型时