diff --git a/madmom/features/tempo.py b/madmom/features/tempo.py index 69a625eeb..bff32d88b 100755 --- a/madmom/features/tempo.py +++ b/madmom/features/tempo.py @@ -251,6 +251,8 @@ class BaseTempoEstimationProcessor(OnlineProcessor): Smooth the activation function over `act_smooth` seconds. hist_smooth : int Smooth the tempo histogram over `hist_smooth` bins. + hist_buffer : float + Aggregate the tempo histogram over `hist_buffer` seconds. fps : float, optional Frames per second. @@ -266,8 +268,8 @@ class BaseTempoEstimationProcessor(OnlineProcessor): """ - def __init__(self, min_bpm, max_bpm, act_smooth, hist_smooth, fps=None, - online=False, **kwargs): + def __init__(self, min_bpm, max_bpm, act_smooth, hist_smooth, + hist_buffer=None, fps=None, online=False, **kwargs): # pylint: disable=unused-argument super(BaseTempoEstimationProcessor, self).__init__(online=online) # save variables @@ -275,9 +277,12 @@ def __init__(self, min_bpm, max_bpm, act_smooth, hist_smooth, fps=None, self.max_bpm = max_bpm self.act_smooth = act_smooth self.hist_smooth = hist_smooth + self.hist_buffer = hist_buffer self.fps = fps if self.online: self.visualize = kwargs.get('verbose', False) + self._hist_buffer = BufferProcessor((int(hist_buffer * self.fps), + len(self.intervals))) @property def min_interval(self): @@ -294,6 +299,10 @@ def intervals(self): """Beat intervals [frames].""" return np.arange(self.min_interval, self.max_interval + 1) + def reset(self): + """Reset the tempo estimator.""" + self._hist_buffer.reset() + def process_offline(self, activations, **kwargs): """ Detect the tempi from the (beat) activations. @@ -426,7 +435,7 @@ def dominant_interval(self, histogram): @staticmethod def add_arguments(parser, min_bpm=None, max_bpm=None, act_smooth=None, - hist_smooth=None): + hist_smooth=None, hist_buffer=None): """ Add tempo estimation related arguments to an existing parser. @@ -442,6 +451,8 @@ def add_arguments(parser, min_bpm=None, max_bpm=None, act_smooth=None, Smooth the activation function over `act_smooth` seconds. hist_smooth : int, optional Smooth the tempo histogram over `hist_smooth` bins. + hist_buffer : float, optional + Aggregate the tempo histogram over `hist_buffer` seconds. Returns ------- @@ -473,6 +484,11 @@ def add_arguments(parser, min_bpm=None, max_bpm=None, act_smooth=None, default=hist_smooth, help='smooth the tempo histogram over N bins ' '[default=%(default)d]') + if hist_buffer is not None: + g.add_argument('--hist_buffer', action='store', type=float, + default=hist_smooth, + help='aggregate the tempo histogram over N seconds ' + '[default=%(default).2f]') # return the argument group so it can be modified if needed return g @@ -492,8 +508,8 @@ class TempoEstimationProcessor(BaseTempoEstimationProcessor): METHOD = 'comb' MIN_BPM = 40. MAX_BPM = 250. - HIST_SMOOTH = 9 ACT_SMOOTH = 0.14 + HIST_SMOOTH = 9 ALPHA = 0.79 def __init__(self, method=METHOD, min_bpm=MIN_BPM, max_bpm=MAX_BPM, @@ -610,15 +626,14 @@ class CombFilterTempoEstimationProcessor(BaseTempoEstimationProcessor): Minimum tempo to detect [bpm]. max_bpm : float, optional Maximum tempo to detect [bpm]. + alpha : float, optional + Scaling factor for the comb filter. act_smooth : float, optional Smooth the activation function over `act_smooth` seconds. hist_smooth : int, optional Smooth the tempo histogram over `hist_smooth` bins. - alpha : float, optional - Scaling factor for the comb filter. - buffer_size : float, optional - Use a buffer of this size to sum the max. bins in online mode - [seconds]. + hist_buffer : float + Aggregate the tempo histogram over `hist_buffer` seconds. fps : float, optional Frames per second. online : bool, optional @@ -650,30 +665,29 @@ class CombFilterTempoEstimationProcessor(BaseTempoEstimationProcessor): # default values for tempo estimation MIN_BPM = 40. MAX_BPM = 250. - HIST_SMOOTH = 9 - ACT_SMOOTH = 0.14 ALPHA = 0.79 - BUFFER_SIZE = 10. + ACT_SMOOTH = 0.14 + HIST_SMOOTH = 9 + HIST_BUFFER = 10. - def __init__(self, min_bpm=MIN_BPM, max_bpm=MAX_BPM, act_smooth=ACT_SMOOTH, - hist_smooth=HIST_SMOOTH, alpha=ALPHA, buffer_size=BUFFER_SIZE, - fps=None, online=False, **kwargs): + def __init__(self, min_bpm=MIN_BPM, max_bpm=MAX_BPM, alpha=ALPHA, + act_smooth=ACT_SMOOTH, hist_smooth=HIST_SMOOTH, + hist_buffer=HIST_BUFFER, fps=None, online=False, **kwargs): # pylint: disable=unused-argument super(CombFilterTempoEstimationProcessor, self).__init__( min_bpm=min_bpm, max_bpm=max_bpm, act_smooth=act_smooth, - hist_smooth=hist_smooth, fps=fps, online=online, **kwargs) + hist_smooth=hist_smooth, hist_buffer=hist_buffer, fps=fps, + online=online, **kwargs) # save additional variables self.alpha = alpha if self.online: self._comb_buffer = BufferProcessor((np.max(self.intervals) + 1, len(self.intervals))) - self._hist_buffer = BufferProcessor((int(buffer_size * self.fps), - len(self.intervals))) def reset(self): """Reset the CombFilterTempoEstimationProcessor.""" + super(CombFilterTempoEstimationProcessor, self).reset() self._comb_buffer.reset() - self._hist_buffer.reset() def interval_histogram(self, activations): """ @@ -790,11 +804,8 @@ class ACFTempoEstimationProcessor(BaseTempoEstimationProcessor): Smooth the activation function over `act_smooth` seconds. hist_smooth : int, optional Smooth the tempo histogram over `hist_smooth` bins. - alpha : float, optional - Scaling factor for the comb filter. - buffer_size : float, optional - Use a buffer of this size for the activations to calculate the - auto-correlation function [seconds]. + hist_buffer : float + Aggregate the tempo histogram over `hist_buffer` seconds. fps : float, optional Frames per second. online : bool, optional @@ -827,26 +838,25 @@ class ACFTempoEstimationProcessor(BaseTempoEstimationProcessor): # default values for tempo estimation MIN_BPM = 40. MAX_BPM = 250. - HIST_SMOOTH = 9 ACT_SMOOTH = 0.14 - BUFFER_SIZE = 10. + HIST_SMOOTH = 9 + HIST_BUFFER = 10. def __init__(self, min_bpm=MIN_BPM, max_bpm=MAX_BPM, act_smooth=ACT_SMOOTH, - hist_smooth=HIST_SMOOTH, buffer_size=BUFFER_SIZE, fps=None, + hist_smooth=HIST_SMOOTH, hist_buffer=HIST_BUFFER, fps=None, online=False, **kwargs): # pylint: disable=unused-argument super(ACFTempoEstimationProcessor, self).__init__( min_bpm=min_bpm, max_bpm=max_bpm, act_smooth=act_smooth, - hist_smooth=hist_smooth, fps=fps, online=online, **kwargs) + hist_smooth=hist_smooth, hist_buffer=hist_buffer, fps=fps, + online=online, **kwargs) if self.online: self._act_buffer = BufferProcessor((np.max(self.intervals) + 1, 1)) - self._hist_buffer = BufferProcessor((int(buffer_size * self.fps), - len(self.intervals))) def reset(self): """Reset the ACFTempoEstimationProcessor.""" + super(ACFTempoEstimationProcessor, self).reset() self._act_buffer.reset() - self._hist_buffer.reset() def interval_histogram(self, activations): """ @@ -922,6 +932,8 @@ class DBNTempoEstimationProcessor(BaseTempoEstimationProcessor): Smooth the activation function over `act_smooth` seconds. hist_smooth : int, optional Smooth the tempo histogram over `hist_smooth` bins. + hist_buffer : float + Aggregate the tempo histogram over `hist_buffer` seconds. fps : float, optional Frames per second. online : bool, optional @@ -948,30 +960,28 @@ class DBNTempoEstimationProcessor(BaseTempoEstimationProcessor): # default values for tempo estimation MIN_BPM = 40. MAX_BPM = 250. - HIST_SMOOTH = 9 ACT_SMOOTH = 0. - BUFFER_SIZE = 10. + HIST_SMOOTH = 9 + HIST_BUFFER = 10. def __init__(self, min_bpm=MIN_BPM, max_bpm=MAX_BPM, act_smooth=ACT_SMOOTH, - hist_smooth=HIST_SMOOTH, buffer_size=BUFFER_SIZE, fps=None, + hist_smooth=HIST_SMOOTH, hist_buffer=HIST_BUFFER, fps=None, online=False, **kwargs): # pylint: disable=unused-argument super(DBNTempoEstimationProcessor, self).__init__( min_bpm=min_bpm, max_bpm=max_bpm, act_smooth=act_smooth, - hist_smooth=hist_smooth, fps=fps, online=online, **kwargs) + hist_smooth=hist_smooth, hist_buffer=hist_buffer, fps=fps, + online=online, **kwargs) # save additional variables from .beats import DBNBeatTrackingProcessor self.dbn = DBNBeatTrackingProcessor(min_bpm=self.min_bpm, max_bpm=self.max_bpm, fps=self.fps, **kwargs) - if self.online: - self._hist_buffer = BufferProcessor((int(buffer_size * self.fps), - len(self.intervals))) def reset(self): """Reset the DBNTempoEstimationProcessor.""" + super(DBNTempoEstimationProcessor, self).reset() self.dbn.hmm.reset() - self._hist_buffer.reset() def interval_histogram(self, activations): """