Spaces:
Runtime error
Runtime error
Add app.py for the user audio input and mel-spec output
Browse files
app.py
CHANGED
|
@@ -1,7 +1,168 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import gradio as gr
|
|
|
|
| 2 |
|
| 3 |
-
|
| 4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
-
demo = gr.Interface(fn=greet, inputs="text", outputs="text")
|
| 7 |
demo.launch()
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import crepe.crepe as crepe
|
| 3 |
+
import matplotlib.pyplot as plt
|
| 4 |
+
import librosa
|
| 5 |
+
import librosa.display
|
| 6 |
+
import numpy as np
|
| 7 |
+
import torch
|
| 8 |
+
import torchaudio
|
| 9 |
+
import pretty_midi
|
| 10 |
import gradio as gr
|
| 11 |
+
from scipy.io import wavfile
|
| 12 |
|
| 13 |
+
# Helper functions
|
| 14 |
+
def dynamic_range_compression_torch(x, C=1, clip_val=1e-5):
|
| 15 |
+
return torch.log(torch.clamp(x, min=clip_val) * C)
|
| 16 |
+
|
| 17 |
+
def dynamic_range_decompression_torch(x, C=1):
|
| 18 |
+
return torch.exp(x) / C
|
| 19 |
+
|
| 20 |
+
def spectral_normalize_torch(magnitudes):
|
| 21 |
+
output = dynamic_range_compression_torch(magnitudes)
|
| 22 |
+
return output
|
| 23 |
+
|
| 24 |
+
def spectral_de_normalize_torch(magnitudes):
|
| 25 |
+
output = dynamic_range_decompression_torch(magnitudes)
|
| 26 |
+
return output
|
| 27 |
+
|
| 28 |
+
def get_melspec(y: np.ndarray, sr: int = 16000, n_mels: int = 64,
|
| 29 |
+
window_length: int = 1024, hop_length: int = 160, fmax: int = 8000, fmin: int = 0) -> torch.tensor:
|
| 30 |
+
y = np.pad(y, (int((window_length - hop_length) / 2), int((window_length - hop_length) / 2)), mode="reflect")
|
| 31 |
+
S = librosa.feature.melspectrogram(y=y, sr=sr, n_mels=n_mels,
|
| 32 |
+
n_fft=window_length,
|
| 33 |
+
hop_length=hop_length,
|
| 34 |
+
win_length=window_length, window='hann',
|
| 35 |
+
fmin=fmin, fmax=fmax,
|
| 36 |
+
center=False, pad_mode="reflect")
|
| 37 |
+
S_norm = spectral_normalize_torch(torch.tensor(S))
|
| 38 |
+
return S_norm
|
| 39 |
+
|
| 40 |
+
def get_f0_melspec(frequency: np.ndarray, confidence: np.ndarray = None,
|
| 41 |
+
n_mels: int = 64, fmax: int = 8000, fmin: int = 0) -> torch.tensor:
|
| 42 |
+
n_frames = len(frequency)
|
| 43 |
+
S = np.zeros((n_mels, n_frames))
|
| 44 |
+
mel_bin_frequencies = librosa.core.mel_frequencies(n_mels=n_mels + 1, fmin=fmin, fmax=fmax, htk=False)
|
| 45 |
+
mel_band_indices = [
|
| 46 |
+
np.clip(np.searchsorted(mel_bin_frequencies, mel_f, side='right') - 1, 0, n_mels - 1) if mel_f is not None else None
|
| 47 |
+
for mel_f in frequency
|
| 48 |
+
]
|
| 49 |
+
for t, mel_band in enumerate(mel_band_indices):
|
| 50 |
+
if mel_band is None:
|
| 51 |
+
continue
|
| 52 |
+
if confidence is not None:
|
| 53 |
+
S[mel_band, t] = confidence[t]
|
| 54 |
+
else:
|
| 55 |
+
S[mel_band, t] = 1.0
|
| 56 |
+
S_norm = spectral_normalize_torch(torch.tensor(S))
|
| 57 |
+
return S_norm
|
| 58 |
+
|
| 59 |
+
def midi_to_frequency(midi_file, sr=16000, duration=10.24, hop_length=160):
|
| 60 |
+
midi_data = pretty_midi.PrettyMIDI(midi_file)
|
| 61 |
+
max_len = int(duration * sr // hop_length)
|
| 62 |
+
frequency = np.full(max_len, None)
|
| 63 |
+
|
| 64 |
+
for instrument in midi_data.instruments:
|
| 65 |
+
if instrument.is_drum:
|
| 66 |
+
continue
|
| 67 |
+
for note in instrument.notes:
|
| 68 |
+
start_frame = int(note.start * sr // hop_length)
|
| 69 |
+
end_frame = int(note.end * sr // hop_length)
|
| 70 |
+
frequency[start_frame:end_frame] = note.pitch
|
| 71 |
+
|
| 72 |
+
frequency = np.array([pretty_midi.note_number_to_hz(note) if note is not None else None for note in frequency])
|
| 73 |
+
return frequency
|
| 74 |
+
|
| 75 |
+
def get_item(filepath: str, config: dict, input_type: str = 'midi'):
|
| 76 |
+
max_len = int(config["audio_length"] * config["sr"])
|
| 77 |
+
|
| 78 |
+
if input_type == 'audio':
|
| 79 |
+
if filepath.endswith('.flac'):
|
| 80 |
+
audio, sr = librosa.load(filepath)
|
| 81 |
+
elif filepath.endswith('.wav'):
|
| 82 |
+
sr, audio = wavfile.read(filepath)
|
| 83 |
+
else:
|
| 84 |
+
raise ValueError('Unsupported file format')
|
| 85 |
+
|
| 86 |
+
if audio.ndim > 1:
|
| 87 |
+
audio = np.mean(audio, axis=1)
|
| 88 |
+
|
| 89 |
+
if sr != config["sr"]:
|
| 90 |
+
audio = torchaudio.functional.resample(torch.Tensor(audio), sr, config['sr']).numpy()
|
| 91 |
+
sr = config["sr"]
|
| 92 |
+
hop_length = config["hop_length"]
|
| 93 |
+
|
| 94 |
+
if len(audio) > max_len:
|
| 95 |
+
audio = audio[:max_len]
|
| 96 |
+
elif len(audio) < max_len:
|
| 97 |
+
pad_length = max_len - len(audio)
|
| 98 |
+
audio = np.pad(audio, (0, pad_length), mode="constant")
|
| 99 |
+
|
| 100 |
+
S_waveform = torch.tensor(audio).unsqueeze(0)
|
| 101 |
+
S = get_melspec(audio, sr=config['sr'], n_mels=config['n_mels'], window_length=config['window_length'],
|
| 102 |
+
hop_length=config['hop_length'], fmax=config['fmax'], fmin=config['fmin'])
|
| 103 |
+
|
| 104 |
+
time, frequency, confidence, activation = crepe.predict(audio, sr, viterbi=True)
|
| 105 |
+
if not config['use_confidence']:
|
| 106 |
+
frequency = np.array([f if c >= config['confidence_threshold'] else None for f, c in zip(frequency, confidence)])
|
| 107 |
+
|
| 108 |
+
if len(frequency) < S.shape[1]:
|
| 109 |
+
if config['use_confidence']:
|
| 110 |
+
assert len(confidence) == len(frequency)
|
| 111 |
+
confidence = np.pad(confidence, (0, S.shape[1] - len(confidence)), mode="constant", constant_values=None)
|
| 112 |
+
frequency = np.pad(frequency, (0, S.shape[1] - len(frequency)), mode="constant", constant_values=None)
|
| 113 |
+
|
| 114 |
+
elif len(frequency) > S.shape[1]:
|
| 115 |
+
frequency = frequency[:S.shape[1]]
|
| 116 |
+
if config['use_confidence']:
|
| 117 |
+
confidence = confidence[:S.shape[1]]
|
| 118 |
+
|
| 119 |
+
elif input_type == 'midi':
|
| 120 |
+
confidence = 1.0
|
| 121 |
+
frequency = midi_to_frequency(filepath, sr=config["sr"], duration=config["audio_length"], hop_length=config["hop_length"])
|
| 122 |
+
|
| 123 |
+
S_f0 = get_f0_melspec(frequency, confidence=confidence if config['use_confidence'] else None,
|
| 124 |
+
n_mels=config['n_mels'], fmax=config['fmax'], fmin=config['fmin'])
|
| 125 |
+
|
| 126 |
+
item_dict = {
|
| 127 |
+
'f0_condition': S_f0
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
return item_dict
|
| 131 |
+
|
| 132 |
+
def spec_show(S, sr):
|
| 133 |
+
fig, ax = plt.subplots(figsize=(6, 2))
|
| 134 |
+
img = librosa.display.specshow(S, sr=sr, ax=ax)
|
| 135 |
+
buf = BytesIO()
|
| 136 |
+
fig.savefig(buf, format='png')
|
| 137 |
+
buf.seek(0)
|
| 138 |
+
plt.close(fig)
|
| 139 |
+
return buf
|
| 140 |
+
|
| 141 |
+
config_AudioLDM = {
|
| 142 |
+
"sr": 16000,
|
| 143 |
+
"audio_length": 10.24,
|
| 144 |
+
"n_mels": 64,
|
| 145 |
+
"window_length": 1024,
|
| 146 |
+
"hop_length": 160,
|
| 147 |
+
"fmax": 8000,
|
| 148 |
+
"fmin": 0,
|
| 149 |
+
"use_confidence": False,
|
| 150 |
+
"confidence_threshold": 0.8,
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
cfg = config_AudioLDM
|
| 154 |
+
|
| 155 |
+
def process_file(file):
|
| 156 |
+
if file.name.endswith('.wav') or file.name.endswith('.flac'):
|
| 157 |
+
item_dict = get_item(file.name, config=cfg, input_type='audio')
|
| 158 |
+
elif file.name.endswith('.mid') or file.name.endswith('.midi'):
|
| 159 |
+
item_dict = get_item(file.name, config=cfg, input_type='midi')
|
| 160 |
+
else:
|
| 161 |
+
return "Unsupported file format"
|
| 162 |
+
|
| 163 |
+
f0_condition = item_dict['f0_condition']
|
| 164 |
+
return spec_show(f0_condition.numpy(), cfg["sr"])
|
| 165 |
+
|
| 166 |
+
demo = gr.Interface(fn=process_file, inputs=gr.inputs.File(), outputs="image", title="Pitch ControlNet")
|
| 167 |
|
|
|
|
| 168 |
demo.launch()
|