audioop ---操作原始音频数据


这个 audioop 模块包含一些对声音片段的有用操作。它操作由8、16、24或32位宽的有符号整数样本组成的声音片段,存储在 bytes-like objects . 除非另有规定,否则所有标量项都是整数。

在 3.4 版更改: 增加了对24位样本的支持。所有功能现在接受任何 bytes-like object . 字符串输入现在会导致立即错误。

此模块支持a-law、u-law和intel/dvi adpcm编码。

一些更复杂的操作只获取16位样本,否则样本大小(以字节为单位)始终是操作的参数。

模块定义以下变量和函数:

exception audioop.error

所有错误都会引发此异常,例如每个样本的字节数未知等。

audioop.add(fragment1, fragment2, width)

返回一个片段,这是作为参数传递的两个样本的相加。 宽度 是以字节为单位的样本宽度,或者 1234 . 两个片段的长度应该相同。如果溢出,则截断样本。

audioop.adpcm2lin(adpcmfragment, width, state)

将intel/dvi adpcm编码的片段解码为线性片段。参见的说明 lin2adpcm() 有关ADPCM编码的详细信息。返回元组 (sample, newstate) 其中样本的宽度在 宽度 .

audioop.alaw2lin(fragment, width)

将A律编码中的声音片段转换为线性编码的声音片段。A-law编码总是使用8位样本,所以 宽度 这里只引用输出片段的样本宽度。

audioop.avg(fragment, width)

返回片段中所有样本的平均值。

audioop.avgpp(fragment, width)

返回片段中所有样本的平均峰值。没有进行过滤,所以这个程序的有用性是值得怀疑的。

audioop.bias(fragment, width, bias)

返回一个片段,该片段是添加到每个样本的原始片段。如果溢出,样品会被包裹起来。

audioop.byteswap(fragment, width)

“byteswap”一个片段中的所有示例,并返回修改后的片段。将big-endian示例转换为little-endian,反之亦然。

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) 在哪里? 抵消 是(整数)偏移量 fragment 最佳匹配开始的位置和 因素 是(浮点)因子 findfactor() .

audioop.findmax(fragment, length)

搜索 fragment 对于一片长度 长度 示例(不是字节!)最大能量,即返回 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)新状态 应传递到的下一个调用 lin2adpcm() . 在最初的通话中, None 可以作为状态传递。 adpcfrag公司 是ADPCM编码的每字节压缩2个4位值的片段。

audioop.lin2alaw(fragment, width)

将音频片段中的示例转换为a-law编码,并将其作为bytes对象返回。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编码,并将其作为bytes对象返回。U-law是一种音频编码格式,通过这种格式,您只需使用8位样本就可以获得大约14位的动态范围。它被Sun音频硬件等使用。

audioop.max(fragment, width)

返回的最大值 绝对值 在一个片段中的所有样本中。

audioop.maxpp(fragment, width)

返回声音片段中的最大峰值。

audioop.minmax(fragment, width)

返回一个由声音片段中所有样本的最小值和最大值组成的元组。

audioop.mul(fragment, width, factor)

返回一个片段,其中原始片段中的所有样本都乘以浮点值 因素 . 如果溢出,则截断样本。

audioop.ratecv(fragment, width, nchannels, inrate, outrate, state[, weightA[, weightB]])

转换输入片段的帧速率。

state 是包含转换器状态的元组。转换器返回一个元组 (newfragment, newstate)新状态 应传递到的下一个调用 ratecv() . 最初的调用应该通过 None 作为国家。

这个 秤锤韦伯 参数是简单数字滤波器的参数,默认为 10 分别。

audioop.reverse(fragment, width)

在片段中反转样本并返回修改后的片段。

audioop.rms(fragment, width)

返回片段的均方根,即 sqrt(sum(S_i^2)/n) .

这是对音频信号功率的测量。

audioop.tomono(fragment, width, lfactor, rfactor)

将立体片段转换为单片段。左通道乘以 因子 右边的频道 因子 在添加两个通道以发出单声道信号之前。

audioop.tostereo(fragment, width, lfactor, rfactor)

从单个片段生成立体片段。立体声片段中的每对样本都是从单声道样本中计算出来的,左声道样本乘以 lfactor 和右通道样本 rfactor .

audioop.ulaw2lin(fragment, width)

将U律编码中的声音片段转换为线性编码的声音片段。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位,第二个元素(增量索引)编码为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)