class_docstr: Downbeat tracking with RNNs and a dynamic Bayesian network (DBN)
  approximated by a Hidden Markov Model (HMM).
  
  Parameters
  ----------
  beats_per_bar : int or list
      Number of beats per bar to be modeled. Can be either a single number
      or a list or array with bar lengths (in beats).
  min_bpm : float or list, optional
      Minimum tempo used for beat tracking [bpm]. If a list is given, each
      item corresponds to the number of beats per bar at the same position.
  max_bpm : float or list, optional
      Maximum tempo used for beat tracking [bpm]. If a list is given, each
      item corresponds to the number of beats per bar at the same position.
  num_tempi : int or list, optional
      Number of tempi to model; if set, limit the number of tempi and use a
      log spacing, otherwise a linear spacing. If a list is given, each
      item corresponds to the number of beats per bar at the same position.
  transition_lambda : float or list, optional
      Lambda for the exponential tempo change distribution (higher values
      prefer a constant tempo from one beat to the next one).  If a list is
      given, each item corresponds to the number of beats per bar at the
      same position.
  observation_lambda : int, optional
      Split one (down-)beat period into `observation_lambda` parts, the first
      representing (down-)beat states and the remaining non-beat states.
  threshold : float, optional
      Threshold the RNN (down-)beat activations before Viterbi decoding.
  correct : bool, optional
      Correct the beats (i.e. align them to the nearest peak of the
      (down-)beat activation function).
  fps : float, optional
      Frames per second.
  
  References
  ----------
  .. [1] Sebastian Böck, Florian Krebs and Gerhard Widmer,
         "Joint Beat and Downbeat Tracking with Recurrent Neural Networks"
         Proceedings of the 17th International Society for Music Information
         Retrieval Conference (ISMIR), 2016.
  
  Examples
  --------
  Create a DBNDownBeatTrackingProcessor. The returned array represents the
  positions of the beats and their position inside the bar. The position is
  given in seconds, thus the expected sampling rate is needed. The position
  inside the bar follows the natural counting and starts at 1.
  
  The number of beats per bar which should be modelled must be given, all
  other parameters (e.g. tempo range) are optional but must have the same
  length as `beats_per_bar`, i.e. must be given for each bar length.
  
  >>> proc = DBNDownBeatTrackingProcessor(beats_per_bar=[3, 4], fps=100)
  >>> proc  # doctest: +ELLIPSIS
  <madmom.features.downbeats.DBNDownBeatTrackingProcessor object at 0x...>
  
  Call this DBNDownBeatTrackingProcessor with the beat activation function
  returned by RNNDownBeatProcessor to obtain the beat positions.
  
  >>> act = RNNDownBeatProcessor()('tests/data/audio/sample.wav')
  >>> proc(act)  # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
  array([[0.09, 1. ],
         [0.45, 2. ],
         ...,
         [2.14, 3. ],
         [2.49, 4. ]])
class_docstr_tok: ["Downbeat","tracking","with","RNNs","and","a","dynamic","Bayesian","network","(","DBN",")","approximated","by","a","Hidden","Markov","Model","(","HMM",")",".","Parameters","--","--","--","--","--","beats_per_bar",":","int","or","list","Number","of","beats","per","bar","to","be","modeled",".","Can","be","either","a","single","number","or","a","list","or","array","with","bar","lengths","(","in","beats",")",".","min_bpm",":","float","or","list",",","optional","Minimum","tempo","used","for","beat","tracking","[","bpm","]",".","If","a","list","is","given",",","each","item","corresponds","to","the","number","of","beats","per","bar","at","the","same","position",".","max_bpm",":","float","or","list",",","optional","Maximum","tempo","used","for","beat","tracking","[","bpm","]",".","If","a","list","is","given",",","each","item","corresponds","to","the","number","of","beats","per","bar","at","the","same","position",".","num_tempi",":","int","or","list",",","optional","Number","of","tempi","to","model",";","if","set",",","limit","the","number","of","tempi","and","use","a","log","spacing",",","otherwise","a","linear","spacing",".","If","a","list","is","given",",","each","item","corresponds","to","the","number","of","beats","per","bar","at","the","same","position",".","transition_lambda",":","float","or","list",",","optional","Lambda","for","the","exponential","tempo","change","distribution","(","higher","values","prefer","a","constant","tempo","from","one","beat","to","the","next","one",")",".","If","a","list","is","given",",","each","item","corresponds","to","the","number","of","beats","per","bar","at","the","same","position",".","observation_lambda",":","int",",","optional","Split","one","(","down-",")","beat","period","into","`","observation_lambda","`","parts",",","the","first","representing","(","down-",")","beat","states","and","the","remaining","non-beat","states",".","threshold",":","float",",","optional","Threshold","the","RNN","(","down-",")","beat","activations","before","Viterbi","decoding",".","correct",":","bool",",","optional","Correct","the","beats","(","i.e",".","align","them","to","the","nearest","peak","of","the","(","down-",")","beat","activation","function",")",".","fps",":","float",",","optional","Frames","per","second",".","References","--","--","--","--","--","..","[","1","]","Sebastian","B\u00f6ck",",","Florian","Krebs","and","Gerhard","Widmer",",","``","Joint","Beat","and","Downbeat","Tracking","with","Recurrent","Neural","Networks","''","Proceedings","of","the","17th","International","Society","for","Music","Information","Retrieval","Conference","(","ISMIR",")",",","2016",".","Examples","--","--","--","--","Create","a","DBNDownBeatTrackingProcessor",".","The","returned","array","represents","the","positions","of","the","beats","and","their","position","inside","the","bar",".","The","position","is","given","in","seconds",",","thus","the","expected","sampling","rate","is","needed",".","The","position","inside","the","bar","follows","the","natural","counting","and","starts","at","1",".","The","number","of","beats","per","bar","which","should","be","modelled","must","be","given",",","all","other","parameters","(","e.g",".","tempo","range",")","are","optional","but","must","have","the","same","length","as","`","beats_per_bar","`",",","i.e",".","must","be","given","for","each","bar","length",".",">",">",">","proc","=","DBNDownBeatTrackingProcessor","(","beats_per_bar=","[","3",",","4","]",",","fps=100",")",">",">",">","proc","#","doctest",":","+ELLIPSIS","<","madmom.features.downbeats.DBNDownBeatTrackingProcessor","object","at","0x","...",">","Call","this","DBNDownBeatTrackingProcessor","with","the","beat","activation","function","returned","by","RNNDownBeatProcessor","to","obtain","the","beat","positions",".",">",">",">","act","=","RNNDownBeatProcessor","(",")","(","'tests\/data\/audio\/sample.wav","'",")",">",">",">","proc","(","act",")","#","doctest",":","+ELLIPSIS","+NORMALIZE_WHITESPACE","array","(","[","[","0.09",",","1",".","]",",","[","0.45",",","2",".","]",",","...",",","[","2.14",",","3",".","]",",","[","2.49",",","4",".","]","]",")"]
docstr: Detect the (down-)beats in the given activation function.
  
  Parameters
  ----------
  activations : numpy array, shape (num_frames, 2)
      Activation function with probabilities corresponding to beats
      and downbeats given in the first and second column, respectively.
  
  Returns
  -------
  beats : numpy array, shape (num_beats, 2)
      Detected (down-)beat positions [seconds] and beat numbers.
