audioop
— 处理原始音频数据¶
audioop
模块包含一些对声音片段有用的操作。它对由 8、16、24 或 32 位宽的有符号整数样本组成的音片段进行操作,这些样本存储在 字节类对象 中。除非另有说明,否则所有标量项都是整数。
在 3.4 版中更改: 增加了对 24 位样本的支持。现在所有函数都接受任何 字节类对象。字符串输入现在会导致立即错误。
此模块提供对 a-LAW、u-LAW 和 Intel/DVI ADPCM 编码的支持。
一些更复杂的操作只采用 16 位样本,否则样本大小(以字节为单位)始终是操作的参数。
该模块定义以下变量和函数
- exception audioop.error¶
在所有错误(例如未知的每个样本字节数等)中引发此异常。
- audioop.add(fragment1, fragment2, width)¶
返回一个片段,该片段是作为参数传递的两个样本的加法。width 是以字节为单位的样本宽度,可以是
1
、2
、3
或4
。两个片段的长度应相同。在溢出的情况下,样本会被截断。
- audioop.adpcm2lin(adpcmfragment, width, state)¶
将 Intel/DVI ADPCM 编码片段解码为线性片段。有关 ADPCM 编码的详细信息,请参阅
lin2adpcm()
的说明。返回一个元组(sample, newstate)
,其中 sample 具有width 中指定的宽度。
- audioop.alaw2lin(fragment, width)¶
将 a-LAW 编码中的声音片段转换为线性编码的声音片段。a-LAW 编码始终使用 8 位样本,因此width 在此处仅指输出片段的样本宽度。
- audioop.avg(fragment, width)¶
返回片段中所有样本的平均值。
- audioop.avgpp(fragment, width)¶
返回片段中所有样本的平均峰峰值。不进行任何滤波,因此此例程的实用性值得怀疑。
- audioop.bias(fragment, width, bias)¶
返回一个片段,该片段是原始片段,每个样本都添加了一个偏差。溢出时,样本会环绕。
- audioop.byteswap(fragment, width)¶
“字节交换”片段中的所有样本并返回修改后的片段。将大端样本转换为小端样本,反之亦然。
在 3.4 版中添加。
- audioop.cross(fragment, width)¶
返回作为参数传递的片段中的零交叉次数。
- audioop.findfactor(fragment, reference)¶
返回一个因子F,使得
rms(add(fragment, mul(reference, -F)))
最小,即返回一个因子,用它乘以reference,使其尽可能与fragment 相匹配。这些片段都应包含 2 字节样本。此例程所花费的时间与
len(fragment)
成正比。
- audioop.findfit(fragment, reference)¶
尝试将reference 尽可能与fragment 的一部分(应为较长的片段)相匹配。从概念上来说,这是通过从fragment 中取出切片,使用
findfactor()
计算最佳匹配,并最小化结果来完成的。这些片段都应包含 2 字节样本。返回一个元组(offset, factor)
,其中offset 是fragment 中最佳匹配开始处的(整数)偏移量,factor 是根据findfactor()
计算出的(浮点)因子。
- audioop.findmax(fragment, length)¶
在fragment 中搜索一个长度为length 个样本(而非字节!)的切片,该切片具有最大的能量,即返回i,使得
rms(fragment[i*2:(i+length)*2])
最大。这些片段都应包含 2 字节样本。此例程所花费的时间与
len(fragment)
成正比。
- audioop.getsample(fragment, width, index)¶
返回片段中样本index 的值。
- audioop.lin2adpcm(fragment, width, state)¶
将样本转换为 4 位 Intel/DVI ADPCM 编码。ADPCM 编码是一种自适应编码方案,其中每个 4 位数字都是一个样本与下一个样本之间的差值,除以一个(可变)步长。Intel/DVI ADPCM 算法已被 IMA 选用,因此它很可能成为一种标准。
state 是包含编码器状态的元组。编码器返回元组
(adpcmfrag, newstate)
,并且应将 newstate 传递给lin2adpcm()
的下一次调用。在初始调用中,可以将None
作为状态传递。adpcmfrag 是 ADPCM 编码片段,以每字节 2 个 4 位值打包。
- audioop.lin2alaw(fragment, width)¶
将音频片段中的样本转换为 a-LAW 编码,并将其作为字节对象返回。a-LAW 是一种音频编码格式,使用仅 8 位样本即可获得约 13 位的动态范围。它由 Sun 音频硬件(以及其他硬件)使用。
- audioop.lin2lin(fragment, width, newwidth)¶
在 1、2、3 和 4 字节格式之间转换样本。
注意
在某些音频格式(例如 .WAV 文件)中,16、24 和 32 位样本是有符号的,但 8 位样本是无符号的。因此,当针对这些格式转换为 8 位宽样本时,还需要将 128 添加到结果中
new_frames = audioop.lin2lin(frames, old_width, 1) new_frames = audioop.bias(new_frames, 1, 128)
当从 8 位转换为 16、24 或 32 位宽样本时,必须应用相同的反向操作。
- audioop.lin2ulaw(fragment, width)¶
将音频片段中的样本转换为 u-LAW 编码,并将其作为字节对象返回。u-LAW 是一种音频编码格式,使用仅 8 位样本即可获得约 14 位的动态范围。它由 Sun 音频硬件(以及其他硬件)使用。
- audioop.max(fragment, width)¶
返回片段中所有样本的绝对值的最大值。
- audioop.maxpp(fragment, width)¶
返回声音片段中的最大峰峰值。
- audioop.minmax(fragment, width)¶
返回一个元组,其中包含声音片段中所有样本的最小值和最大值。
- audioop.mul(fragment, width, factor)¶
返回一个片段,其中原始片段中的所有样本都乘以浮点值factor。如果发生溢出,样本将被截断。
- audioop.ratecv(fragment, width, nchannels, inrate, outrate, state[, weightA[, weightB]])¶
转换输入片段的帧速率。
state 是一个包含转换器状态的元组。转换器返回一个元组
(newfragment, newstate)
,并且应将newstate 传递给ratecv()
的下一次调用。初始调用应将None
作为状态传递。weightA 和 weightB 参数是简单数字滤波器的参数,分别默认为
1
和0
。
- audioop.reverse(fragment, width)¶
反转片段中的样本并返回修改后的片段。
- audioop.rms(fragment, width)¶
返回片段的均方根,即
sqrt(sum(S_i^2)/n)
。这是音频信号中功率的度量。
- audioop.tomono(fragment, width, lfactor, rfactor)¶
将立体声片段转换为单声道片段。在将两个声道相加以得到单声道信号之前,左声道乘以lfactor,右声道乘以rfactor。
- audioop.tostereo(fragment, width, lfactor, rfactor)¶
从单声道片段生成立体声片段。立体声片段中的每对采样都从单声道采样计算得出,其中左声道采样乘以lfactor,右声道采样乘以rfactor。
- audioop.ulaw2lin(fragment, width)¶
将 u-LAW 编码的音频片段转换为线性编码的音频片段。u-LAW 编码始终使用 8 位采样,因此width 在此处仅指输出片段的采样宽度。
请注意,诸如 mul()
或 max()
等操作不会区分单声道和立体声片段,即所有采样都得到平等对待。如果这是一个问题,则应首先将立体声片段拆分为两个单声道片段,然后重新组合。以下是如何执行此操作的一个示例
def mul_stereo(sample, width, lfactor, rfactor):
lsample = audioop.tomono(sample, width, 1, 0)
rsample = audioop.tomono(sample, width, 0, 1)
lsample = audioop.mul(lsample, width, lfactor)
rsample = audioop.mul(rsample, width, rfactor)
lsample = audioop.tostereo(lsample, width, 1, 0)
rsample = audioop.tostereo(rsample, width, 0, 1)
return audioop.add(lsample, rsample, width)
如果您使用 ADPCM 编码器构建网络数据包并且希望您的协议是无状态的(即能够容忍数据包丢失),则不仅应传输数据,还应传输状态。请注意,您应将初始状态(传递给 lin2adpcm()
的状态)发送给解码器,而不是最终状态(由编码器返回)。如果您想使用 struct.Struct
以二进制形式存储状态,则可以将第一个元素(预测值)编码为 16 位,将第二个元素(增量索引)编码为 8 位。
ADPCM 编码器从未与其他 ADPCM 编码器进行过比较,只与它们自己进行过比较。很可能是,我误解了标准,在这种情况下,它们将无法与各自的标准互操作。
find*()
例程乍一看可能有点奇怪。它们主要用于进行回声消除。执行此操作的一种相当快速的方法是选择输出采样的最活跃部分,在输入采样中找到该部分,然后从输入采样中减去整个输出采样
def echocancel(outputdata, inputdata):
pos = audioop.findmax(outputdata, 800) # one tenth second
out_test = outputdata[pos*2:]
in_test = inputdata[pos*2:]
ipos, factor = audioop.findfit(in_test, out_test)
# Optional (for better cancellation):
# factor = audioop.findfactor(in_test[ipos*2:ipos*2+len(out_test)],
# out_test)
prefill = '\0'*(pos+ipos)*2
postfill = '\0'*(len(inputdata)-len(prefill)-len(outputdata))
outputdata = prefill + audioop.mul(outputdata, 2, -factor) + postfill
return audioop.add(inputdata, outputdata, 2)