File size: 4,348 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
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
"""
SheetSage: lead sheet transcription model
- reference: https://github.com/chrisdonahue/sheetsage
"""

import logging
import shutil
import subprocess
import tempfile
from pathlib import Path
from typing import Union

from sheetsage.infer import sheetsage as sheetsage_infer
from tqdm import tqdm as tqdm_fn


class SheetSage:
    def __init__(self):
        pass

    def __call__(
        self,
        audio_path: Union[str, Path] = None,
        audio_url: str = None,
        segment_start_hint=None,
        segment_end_hint=None,
        use_jukebox=True,
        measures_per_chunk=8,
        dynamic_chunking=True,
        segment_hints_are_downbeats=False,
        beat_information=None,
        beats_per_measure_hint=None,
        beats_per_minute_hint=None,
        detect_melody=True,
        detect_harmony=True,
        melody_threshold=None,
        harmony_threshold=None,
        beat_detection_padding=15.0,
        avoid_chunking_if_possible=True,
        legacy_behavior=False,
        status_change_callback=lambda s: logging.info(s.name),
        return_intermediaries=False,
        tqdm=tqdm_fn,
        return_dict=True,
    ):
        # assert audio_path or audio_url should be provided but not both
        assert (audio_path and not audio_url) or (audio_url and not audio_path), (
            f"One of audio_path or audio_url should be provided but not both: {audio_path}, {audio_url}"
        )

        assert shutil.which("ffmpeg") is not None, "ffmpeg not found. Please install ffmpeg."

        if audio_path:  # if audio_path is provided
            ext = "flac"
            tmp_audio_file = tempfile.NamedTemporaryFile(suffix=f".{ext}")
            subprocess.run(
                [
                    "ffmpeg",
                    "-i",
                    str(audio_path),
                    "-vn",
                    "-f",
                    ext,
                    "-y",
                    tmp_audio_file.name,
                ]
            )
            audio_path = Path(tmp_audio_file.name)

            assert audio_path.exists(), f"File not found: {audio_path}"
        else:  # if audio_url is provided
            ext = "flac"
            tmp_dir = tempfile.TemporaryDirectory()
            tmp_audio_file = tmp_dir.name + f"/audio.{ext}"
            subprocess.run(
                [
                    "yt-dlp",
                    "-x",
                    "--audio-format",
                    ext,
                    "--audio-quality",
                    "0",
                    "-o",
                    tmp_dir.name + "/audio.%(ext)s",
                    audio_url,
                ],
                check=True,
            )
            audio_path = Path(tmp_audio_file)

        sheetsage_output = sheetsage_infer(
            audio_path_bytes_or_url=audio_path,
            segment_start_hint=segment_start_hint,
            segment_end_hint=segment_end_hint,
            use_jukebox=use_jukebox,
            measures_per_chunk=measures_per_chunk,
            dynamic_chunking=dynamic_chunking,
            segment_hints_are_downbeats=segment_hints_are_downbeats,
            beat_information=beat_information,
            beats_per_measure_hint=beats_per_measure_hint,
            beats_per_minute_hint=beats_per_minute_hint,
            detect_melody=detect_melody,
            detect_harmony=detect_harmony,
            melody_threshold=melody_threshold,
            harmony_threshold=harmony_threshold,
            beat_detection_padding=beat_detection_padding,
            avoid_chunking_if_possible=avoid_chunking_if_possible,
            legacy_behavior=legacy_behavior,
            status_change_callback=status_change_callback,
            return_intermediaries=return_intermediaries,
            tqdm=tqdm,
        )

        if return_dict:
            return sheetsage_output
        else:
            return (
                sheetsage_output["lead_sheet"],
                sheetsage_output["segment_beats"],
                sheetsage_output["segment_beats_times"],
                sheetsage_output["chunks_tertiaries"],
                sheetsage_output["melody_logits"],
                sheetsage_output["harmony_logits"],
                sheetsage_output["melody_last_hidden_state"],
                sheetsage_output["harmony_last_hidden_state"],
            )