File size: 6,043 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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
"""
Patch for scipy/librosa/madmom compatibility issues.
This file patches compatibility issues with newer versions of scipy and numpy.
"""

import sys
import importlib
import inspect
import types
import warnings
import numpy as np

# Suppress the deprecation warnings for numpy patches
warnings.filterwarnings("ignore", message=".*np.float.*deprecated.*")
warnings.filterwarnings("ignore", message=".*np.int.*deprecated.*")

def patch_numpy_compatibility():
    """
    Patch numpy to restore deprecated attributes for compatibility with older packages.
    This fixes compatibility issues with:
    - madmom (uses np.float in io/__init__.py)
    - other packages that rely on deprecated numpy attributes
    """
    # Restore deprecated numpy attributes if they don't exist
    if not hasattr(np, 'float'):
        np.float = np.float64
        print("Applied numpy patch: np.float -> np.float64")
    if not hasattr(np, 'int'):
        np.int = np.int_
        print("Applied numpy patch: np.int -> np.int_")
    if not hasattr(np, 'complex'):
        np.complex = np.complex128
        print("Applied numpy patch: np.complex -> np.complex128")
    if not hasattr(np, 'bool'):
        np.bool = np.bool_
        print("Applied numpy patch: np.bool -> np.bool_")

def apply_scipy_patches():
    """
    Apply patches to make librosa work with newer versions of scipy.
    Specifically, this patches the __beat_tracker function in librosa.beat
    to use scipy.signal.windows.hann instead of scipy.signal.hann.
    """
    try:
        import scipy.signal
        import librosa.beat
        
        # Check if scipy.signal.hann exists
        if not hasattr(scipy.signal, 'hann') and hasattr(scipy.signal.windows, 'hann'):
            print("Applying patch: scipy.signal.hann -> scipy.signal.windows.hann")
            
            # Create a reference to the windows.hann function in the signal module
            scipy.signal.hann = scipy.signal.windows.hann
            
            # Reload librosa.beat to use the patched scipy.signal
            importlib.reload(librosa.beat)
            
            return True
    except Exception as e:
        warnings.warn(f"Failed to apply scipy patch: {e}")
        return False

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']
            
            print("Successfully patched librosa.beat.__trim_beats")
            return True
    except Exception as e:
        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
        print("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

# Apply numpy compatibility patches immediately when this module is imported
patch_numpy_compatibility()

if __name__ == "__main__":
    # Apply all patches
    patch_numpy_compatibility()
    apply_scipy_patches()
    patch_librosa_beat_tracker()
    monkey_patch_beat_track()