File size: 2,727 Bytes
88490a8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import glob
import sys
import os


import librosa
import soundfile as sf
import numpy as np

import note_seq
from omegaconf import OmegaConf
from beat_quantizer import extract_rhythm, midi_quantize_by_beats

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from midiaudiopair import MidiAudioPair
from utils.dsp import get_stereo


def estimate(meta_file, ignore_sustain_pedal):
    sample = MidiAudioPair(meta_file)

    if (
        sample.error_code == MidiAudioPair.NO_PIANO
        or sample.error_code == MidiAudioPair.NO_SONG_DIR
        or sample.error_code == MidiAudioPair.NO_SONG
    ):
        return

    bpm, beat_times, confidence, estimates, essentia_beat_intervals = extract_rhythm(sample.song)
    beat_times = np.array(beat_times)
    essentia_beat_intervals = np.array(essentia_beat_intervals)

    qns, discrete_notes, beat_steps_8th = midi_quantize_by_beats(
        sample, beat_times, 2, ignore_sustain_pedal=ignore_sustain_pedal
    )

    qpm = note_seq.note_sequence_to_pretty_midi(qns)
    qpm.instruments[0].control_changes = []
    qpm.write(sample.qmidi)
    y, sr = librosa.load(sample.song, sr=None)
    qpm_y = qpm.fluidsynth(sr)
    qmix = get_stereo(y, qpm_y, 0.4)
    sf.write(file=sample.qmix, data=qmix.T, samplerate=sr, format="flac")

    meta = OmegaConf.load(meta_file)
    meta.tempo = OmegaConf.create()
    meta.tempo.bpm = bpm
    meta.tempo.confidence = confidence
    OmegaConf.save(meta, meta_file)

    np.save(sample.notes, discrete_notes)
    np.save(sample.beatstep, beat_steps_8th)
    np.save(sample.beattime, beat_times)
    np.save(sample.beatinterval, essentia_beat_intervals)


def main(meta_files, ignore_sustain_pedal):
    from tqdm import tqdm
    import multiprocessing
    from joblib import Parallel, delayed

    def files():
        pbar = tqdm(meta_files)
        for meta_file in pbar:
            pbar.set_description(meta_file)
            yield meta_file

    Parallel(n_jobs=multiprocessing.cpu_count() // 2)(
        delayed(estimate)(meta_file, ignore_sustain_pedal) for meta_file in files()
    )


if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser(description="bpm estimate using essentia")

    parser.add_argument(
        "data_dir",
        type=str,
        default=None,
        help="""directory contains {id}/{pop_filename.wav}
        """,
    )

    parser.add_argument(
        "--ignore_sustain_pedal",
        default=False,
        action="store_true",
        help="whether dry_run",
    )

    args = parser.parse_args()

    meta_files = sorted(glob.glob(args.data_dir + "/*.yaml"))
    print("meta ", len(meta_files))

    main(meta_files, args.ignore_sustain_pedal)