Skip to content

Commit

Permalink
improved efficiency and documentation for backtracking
Browse files Browse the repository at this point in the history
  • Loading branch information
bmcfee committed Dec 13, 2016
1 parent 4030c84 commit 41613f2
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 5 deletions.
14 changes: 9 additions & 5 deletions librosa/onset.py
Expand Up @@ -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)]
Expand Down
8 changes: 8 additions & 0 deletions librosa/util/utils.py
Expand Up @@ -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))

Expand All @@ -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
Expand Down

0 comments on commit 41613f2

Please sign in to comment.