python3从零学习-5.11.1、 audioop—操作原始音频数据

78 篇文章 1 订阅
78 篇文章 0 订阅

 

audioop模块包含一些对声音片段的有用操作。它对声音片段进行操作,这些声音片段由8、16、24或32位宽的带符号整数样本组成,存储在类似字节的对象中。除非另有指定,否则所有标量项都是整数。

 

在3.4版更改:支持24位样品了。所有函数现在都接受任何字节类对象。字符串输入现在会立即导致错误。

 

本模块支持a-LAW、u-LAW和Intel/DVI ADPCM编码。

 

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

 

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

exception audioop.error

这个异常会在所有错误上引发,比如每个样本的未知字节数,等等。

 

audioop.add(fragment1, fragment2, width)

返回一个片段,它是作为参数传递的两个样本的附加。宽度是以字节为单位的采样宽度,可以是1、2、3或4。两个片段应该具有相同的长度。样本被截断以防溢出。

 

audioop.adpcm2lin(adpcmfragment, width, state)

解码一个英特尔/DVI ADPCM编码片段到一个线性片段。有关ADPCM编码的详细信息,请参阅lin2adpcm()的描述。返回一个元组(sample, newstate),其中示例的宽度在width中指定。

 

audioop.alaw2lin(fragment, width)

在a-LAW编码转换声音片段到线性编码的声音片段。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示例,反之亦然。

 

audioop.cross(fragment, width)

返回作为参数传递的片段中的零交叉次数。

 

audioop.findfactor(fragment, reference)

返回一个因子F,使rms(添加(片段,mul(引用,-F))最小,即,返回应该与之相乘的引用以使其尽可能与fragment匹配的因子。这些片段都应该包含2字节的示例。

 

这个例程所花费的时间与len(fragment)成比例。

 

audioop.findfit(fragment, reference)

尽量将引用匹配到片段的一部分(应该是较长的片段)。这(从概念上)是通过从片段中取出切片、使用findfactor()计算最佳匹配并最小化结果来完成的。这些片段都应该包含2字节的示例。返回一个元组(偏移量、因子),其中偏移量是最优匹配开始的片段中的(整数)偏移量,而因子是findfactor()中的(浮点)因子。

 

audioop.findmax(fragment, length)

搜索片段,以获得最大能量的片段长度样本(不是字节!),返回rms(fragment[i*2:(i+length)*2])的最大值。这些片段都应该包含2字节的示例。

例程花费的时间与len(fragment)成比例。

 

audioop.getsample(fragment, width, index)

从片段中返回样本索引的值。

 

audioop.lin2adpcm(fragment, width, state)

转换样本4位英特尔/DVI ADPCM编码。ADPCM编码是一种自适应编码方案,其中每个4位数是一个样本和下一个之间的差,除以一个(变化的)步骤。IMA选择了Intel/DVI ADPCM算法,很有可能成为标准。

 

state是包含编码器状态的元组。编码器返回一个元组(adpcmfrag, newstate), newstate应该被传递给lin2adpcm()的下一个调用。在初始调用中,任何状态都不能作为状态传递。adpcmfrag是ADPCM编码片段,每字节封装2个4位值。

 

audioop.lin2alaw(fragment, width)

将音频片段中的样本转换为a- law编码并将其作为字节对象返回。a- law是一种音频编码格式,你得到一个动态范围约13位使用仅8位样本。它被Sun音频硬件所使用。

 

audioop.lin2lin(fragment, width, newwidth)

在1字节、2字节、3字节和4字节格式之间转换示例。

注解在某些音频格式,如wav文件,16日24和32位样品签署,但8位样本是无符号的。所以当转换为8位宽的样本为这些格式,你也需要增加128的结果:

new_frames = audioop。lin2lin(帧old_width 1)

new_frames = audioop。偏见(new_frames, 128)

同样的,反过来,必须应用从8位到16位、24位或32位宽度样本的转换。

audioop.lin2ulaw(fragment, width)

将音频片段中的样本转换为u-LAW编码并将其作为字节对象返回。u-LAW是一种音频编码格式,你得到一个动态范围约14位使用仅8位样本。它被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), 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律编码到线性编码的声音片段。u-LAW编码总是使用8位样本,因此宽度仅指输出片段的样本宽度。

 

注意,像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。为了将状态存储为二进制,可以将第一个元素(预测值)编码为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)

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值