Spaces:
Runtime error
Runtime error
import copy | |
import librosa | |
import essentia | |
import essentia.standard | |
import numpy as np | |
import scipy.interpolate as interp | |
import note_seq | |
SAMPLERATE = 44100 | |
def nearest_onset_offset_digitize(on, off, bins): | |
intermediate = (bins[1:] + bins[:-1]) / 2 | |
on_idx = np.digitize(on, intermediate) | |
off_idx = np.digitize(off, intermediate) | |
off_idx[on_idx == off_idx] += 1 | |
# off_idx = np.clip(off_idx, a_min=0, a_max=len(bins) - 1) | |
return on_idx, off_idx | |
def apply_sustain_pedal(pm): | |
ns = note_seq.midi_to_note_sequence(pm) | |
susns = note_seq.apply_sustain_control_changes(ns) | |
suspm = note_seq.note_sequence_to_pretty_midi(susns) | |
return suspm | |
def interpolate_beat_times(beat_times, steps_per_beat, extend=False): | |
beat_times_function = interp.interp1d( | |
np.arange(beat_times.size), | |
beat_times, | |
bounds_error=False, | |
fill_value="extrapolate", | |
) | |
if extend: | |
beat_steps_8th = beat_times_function( | |
np.linspace(0, beat_times.size, beat_times.size * steps_per_beat + 1) | |
) | |
else: | |
beat_steps_8th = beat_times_function( | |
np.linspace(0, beat_times.size - 1, beat_times.size * steps_per_beat - 1) | |
) | |
return beat_steps_8th | |
def midi_quantize_by_beats( | |
sample, beat_times, steps_per_beat, ignore_sustain_pedal=False | |
): | |
ns = note_seq.midi_file_to_note_sequence(sample.midi) | |
if ignore_sustain_pedal: | |
susns = ns | |
else: | |
susns = note_seq.apply_sustain_control_changes(ns) | |
qns = copy.deepcopy(susns) | |
notes = np.array([[n.start_time, n.end_time] for n in susns.notes]) | |
note_attributes = np.array([[n.pitch, n.velocity] for n in susns.notes]) | |
note_ons = np.array(notes[:, 0]) | |
note_offs = np.array(notes[:, 1]) | |
beat_steps_8th = interpolate_beat_times(beat_times, steps_per_beat, extend=False) | |
on_idx, off_idx = nearest_onset_offset_digitize(note_ons, note_offs, beat_steps_8th) | |
beat_steps_8th = interpolate_beat_times(beat_times, steps_per_beat, extend=True) | |
discrete_notes = np.concatenate( | |
(np.stack((on_idx, off_idx), axis=1), note_attributes), axis=1 | |
) | |
def delete_duplicate_notes(dnotes): | |
note_order = dnotes[:, 0] * 128 + dnotes[:, 2] | |
dnotes = dnotes[note_order.argsort()] | |
indices = [] | |
for i in range(1, len(dnotes)): | |
if dnotes[i, 0] == dnotes[i - 1, 0] and dnotes[i, 2] == dnotes[i - 1, 2]: | |
indices.append(i) | |
dnotes = np.delete(dnotes, indices, axis=0) | |
note_order = dnotes[:, 0] * 128 + dnotes[:, 1] | |
dnotes = dnotes[note_order.argsort()] | |
return dnotes | |
discrete_notes = delete_duplicate_notes(discrete_notes) | |
digitized_note_ons, digitized_note_offs = ( | |
beat_steps_8th[on_idx], | |
beat_steps_8th[off_idx], | |
) | |
for i, note in enumerate(qns.notes): | |
note.start_time = digitized_note_ons[i] | |
note.end_time = digitized_note_offs[i] | |
return qns, discrete_notes, beat_steps_8th | |
def extract_rhythm(song, y=None): | |
if y is None: | |
y, sr = librosa.load(song, sr=SAMPLERATE) | |
essentia_tracker = essentia.standard.RhythmExtractor2013(method="multifeature") | |
( | |
bpm, | |
beat_times, | |
confidence, | |
estimates, | |
essentia_beat_intervals, | |
) = essentia_tracker(y) | |
return bpm, beat_times, confidence, estimates, essentia_beat_intervals | |