【问题标题】:Detecting beat energy with Librosa, finding the first beat of each bar使用 Librosa 检测节拍能量,找到每个小节的第一个节拍
【发布时间】:2019-08-06 21:48:36
【问题描述】:

我需要使用 Librosa 找到峰值的能量,以便检测每个小节的第一个节拍。

我正在使用 Librosa 检测点击轨道中的音频节拍。这运作良好,但我现在希望检测每个小节的第一个节拍。我认为最好的方法是检测每个节拍的能量或音高。

目前我正在将所有节拍记录到一个数组中。如何检测每个小节的第一个节拍?

def findPeaks(inputFile):
    print(">>> Finding peaks...\n")
    y, sr = librosa.load(inputFile)
    onset_env = librosa.onset.onset_strength(
        y=y, sr=sr, hop_length=512, aggregate=np.median
    )
    global inputTrackPeaks  # array of peaks
    inputTrackPeaks = librosa.util.peak_pick(onset_env, 3, 3, 3, 5, 0.5, 10)
    inputTrackPeaks = librosa.frames_to_time(inputTrackPeaks, sr=sr)
    inputTrackPeaks = inputTrackPeaks * 1000  # convert array to milliseconds
    print("Peak positions (ms): \n", inputTrackPeaks)

【问题讨论】:

    标签: python librosa audio-analysis


    【解决方案1】:

    对于一个非常简单的节拍跟踪器,您可能想要使用 librosa 的内置 beat tracking

    import librosa
    
    y, sr = librosa.load(librosa.util.example_audio_file())
    tempo, beats = librosa.beat.beat_track(y=y, sr=sr)
    # beats now contains the beat *frame positions*
    # convert to timestamps like this:
    beat_times = librosa.frames_to_time(beats, sr=sr)
    

    这为您提供了节拍位置。但您实际上一直在要求悲观估计。您找到具有最高能量的节拍的想法很好,但您可能需要结合一些额外的知识和平均相应节拍。例如,如果您知道曲目是 4/4 拍,则可以将每 4 个节拍的能量相加,然后得出能量和最高的节拍位置为强拍。

    大概是这样的:

    import librosa
    import numpy as np
    
    y, sr = librosa.load('my file.wav')
    # get onset envelope
    onset_env = librosa.onset.onset_strength(y, sr=sr, aggregate=np.median)
    # get tempo and beats
    tempo, beats = librosa.beat.beat_track(onset_envelope=onset_env, sr=sr)
    # we assume 4/4 time
    meter = 4
    # calculate number of full measures 
    measures = (len(beats) // meter)
    # get onset strengths for the known beat positions
    # Note: this is somewhat naive, as the main strength may be *around*
    #       rather than *on* the detected beat position. 
    beat_strengths = onset_env[beats]
    # make sure we only consider full measures
    # and convert to 2d array with indices for measure and beatpos
    measure_beat_strengths = beat_strengths[:measures * meter].reshape(-1, meter)
    # add up strengths per beat position
    beat_pos_strength = np.sum(measure_beat_strengths, axis=0)
    # find the beat position with max strength
    downbeat_pos = np.argmax(beat_pos_strength)
    # convert the beat positions to the same 2d measure format
    full_measure_beats = beats[:measures * meter].reshape(-1, meter)
    # and select the beat position we want: downbeat_pos
    downbeat_frames = full_measure_beats[:, downbeat_pos]
    print('Downbeat frames: {}'.format(downbeat_frames))
    # print times
    downbeat_times = librosa.frames_to_time(downbeat_frames, sr=sr)
    print('Downbeat times in s: {}'.format(downbeat_times))
    

    您使用这样的代码的里程会有所不同。成功取决于音乐的种类、流派、节奏、节拍检测的质量等。那是因为它不是微不足道的。 事实上,悲观估计是当前Music Information Retrieval (MIR) 的研究课题,并没有完全解决。有关基于高级深度学习的自动强拍跟踪的最新评论,您可能需要查看this article

    【讨论】:

    • 谢谢,太好了。然而,一个问题是,并非我使用的所有点击轨道都是恒定的 4/4。有些只有 2/4 的酒吧。我应该指出,我用作源文件的点击轨道上的强拍与其他小节有不同的音调。因此,是否有一种方法可以通过音高而不是能量来检测强拍?
    • 如果您的点击轨道仅包含两种不同类型的音高/点击,而没有其他内容,为什么不简单地(错误地)使用librosa.core.piptrack,识别峰值并将其分类为弱拍。如果“咔嗒”声是和声的,您应该能够测量要寻找哪个音高作为强拍。另请参阅stackoverflow.com/q/43877971/942774 并接受选择最大音高的答案。
    猜你喜欢
    • 1970-01-01
    • 2017-05-02
    • 1970-01-01
    • 2012-01-29
    • 1970-01-01
    • 2011-09-27
    • 1970-01-01
    • 1970-01-01
    • 2011-09-27
    相关资源
    最近更新 更多