import warnings warnings.filterwarnings("ignore", category=DeprecationWarning) import numpy as np import scipy import math import librosa import librosa.display import fnmatch import os from functools import partial import pyloudnorm from scipy.signal import lfilter from sklearn.metrics import mean_absolute_error, mean_squared_error from sklearn.metrics.pairwise import paired_distances import matplotlib.pyplot as plt def db(x): """Computes the decible energy of a signal""" return 20*np.log10(np.sqrt(np.mean(np.square(x)))) def melspectrogram(y, mirror_pad=False): """Compute melspectrogram feature extraction Keyword arguments: signal -- input audio as a signal in a numpy object inputnorm -- normalization of output mirror_pad -- pre and post-pend mirror signals Returns freq x time Assumes the input sampling rate is 22050Hz """ # Extract mel. fftsize = 1024 window = 1024 hop = 512 melBin = 128 sr = 22050 # mirror pad signal # first embedding centered on time 0 # last embedding centered on end of signal if mirror_pad: y = np.insert(y, 0, y[0:int(half_frame_length_sec * sr)][::-1]) y = np.insert(y, len(y), y[-int(half_frame_length_sec * sr):][::-1]) S = librosa.core.stft(y,n_fft=fftsize,hop_length=hop,win_length=window) X = np.abs(S) mel_basis = librosa.filters.mel(sr,n_fft=fftsize,n_mels=melBin) mel_S = np.dot(mel_basis,X) # value log compression mel_S = np.log10(1+10*mel_S) mel_S = mel_S.astype(np.float32) return mel_S def getFilesPath(directory, extension): n_path=[] for path, subdirs, files in os.walk(directory): for name in files: if fnmatch.fnmatch(name, extension): n_path.append(os.path.join(path,name)) n_path.sort() return n_path def getRandomTrim(x, length, pad=0, start=None): length = length+pad if x.shape[0] <= length: x_ = x while(x.shape[0] <= length): x_ = np.concatenate((x_,x_)) else: if start is None: start = np.random.randint(0, x.shape[0]-length, size=None) end = length+start if end > x.shape[0]: x_ = x[start:] x_ = np.concatenate((x_, x[:length-x.shape[0]])) else: x_ = x[start:length+start] return x_[:length] def fadeIn(x, length=128): w = scipy.signal.hann(length*2, sym=True) w1 = w[0:length] ones = np.ones(int(x.shape[0]-length)) w = np.append(w1, ones) return x*w def fadeOut(x, length=128): w = scipy.signal.hann(length*2, sym=True) w2 = w[length:length*2] ones = np.ones(int(x.shape[0]-length)) w = np.append(ones, w2) return x*w def plotTimeFreq(audio, sr, n_fft=512, hop_length=128, ylabels=None): n = len(audio) # plt.figure(figsize=(14, 4*n)) colors = list(plt.cm.viridis(np.linspace(0,1,n))) X = [] X_db = [] maxs = np.zeros((n,)) mins = np.zeros((n,)) maxs_t = np.zeros((n,)) for i, x in enumerate(audio): if x.ndim == 2 and x.shape[-1] == 2: x = librosa.core.to_mono(x.T) X_ = librosa.stft(x, n_fft=n_fft, hop_length=hop_length) X_db_ = librosa.amplitude_to_db(abs(X_)) X.append(X_) X_db.append(X_db_) maxs[i] = np.max(X_db_) mins[i] = np.min(X_db_) maxs_t[i] = np.max(np.abs(x)) vmax = np.max(maxs) vmin = np.min(mins) tmax = np.max(maxs_t) for i, x in enumerate(audio): if x.ndim == 2 and x.shape[-1] == 2: x = librosa.core.to_mono(x.T) plt.subplot(n, 2, 2*i+1) librosa.display.waveplot(x, sr=sr, color=colors[i]) if ylabels: plt.ylabel(ylabels[i]) plt.ylim(-tmax,tmax) plt.subplot(n, 2, 2*i+2) librosa.display.specshow(X_db[i], sr=sr, x_axis='time', y_axis='log', hop_length=hop_length, cmap='GnBu', vmax=vmax, vmin=vmin) # plt.colorbar(format='%+2.0f dB') def slicing(x, win_length, hop_length, center = True, windowing = False, pad = 0): # Pad the time series so that frames are centered if center: # x = np.pad(x, int((win_length-hop_length+pad) // 2), mode='constant') x = np.pad(x, ((int((win_length-hop_length+pad)//2), int((win_length+hop_length+pad)//2)),), mode='constant') # Window the time series. y_frames = librosa.util.frame(x, frame_length=win_length, hop_length=hop_length) if windowing: window = scipy.signal.hann(win_length, sym=False) else: window = 1.0 f = [] for i in range(len(y_frames.T)): f.append(y_frames.T[i]*window) return np.float32(np.asarray(f)) def overlap(x, x_len, win_length, hop_length, windowing = True, rate = 1): x = x.reshape(x.shape[0],x.shape[1]).T if windowing: window = scipy.signal.hann(win_length, sym=False) rate = rate*hop_length/win_length else: window = 1 rate = 1 n_frames = x_len / hop_length expected_signal_len = int(win_length + hop_length * (n_frames)) y = np.zeros(expected_signal_len) for i in range(int(n_frames)): sample = i * hop_length w = x[:, i] y[sample:(sample + win_length)] = y[sample:(sample + win_length)] + w*window y = y[int(win_length // 2):-int(win_length // 2)] return np.float32(y*rate) def highpassFiltering(x_list, f0, sr): b1, a1 = scipy.signal.butter(4, f0/(sr/2),'highpass') x_f = [] for x in x_list: x_f_ = scipy.signal.filtfilt(b1, a1, x).copy(order='F') x_f.append(x_f_) return x_f def lineartodB(x): return 20*np.log10(x) def dBtoLinear(x): return np.power(10,x/20) def lufs_normalize(x, sr, lufs, log=True): # measure the loudness first meter = pyloudnorm.Meter(sr) # create BS.1770 meter loudness = meter.integrated_loudness(x+1e-10) if log: print("original loudness: ", loudness," max value: ", np.max(np.abs(x))) loudness_normalized_audio = pyloudnorm.normalize.loudness(x, loudness, lufs) maxabs_amp = np.maximum(1.0, 1e-6 + np.max(np.abs(loudness_normalized_audio))) loudness_normalized_audio /= maxabs_amp loudness = meter.integrated_loudness(loudness_normalized_audio) if log: print("new loudness: ", loudness," max value: ", np.max(np.abs(loudness_normalized_audio))) return loudness_normalized_audio import soxbindings as sox def lufs_normalize_compand(x, sr, lufs): tfm = sox.Transformer() tfm.compand(attack_time = 0.001, decay_time = 0.01, soft_knee_db = 1.0, tf_points = [(-70, -70), (-0.1, -20), (0, 0)]) x = tfm.build_array(input_array=x, sample_rate_in=sr).astype(np.float32) # measure the loudness first meter = pyloudnorm.Meter(sr) # create BS.1770 meter loudness = meter.integrated_loudness(x) print("original loudness: ", loudness," max value: ", np.max(np.abs(x))) loudness_normalized_audio = pyloudnorm.normalize.loudness(x, loudness, lufs) maxabs_amp = np.maximum(1.0, 1e-6 + np.max(np.abs(loudness_normalized_audio))) loudness_normalized_audio /= maxabs_amp loudness = meter.integrated_loudness(loudness_normalized_audio) print("new loudness: ", loudness," max value: ", np.max(np.abs(loudness_normalized_audio))) return loudness_normalized_audio def getDistances(x,y): distances = {} distances['mae'] = mean_absolute_error(x, y) distances['mse'] = mean_squared_error(x, y) distances['euclidean'] = np.mean(paired_distances(x, y, metric='euclidean')) distances['manhattan'] = np.mean(paired_distances(x, y, metric='manhattan')) distances['cosine'] = np.mean(paired_distances(x, y, metric='cosine')) distances['mae'] = round(distances['mae'], 5) distances['mse'] = round(distances['mse'], 5) distances['euclidean'] = round(distances['euclidean'], 5) distances['manhattan'] = round(distances['manhattan'], 5) distances['cosine'] = round(distances['cosine'], 5) return distances def getMFCC(x, sr, mels=128, mfcc=13, mean_norm=False): melspec = librosa.feature.melspectrogram(y=x, sr=sr, S=None, n_fft=1024, hop_length=256, n_mels=mels, power=2.0) melspec_dB = librosa.power_to_db(melspec, ref=np.max) mfcc = librosa.feature.mfcc(S=melspec_dB, sr=sr, n_mfcc=mfcc) if mean_norm: mfcc -= (np.mean(mfcc, axis=0)) return mfcc def getMSE_MFCC(y_true, y_pred, sr, mels=128, mfcc=13, mean_norm=False): ratio = np.mean(np.abs(y_true))/np.mean(np.abs(y_pred)) y_pred = ratio*y_pred y_mfcc = getMFCC(y_true, sr, mels=mels, mfcc=mfcc, mean_norm=mean_norm) z_mfcc = getMFCC(y_pred, sr, mels=mels, mfcc=mfcc, mean_norm=mean_norm) return getDistances(y_mfcc[:,:], z_mfcc[:,:])