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