File size: 3,815 Bytes
77a71b4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
"""
Librosa compatibility patches.

This module patches librosa to fix compatibility issues with newer
versions of SciPy and NumPy, particularly around beat tracking functionality.
"""

import inspect
import warnings
import numpy as np
from utils.logging import log_debug, is_debug_enabled


def patch_librosa_beat_tracker():
    """
    Directly patch the __beat_tracker and __trim_beats functions in librosa.beat
    to use scipy.signal.windows.hann instead of scipy.signal.hann.
    """
    try:
        import librosa.beat
        import scipy.signal

        # Get the source code of the __trim_beats function
        trim_beats_source = inspect.getsource(librosa.beat.__trim_beats)

        # Replace scipy.signal.hann with scipy.signal.windows.hann
        if 'scipy.signal.hann' in trim_beats_source:
            new_source = trim_beats_source.replace('scipy.signal.hann', 'scipy.signal.windows.hann')

            # Compile the new function
            code = compile(new_source, '<string>', 'exec')

            # Create a new function object
            new_locals = {}
            exec(code, librosa.beat.__dict__, new_locals)

            # Replace the original function with our patched version
            librosa.beat.__trim_beats = new_locals['__trim_beats']

            if is_debug_enabled():
                log_debug("Successfully patched librosa.beat.__trim_beats")
            return True

    except Exception as e:
        if is_debug_enabled():
            warnings.warn(f"Failed to patch librosa.beat.__trim_beats: {e}")
        return False


def monkey_patch_beat_track():
    """
    Create a monkey-patched version of librosa.beat.beat_track that doesn't use
    the problematic scipy.signal.hann function.
    """
    try:
        import librosa
        import numpy as np

        # Original beat_track function
        original_beat_track = librosa.beat.beat_track

        def patched_beat_track(y=None, sr=22050, onset_envelope=None, hop_length=512,
                              start_bpm=120.0, tightness=100, trim=True, bpm=None,
                              units='frames', prior=None, **kwargs):
            """
            Patched version of librosa.beat.beat_track that handles the scipy.signal.hann issue
            """
            # Use the original function to get tempo and beats
            tempo, beats = original_beat_track(y=y, sr=sr, onset_envelope=onset_envelope,
                                              hop_length=hop_length, start_bpm=start_bpm,
                                              tightness=tightness, trim=False, bpm=bpm,
                                              units=units, prior=prior, **kwargs)

            # If trim is True, we need to handle the trimming ourselves
            if trim and len(beats) > 0:
                # Get the onset envelope if it wasn't provided
                if onset_envelope is None:
                    onset_envelope = librosa.onset.onset_strength(y=y, sr=sr, hop_length=hop_length, **kwargs)

                # Simple trimming without using scipy.signal.hann
                # Just keep beats where the onset strength is above the median
                if len(beats) > 0:
                    onset_strength_at_beats = onset_envelope[beats]
                    median_strength = np.median(onset_strength_at_beats)
                    beats = beats[onset_strength_at_beats >= median_strength]

            return tempo, beats

        # Replace the original function with our patched version
        librosa.beat.beat_track = patched_beat_track
        if is_debug_enabled():
            log_debug("Successfully monkey-patched librosa.beat.beat_track")
        return True

    except Exception as e:
        warnings.warn(f"Failed to monkey-patch librosa.beat.beat_track: {e}")
        return False