将 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 范围的主要内容,如果未能解决你的问题,请参考以下文章