def tempo(y=None, sr=22050, onset_envelope=None, hop_length=512, start_bpm=120, std_bpm=1.0, ac_size=8.0, max_tempo=320.0, aggregate=np.mean): if start_bpm <= 0: raise ParameterError('start_bpm must be strictly positive') win_length = np.asscalar(core.time_to_frames(ac_size, sr=sr, hop_length=hop_length)) tg = tempogram(y=y, sr=sr, onset_envelope=onset_envelope, hop_length=hop_length, win_length=win_length) # Eventually, we want this to work for time-varying tempo if aggregate is not None: tg = aggregate(tg, axis=1, keepdims=True) # Get the BPM values for each bin, skipping the 0-lag bin bpms = core.tempo_frequencies(tg.shape[0], hop_length=hop_length, sr=sr) # Weight the autocorrelation by a log-normal distribution prior = np.exp(-0.5 * ((np.log2(bpms) - np.log2(start_bpm)) / std_bpm)**2) prior2 = np.argsort(prior, axis=0) prior2_idx = prior2[-2] # print(prior2_idx) # print('prior_2_idx', prior2_idx) # Kill everything above the max tempo if max_tempo is not None: max_idx = np.argmax(bpms < max_tempo) prior[:max_idx] = 0 # Really, instead of multiplying by the prior, we should set up a # probabilistic model for tempo and add log-probabilities. # This would give us a chance to recover from null signals and # rely on the prior. # it would also make time aggregation much more natural # Get the maximum, weighted by the prior period = tg * prior[:, np.newaxis] best_period = np.argmax(period, axis=0) best_2 = np.argsort(period, axis=0) prior2_idx = best_2[-2] #print(prior2_idx) #print(best_period) second_period = prior2_idx tempi = bpms[best_period] tempi2 = bpms[second_period] #print(type(tempi), type(tempi2)) # Wherever the best tempo is index 0, return start_bpm tempi[best_period == 0] = start_bpm tempi2[second_period == 0] = start_bpm return (tempi2.astype(float)[0].item(), tempi.astype(float)[0].item())
def __coord_tempo(n, sr=22050, hop_length=512, **_kwargs): """Tempo coordinates""" basis = core.tempo_frequencies(n + 2, sr=sr, hop_length=hop_length)[1:] edges = np.arange(1, n + 2) return basis * (edges + 0.5) / edges
def __coord_tempo(n, sr=22050, hop_length=512, **_kwargs): '''Tempo coordinates''' return core.tempo_frequencies(n + 1, sr=sr, hop_length=hop_length)
def tempo(tg, sr=22050, onset_envelope=None, hop_length=512, start_bpm=120, std_bpm=1.0, ac_size=8.0, max_tempo=320.0, aggregate=np.mean): """Estimate the tempo (beats per minute) (from librosa.beat.tempo) Parameters ---------- y : np.ndarray [shape=(n,)] or None audio time series sr : number > 0 [scalar] sampling rate of the time series onset_envelope : np.ndarray [shape=(n,)] pre-computed onset strength envelope hop_length : int > 0 [scalar] hop length of the time series start_bpm : float [scalar] initial guess of the BPM std_bpm : float > 0 [scalar] standard deviation of tempo distribution ac_size : float > 0 [scalar] length (in seconds) of the auto-correlation window max_tempo : float > 0 [scalar, optional] If provided, only estimate tempo below this threshold aggregate : callable [optional] Aggregation function for estimating global tempo. If `None`, then tempo is estimated independently for each frame. Returns ------- tempo : np.ndarray [scalar] estimated tempo (beats per minute) """ if start_bpm <= 0: raise ParameterError('start_bpm must be strictly positive') # Eventually, we want this to work for time-varying tempo if aggregate is not None: tg = aggregate(tg, axis=1, keepdims=True) # Get the BPM values for each bin, skipping the 0-lag bin bpms = tempo_frequencies(tg.shape[0], hop_length=hop_length, sr=sr) # Weight the autocorrelation by a log-normal distribution prior = np.exp(-0.5 * ((np.log2(bpms) - np.log2(start_bpm)) / std_bpm)**2) # Kill everything above the max tempo if max_tempo is not None: max_idx = np.argmax(bpms < max_tempo) prior[:max_idx] = 0 # Really, instead of multiplying by the prior, we should set up a # probabilistic model for tempo and add log-probabilities. # This would give us a chance to recover from null signals and # rely on the prior. # it would also make time aggregation much more natural # Get the maximum, weighted by the prior best_period = np.argmax(tg * prior[:, np.newaxis], axis=0) tempi = bpms[best_period] # Wherever the best tempo is index 0, return start_bpm tempi[best_period == 0] = start_bpm return tempi