File size: 3,358 Bytes
90f7c1e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 os.path
import json
from tqdm import tqdm
import pandas as pd
import numpy as np
import textgrid
import pretty_midi
import music21
import librosa
import soundfile as sf


def piano_roll_to_pretty_midi(piano_roll, fs=100, program=0, bpm=120):
    notes, frames = piano_roll.shape
    pm = pretty_midi.PrettyMIDI()
    instrument = pretty_midi.Instrument(program=program, )

    # pad 1 column of zeros so we can acknowledge inital and ending events
    piano_roll = np.pad(piano_roll, [(0, 0), (1, 1)], 'constant')

    # use changes in velocities to find note on / note off events
    velocity_changes = np.nonzero(np.diff(piano_roll).T)

    # keep track on velocities and note on times
    prev_velocities = np.zeros(notes, dtype=int)
    note_on_time = np.zeros(notes)

    for time, note in zip(*velocity_changes):
        # use time + 1 because of padding above
        velocity = piano_roll[note, time + 1]
        time = time / fs * bpm / 120
        # time = time / fs
        if velocity > 0:
            if prev_velocities[note] == 0:
                note_on_time[note] = time
                prev_velocities[note] = velocity
        else:
            pm_note = pretty_midi.Note(
                velocity=prev_velocities[note],
                pitch=note,
                start=note_on_time[note],
                end=time)
            instrument.notes.append(pm_note)
            prev_velocities[note] = 0
    pm.instruments.append(instrument)

    beats = np.array([0, int(pm.get_end_time()+1)])
    pm.adjust_times(beats, beats * 120 / bpm)
    # print(beats)
    return pm


f = open('CSD/English/metadata.json', encoding="utf8")
meta = json.load(f)
folder = 'CSD/English/'
for wav in tqdm(os.listdir(folder+'wav')):
    song_id = wav.replace('.wav', '')
    midi_id = wav.replace('.wav', '.mid')
    roll_id = wav.replace('.wav', '.npy')

    wav, sr = librosa.load(folder+'wav/'+wav)
    midi = pretty_midi.PrettyMIDI(folder+'mid/'+midi_id)
    roll = midi.get_piano_roll()

    bpm = meta[song_id]['tempo']

    for i in range(int(roll.shape[1])//1000):
        # print(i)
        start = i*10
        end = (i+1)*10

        wav_seg = wav[round(start * sr):round(end * sr)]

        os.makedirs('CSD_segements/'+song_id+'/vocal/', exist_ok=True)
        os.makedirs('CSD_segements/' + song_id + '/roll/', exist_ok=True)
        os.makedirs('CSD_segements/' + song_id + '/midi/', exist_ok=True)

        sf.write('CSD_segements/'+song_id+'/vocal/'+str(i)+'.wav', wav_seg, samplerate=sr)

        cur_roll = roll[:, round(100*start):round(100*end)]

        if round((end-start)*100) != cur_roll.shape[1]:
            print(sentence)
            print(song_id)
            print((end-start)*100)
            print(cur_roll.shape)

        # save npy rolls
        np.save('CSD_segements/'+song_id+'/roll/'+str(i)+'.npy', cur_roll)

        # save midi files
        cur_midi = piano_roll_to_pretty_midi(cur_roll, fs=100, bpm=bpm)
        # cur_midi.write('cache/'+song_id+str(num)+'.midi')
        cur_midi.write('CSD_segements/'+song_id+'/midi/'+str(i)+'.midi')
        # fctr = bpm/120
        # score = music21.converter.Converter()
        # score.parseFile('cache/'+song_id+str(num)+'.midi')
        # newscore = score.stream.augmentOrDiminish(fctr)
        # newscore.write('midi', 'segements/'+song_id+'/midi/'+str(num)+'.midi')