File size: 2,508 Bytes
fe7e262
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
"""
CPJKU's beat_this
- reference: https://github.com/CPJKU/beat_this
"""

import sys
from pathlib import Path

import torch

from .utils import load_audio

if not sys.version_info < (3, 10):
    from beat_this.inference import Audio2Beats


class BeatThis:
    def __init__(self, cuda=None, dbn=True):
        if cuda is None:
            cuda = torch.cuda.is_available()

        self.audio2beats = Audio2Beats(
            device="cuda" if cuda else "cpu",
            dbn=dbn,
        )
        self.use_dbn = dbn

    @torch.no_grad()
    def __call__(
        self,
        file_or_array,
        sr=None,
        beats_per_bar=[3, 4],
        min_bpm=55.0,
        max_bpm=215.0,
        fps=50,
        transition_lambda=100,
    ):
        """
        Function for extracting beat and downbeat positions (in seconds) from a file or a data array.

        Args:
            file_or_array (str or Path or ndarray): Path to the audio file or numpy array containing the audio data.
            sr (int, optional): Sample rate of the audio file. Required if `file_or_array` is a numpy array. Defaults to None.
            if dbn is True:
                beats_per_bar (list, optional): List of possible beats per bar. Defaults to [3, 4].
                min_bpm (float, optional): Minimum tempo in BPM. Defaults to 55.0.
                max_bpm (float, optional): Maximum tempo in BPM. Defaults to 215.0.
                fps (int, optional): Frames per second. Defaults to 50.

        Returns:
            beats (ndarray): Array of beat positions in seconds.
            downbeats (ndarray): Array of downbeat positions in seconds.
        """
        if sys.version_info < (3, 10):
            raise ImportError("Python 3.10 or higher is required to use this function.")

        if isinstance(file_or_array, (str, Path)):
            audio, sr = load_audio(file_or_array, dtype="float64")
        else:
            audio = file_or_array

        if self.use_dbn:
            from madmom.features.downbeats import DBNDownBeatTrackingProcessor

            # WARN: This is a hacky way to set the DBN parameters
            dbn = DBNDownBeatTrackingProcessor(
                beats_per_bar=beats_per_bar,
                min_bpm=min_bpm,
                max_bpm=max_bpm,
                fps=fps,
                transition_lambda=transition_lambda,
            )
            self.audio2beats.frames2beats.dbn = dbn

        beats, downbeats = self.audio2beats(audio, sr)

        return beats, downbeats