【问题标题】:Detect beat and play (wav) file in a synchronised manner以同步方式检测节拍和播放 (wav) 文件
【发布时间】:2012-09-02 22:07:38
【问题描述】:

我正在尝试使用 this 节拍检测算法在 python 中进行音频处理。我已经实现了上述文章中的第一个(非优化版本)。虽然它会打印一些结果,但我无法检测它是否能以某种准确度工作,因为我不知道如何用它播放声音。

目前,我正在使用Popen 在进入计算循环之前用歌曲异步启动我的媒体播放器,但我不确定这种策略是否有效并给出同步结果。

#!/usr/bin/python

import scipy.io.wavfile, numpy, sys, subprocess

# Some abstractions for computation
def sumsquared(arr):
    sum = 0
    for i in arr:
            sum = sum + (i[0] * i[0]) + (i[1] * i[1])

    return sum

if sys.argv.__len__() < 2:
    print 'USAGE: wavdsp <wavfile>'
    sys.exit(1)

numpy.set_printoptions(threshold='nan')
rate, data = scipy.io.wavfile.read(sys.argv[1])


# Beat detection algorithm begin 
# the algorithm has been implemented as per GameDev Article
# Initialisation
data_len = data.__len__()
idx = 0
hist_last = 44032
instant_energy = 0
local_energy = 0
le_multi = 0.023219955 # Local energy multiplier ~ 1024/44100


# Play the song
p = subprocess.Popen(['audacious', sys.argv[1]])

while idx < data_len - 48000:
    dat = data[idx:idx+1024]
    history = data[idx:hist_last]
    instant_energy = sumsquared(dat)
    local_energy = le_multi * sumsquared(history)
    print instant_energy, local_energy
    if instant_energy > (local_energy * 1.3):
            print 'Beat'

    idx = idx + 1024
    hist_last = hist_last + 1024 # Right shift history buffer

 p.terminate()

为了以时间同步的方式获得音频输出和算法(控制台)输出,我可以对脚本进行哪些修改/添加?即当控制台输出特定帧的结果时,该帧必须在扬声器上播放。

【问题讨论】:

  • 你可以将sumsquared改写为一行:return (arr**2).sum()。这会将所有这些计算下推到 C 代码中,并且可能会更快。

标签: python audio-processing beat-detection


【解决方案1】:

工作节拍检测代码(NumPy / PyAudio)

如果您使用 NumPy,此代码可能会有所帮助。它假设信号(使用 PyAudio 读取)是 16 位宽的 Int。如果不是这种情况,请更改或删除 signal.astype() 并调整归一化分频器(此处为最大 int16)。

class SimpleBeatDetection:
    """
    Simple beat detection algorithm from
    http://archive.gamedev.net/archive/reference/programming/features/beatdetection/index.html
    """
    def __init__(self, history = 43):
        self.local_energy = numpy.zeros(history) # a simple ring buffer
        self.local_energy_index = 0 # the index of the oldest element

    def detect_beat(self, signal):

        samples = signal.astype(numpy.int) # make room for squares
        # optimized sum of squares, i.e faster version of (samples**2).sum()
        instant_energy = numpy.dot(samples, samples) / float(0xffffffff) # normalize

        local_energy_average = self.local_energy.mean()
        local_energy_variance = self.local_energy.var()

        beat_sensibility = (-0.0025714 * local_energy_variance) + 1.15142857
        beat = instant_energy > beat_sensibility * local_energy_average

        self.local_energy[self.local_energy_index] = instant_energy
        self.local_energy_index -= 1
        if self.local_energy_index < 0:
            self.local_energy_index = len(self.local_energy) - 1

        return beat

用于 wav 读取或麦克风记录的 PyAudio 示例将为您提供所需的信号数据。使用frombuffer()高效创建 NumPy 数组

data = stream.read(CHUNK)
signal = numpy.frombuffer(data, numpy.int16)

【讨论】:

  • 实现了这一点,并通过在我的麦克风前鼓掌来测试它。假阳性率非常高。也许我的期望太高了,我可以对其进行调整以改进,但只是注意到它不是一个强大的、开箱即用的解决方案。
  • 我知道这是一个老问题,但有没有人设法改进这个例子?我和@Oddthinking 有同样的问题。我试图改进它,并且仍在尝试,但到目前为止没有运气。
【解决方案2】:

一种更简单的非实时方法

我对将控制台输出与实时音频同步并不乐观。我的方法会简单一些。当您阅读并处理文件时,将样本写入新的音频文件。每当检测到节拍时,为您正在编写的音频添加一些难以错过的声音,例如响亮、短促的正弦音。这样,您就可以从听觉上评估结果的质量。

合成您的节拍指示器声音:

def testsignal(hz,seconds=5.,sr=44100.):
    '''
    Create a sine wave at hz for n seconds
    '''
    # cycles per sample
    cps = hz / sr
    # total samples
    ts = seconds * sr
    return np.sin(np.arange(0,ts*cps,cps) * (2*np.pi))

signal = testsignal(880,seconds = .02)

在您的while 循环中,如果检测到节拍,则将测试信号添加到输入帧,如果未检测到节拍,则保持帧不变。将这些帧写入文件并收听以评估节拍检测的质量。

这是aubio 库用来评估节拍检测结果的方法。请参阅文档here。特别感兴趣的是--output 命令行选项的文档:

将结果保存在此文件中。该文件将在模型上创建 输入文件。结果由一个非常短的木块样本标记。

优化

由于 numpy 已经是一个依赖项,使用它的功能来加速你的算法。您可以将sumsquared 函数重写为:

def sumsquared(arr):
    return (arr**2).sum()

摆脱 Python for 循环并将这些计算下推到 C 代码中应该可以提高速度。

另外,请查看this questionthis question,了解如何使用numpy.lib.stride_tricks 方法在while 循环中矢量化局部到瞬时能量比较。

【讨论】:

    【解决方案3】:

    一个不错的选择是尝试使用 portaudio (pyaudio) 来获取实时数据,然后您应该能够查看它是否匹配。

    这是一个很好的例子,使用 pyaudio 中的 fft:

    http://www.swharden.com/blog/2010-03-05-realtime-fft-graph-of-audio-wav-file-or-microphone-input-with-python-scipy-and-wckgraph/

    【讨论】:

      猜你喜欢
      • 2018-10-16
      • 2011-02-28
      • 1970-01-01
      • 1970-01-01
      • 2013-04-01
      • 2012-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多