Spaces:
Sleeping
Sleeping
File size: 4,150 Bytes
f330184 | 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 | from itertools import chain
from pathlib import Path
import numpy as np
def index_to_framewise(index, length):
"""Convert an index to a framewise sequence"""
sequence = np.zeros(length, dtype=bool)
sequence[index] = True
return sequence
def filename_to_augmentation(filename):
"""Convert a filename to an augmentation factor."""
parts = Path(filename).stem.split("_")
augmentations = {}
for part in parts[1:]:
if part.startswith("ps"):
augmentations["shift"] = int(part[2:])
elif part.startswith("ts"):
augmentations["stretch"] = int(part[2:])
return augmentations
def infer_beat_numbers(beats: np.ndarray, downbeats: np.ndarray) -> np.ndarray:
"""
From beat and downbeat times, infer a number for each beat such that each downbeat
is associated with a 1 and beats in between are counted upwards.
The function requires that all downbeats are also listed as beats.
Args:
beats (numpy.ndarray): Array of beat positions in seconds (including downbeats).
downbeats (numpy.ndarray): Array of downbeat positions in seconds.
Returns:
numbers (numpy.ndarray): Array of integer beat numbers.
"""
# check if all downbeats are beats
if not np.all(np.isin(downbeats, beats)):
raise ValueError("Not all downbeats are beats.")
# handle pickup measure, by considering the beat count of the first full measure
if len(downbeats) >= 2:
# find the number of beats between the first two downbeats
first_downbeat, second_downbeat = np.searchsorted(beats, downbeats[:2])
beats_in_first_measure = second_downbeat - first_downbeat
# find the number of beats before the first downbeat
pickup_beats = first_downbeat
# derive where to start counting
if pickup_beats < beats_in_first_measure:
start_counter = beats_in_first_measure - pickup_beats
else:
print(
"WARNING: There are more beats in the pickup measure than in the first measure. The beat count will start from 2 without trying to estimate the length of the pickup measure."
)
start_counter = 1
else:
print(
"WARNING: There are less than two downbeats in the predictions. Something may be wrong. The beat count will start from 2 without trying to estimate the length of the pickup measure."
)
start_counter = 1
# assemble the beat numbers
numbers = []
counter = start_counter
downbeats = chain(downbeats, [-1])
next_downbeat = next(downbeats)
for beat in beats:
if beat == next_downbeat:
counter = 1
next_downbeat = next(downbeats)
else:
counter += 1
numbers.append(counter)
return np.asarray(numbers)
def save_beat_tsv(beats: np.ndarray, downbeats: np.ndarray, outpath: str) -> None:
"""
Save beat information to a tab-separated file in the standard .beats format:
each line has a time in seconds, a tab, and a beat number (1 = downbeat).
The function requires that all downbeats are also listed as beats.
Args:
beats (numpy.ndarray): Array of beat positions in seconds (including downbeats).
downbeats (numpy.ndarray): Array of downbeat positions in seconds.
outpath (str): Path to the output TSV file.
Returns:
None
"""
# infer beat numbers
numbers = infer_beat_numbers(beats, downbeats)
# write the beat file
Path(outpath).parent.mkdir(parents=True, exist_ok=True)
try:
with open(outpath, "w") as f:
f.writelines(f"{beat}\t{number}\n" for beat, number in zip(beats, numbers))
except KeyboardInterrupt:
outpath.unlink() # avoid half-written files
def replace_state_dict_key(state_dict: dict, old: str, new: str):
"""Replaces `old` in all keys of `state_dict` with `new`."""
keys = list(state_dict.keys()) # take snapshot of the keys
for key in keys:
if old in key:
state_dict[key.replace(old, new)] = state_dict.pop(key)
return state_dict
|