From 41613f2f7b33034af10a2fca30ce0eb9fd8ddbea Mon Sep 17 00:00:00 2001 From: Brian McFee Date: Tue, 13 Dec 2016 12:33:47 -0500 Subject: [PATCH] improved efficiency and documentation for backtracking --- librosa/onset.py | 14 +++++++++----- librosa/util/utils.py | 8 ++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/librosa/onset.py b/librosa/onset.py index 20e03e61de..5088df7fa0 100644 --- a/librosa/onset.py +++ b/librosa/onset.py @@ -380,11 +380,15 @@ def onset_backtrack(events, energy): >>> plt.legend(frameon=True, framealpha=0.75) ''' - # Find points where energy is decreasing - minima = 1 + np.flatnonzero(energy[1:] <= energy[:-1]) - - # Pad on a 0, since we only do left-sided matching - minima = util.fix_frames(minima) + # Find points where energy is non-increasing + # all points: energy[i] <= energy[i-1] + # tail points: energy[i] < energy[i+1] + minima = np.flatnonzero((energy[1:-1] <= energy[:-2]) & + (energy[1:-1] < energy[2:])) + + # Pad on a 0, just in case we have onsets with no preceding minimum + # Shift by one to account for slicing in minima detection + minima = util.fix_frames(1 + minima, x_min=0) # Only match going left from the detected events return minima[util.match_events(events, minima, right=False)] diff --git a/librosa/util/utils.py b/librosa/util/utils.py index 90cb49263d..d3f2f5afb9 100644 --- a/librosa/util/utils.py +++ b/librosa/util/utils.py @@ -906,8 +906,10 @@ def match_events(events_from, events_to, left=True, right=True): raise ParameterError('Cannot match events with right=False ' 'and min(events_to) > min(events_from)') + # Pre-allocate the output array output = np.empty_like(events_from, dtype=np.int) + # Compute how many rows we can process at once within the memory block n_rows = int(MAX_MEM_BLOCK / (np.prod(output.shape[1:]) * len(events_to) * events_from.itemsize)) @@ -920,15 +922,21 @@ def match_events(events_from, events_to, left=True, right=True): event_block = events_from[bl_s:bl_t] + # distance[i, j] = |events_from - events_to[j]| distance = np.abs(np.subtract.outer(event_block, events_to)).astype(np.float) + # If we can't match to the right, squash all comparisons where + # events_to[j] > events_from[i] if not right: distance[np.less.outer(event_block, events_to)] = np.nan + # If we can't match to the left, squash all comparisons where + # events_to[j] < events_from[i] if not left: distance[np.greater.outer(event_block, events_to)] = np.nan + # Find the minimum distance point from whatever's left after squashing output[bl_s:bl_t] = np.nanargmin(distance, axis=-1) return output