code: def process(self, activations, **kwargs):
      """
      Detect the (down-)beats in the given activation function.
  
      Parameters
      ----------
      activations : numpy array, shape (num_frames, 2)
          Activation function with probabilities corresponding to beats
          and downbeats given in the first and second column, respectively.
  
      Returns
      -------
      beats : numpy array, shape (num_beats, 2)
          Detected (down-)beat positions [seconds] and beat numbers.
  
      """
      # pylint: disable=arguments-differ
      import itertools as it
  
      # use only the activations > threshold (init offset to be added later)
      first = 0
      if self.threshold:
          activations, first = threshold_activations(
              activations, self.threshold
          )
      # return no beats if no activations given / remain after thresholding
      if not activations.any():
          return np.empty((0, 2))
      # (parallel) decoding of the activations with HMM
      results = list(
          self.map(_process_dbn, zip(self.hmms, it.repeat(activations)))
      )
      # choose the best HMM (highest log probability)
      best = np.argmax(list(r[1] for r in results))
      # the best path through the state space
      path, _ = results[best]
      # the state space and observation model of the best HMM
      st = self.hmms[best].transition_model.state_space
      om = self.hmms[best].observation_model
      # the positions inside the pattern (0..num_beats)
      positions = st.state_positions[path]
      # corresponding beats (add 1 for natural counting)
      beat_numbers = positions.astype(int) + 1
      if self.correct:
          beats = np.empty(0, dtype=int)
          # for each detection determine the "beat range", i.e. states where
          # the pointers of the observation model are >= 1
          beat_range = om.pointers[path] >= 1
          # if there aren't any in the beat range, there are no beats
          if not beat_range.any():
              return np.empty((0, 2))
          # get all change points between True and False (cast to int before)
          idx = np.nonzero(np.diff(beat_range.astype(int)))[0] + 1
          # if the first frame is in the beat range, add a change at frame 0
          if beat_range[0]:
              idx = np.r_[0, idx]
          # if the last frame is in the beat range, append the length of the
          # array
          if beat_range[-1]:
              idx = np.r_[idx, beat_range.size]
          # iterate over all regions
          if idx.any():
              for left, right in idx.reshape((-1, 2)):
                  # pick the frame with the highest activations value
                  # Note: we look for both beats and down-beat activations;
                  #       since np.argmax works on the flattened array, we
                  #       need to divide by 2
                  peak = np.argmax(activations[left:right]) // 2 + left
                  beats = np.hstack((beats, peak))
      else:
          # transitions are the points where the beat numbers change
          # FIXME: we might miss the first or last beat!
          #        we could calculate the interval towards the beginning/end
          #        to decide whether to include these points
          beats = np.nonzero(np.diff(beat_numbers))[0] + 1
      # return the beat positions (converted to seconds) and beat numbers
      return np.vstack(
          ((beats + first) / float(self.fps), beat_numbers[beats])
      ).T
  
imports: from __future__ import absolute_import, division, print_function
  import sys
  import warnings
  import numpy
  from .beats import threshold_activations
  from .beats_hmm import BarStateSpace, BarTransitionModel, GMMPatternTrackingObservationModel, MultiPatternStateSpace, MultiPatternTransitionModel, RNNBeatTrackingObservationModel, RNNDownBeatTrackingObservationModel
  from ..ml.hmm import HiddenMarkovModel
  from ..processors import ParallelProcessor, Processor, SequentialProcessor
  from ..utils import string_types
label_desc: Use image node_id 2 for calling the DBNDownBeatTrackingProcessor obj's underlying member method code with example usage: obj.process(activations) and returns: np, np, np