【发布时间】:2012-03-19 00:05:56
【问题描述】:
我正在编写一个 python 函数来返回 .wav 文件的响度。 RMS 似乎是最好的指标,Detect and record a sound with python。
audioop.rms() 可以解决问题,但我想避免将 audioop 作为依赖项,并且我已经导入了 numpy.但我没有得到相同的 RMS 值,希望能帮助我理解正在发生的事情。
来自audioop page,它表示rms 计算正是您所期望的,即sqrt(sum(S_i^2)/n),其中S_i 是i-th 声音样本。似乎它不是火箭科学。
要使用 numpy,我首先将声音转换为 numpy 数组,并且总是看到相同的最小值/最大值和相同的数据长度(因此转换看起来很好)。
>>> d = np.frombuffer(data, np.int16)
>>> print (min(d), max(d)), audioop.minmax(data,2)
(-2593, 2749) (-2593, 2749)
但我得到非常不同的 RMS 值,甚至没有接近球场:
>>> numpy_rms = np.sqrt(sum(d*d)/len(d))
>>> print numpy_rms, audioop.rms(data, 2)
41.708703254716383, 120
它们之间的区别是可变的,我看不到明显的模式,例如,我也得到:
63.786714248938772, 402
62.779300661773405, 148
我的 numpy RMS 代码给出了与此处相同的输出:Numpy Root-Mean-Squared (RMS) smoothing of a signal
我看不出哪里出错了,但有些不对劲。非常感谢任何帮助。
编辑/更新:
如果它有用,这是我最终得到的代码。它没有audioop那么快,但仍然足够快,足以满足我的目的。值得注意的是,使用 np.mean() 比我使用 python sum() 的版本快得多(~100 倍)。
def np_audioop_rms(data, width):
"""audioop.rms() using numpy; avoids another dependency for app"""
#_checkParameters(data, width)
if len(data) == 0: return None
fromType = (np.int8, np.int16, np.int32)[width//2]
d = np.frombuffer(data, fromType).astype(np.float)
rms = np.sqrt( np.mean(d**2) )
return int( rms )
【问题讨论】:
-
谢谢,但不行。使用: "d = np.frombuffer(data, np.short)" 给出完全相同的行为。
-
对不起,我在看到回复之前已经删除了评论。顺便说一句,如果您使用
double来计算np.power(a, 2),例如,将其更改为np.power(a, 2.),则可以使用window_rms()。 -
为什么不能使用
audioop?数据有多大?可以使用 C 扩展吗? -
我可以使用 audioop,但这样做意味着为应用程序打包另一个依赖项(= 更大的下载量,并且在构建版本时更麻烦)。我们已经包含了 numpy,并且不需要每一微秒。可能只有很短的声音片段。
-
audioop 在 stdlib 中还是我遗漏了什么?您可以使用
np.power(np.frombuffer(data, dtype=fromType), 2.0).mean()**.5来避免使用.astype()进行复制(这里power创建浮点数组)。