22.1. audioop
—处理原始音频数据¶
audioop
模块包含对声音片段的一些有用的操作。它对存储在 字节状对象 中的由有符号整数样本8,16,24或32位宽组成的声音片段进行操作。除非另有说明,所有标量项都是整数。
在 3.4 版更改: 增加了对24位样本的支持。所有功能现在接受任何 bytes-like object。字符串输入现在会导致立即错误。
此模块支持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)
,其中样本具有在 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)¶ “Byteswap”片段中的所有样本,并返回修改的片段。将大尾数样本转换为小尾数法,反之亦然。
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 样本(不是字节!)的片段,即
rms(fragment[i*2:(i+length)*2])
为最大的返回 i。片段都应包含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)¶ 从单声道片段生成立体声片段。从单声道采样计算立体声片段中的每对采样,由此通过 rfactor 将左声道采样乘以 lfactor 和右声道采样。
-
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编码器来构建网络数据包,并且您希望您的协议是无状态的(即,能够容忍数据包丢失),您不仅应传输数据,还应传输状态。请注意,您应该将 initial 状态(传递给 lin2adpcm()
的状态)发送到解码器,而不是最终状态(由编码器返回)。如果你想使用 struct.Struct
来存储二进制的状态,你可以编码第一个元素(预测值)在16位和第二个(delta索引)在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)