def match_notes(
        ref_intervals, ref_pitches, ref_velocities, est_intervals, est_pitches,
        est_velocities, onset_tolerance=0.05, pitch_tolerance=50.0,
        offset_ratio=0.2, offset_min_tolerance=0.05, strict=False,
        velocity_tolerance=0.1):
    """Match notes, taking note velocity into consideration.

    This function first calls :func:`mir_eval.transcription.match_notes` to
    match notes according to the supplied intervals, pitches, onset, offset,
    and pitch tolerances. The velocities of the matched notes are then used to
    estimate a slope and intercept which can rescale the estimated velocities
    so that they are as close as possible (in L2 sense) to their matched
    reference velocities. Velocities are then normalized to the range [0, 1]. A
    estimated note is then further only considered correct if its velocity is
    within ``velocity_tolerance`` of its matched (according to pitch and
    timing) reference note.

    Parameters
    ----------
    ref_intervals : np.ndarray, shape=(n,2)
        Array of reference notes time intervals (onset and offset times)
    ref_pitches : np.ndarray, shape=(n,)
        Array of reference pitch values in Hertz
    ref_velocities : np.ndarray, shape=(n,)
        Array of MIDI velocities (i.e. between 0 and 127) of reference notes
    est_intervals : np.ndarray, shape=(m,2)
        Array of estimated notes time intervals (onset and offset times)
    est_pitches : np.ndarray, shape=(m,)
        Array of estimated pitch values in Hertz
    est_velocities : np.ndarray, shape=(m,)
        Array of MIDI velocities (i.e. between 0 and 127) of estimated notes
    onset_tolerance : float > 0
        The tolerance for an estimated note's onset deviating from the
        reference note's onset, in seconds. Default is 0.05 (50 ms).
    pitch_tolerance : float > 0
        The tolerance for an estimated note's pitch deviating from the
        reference note's pitch, in cents. Default is 50.0 (50 cents).
    offset_ratio : float > 0 or None
        The ratio of the reference note's duration used to define the
        offset_tolerance. Default is 0.2 (20%), meaning the
        ``offset_tolerance`` will equal the ``ref_duration * 0.2``, or 0.05 (50
        ms), whichever is greater. If ``offset_ratio`` is set to ``None``,
        offsets are ignored in the matching.
    offset_min_tolerance : float > 0
        The minimum tolerance for offset matching. See offset_ratio description
        for an explanation of how the offset tolerance is determined. Note:
        this parameter only influences the results if ``offset_ratio`` is not
        ``None``.
    strict : bool
        If ``strict=False`` (the default), threshold checks for onset, offset,
        and pitch matching are performed using ``<=`` (less than or equal). If
        ``strict=True``, the threshold checks are performed using ``<`` (less
        than).
    velocity_tolerance : float > 0
        Estimated notes are considered correct if, after rescaling and
        normalization to [0, 1], they are within ``velocity_tolerance`` of a
        matched reference note.

    Returns
    -------
    matching : list of tuples
        A list of matched reference and estimated notes.
        ``matching[i] == (i, j)`` where reference note ``i`` matches estimated
        note ``j``.
    """
    # Compute note matching as usual using standard transcription function
    matching = transcription.match_notes(
        ref_intervals, ref_pitches, est_intervals, est_pitches,
        onset_tolerance, pitch_tolerance, offset_ratio, offset_min_tolerance,
        strict)

    # Rescale reference velocities to the range [0, 1]
    min_velocity, max_velocity = np.min(ref_velocities), np.max(ref_velocities)
    # Make the smallest possible range 1 to avoid divide by zero
    velocity_range = max(1, max_velocity - min_velocity)
    ref_velocities = (ref_velocities - min_velocity)/float(velocity_range)

    # Convert matching list-of-tuples to array for fancy indexing
    matching = np.array(matching)
    # When there is no matching, return an empty list
    if matching.size == 0:
        return []
    # Grab velocities for matched notes
    ref_matched_velocities = ref_velocities[matching[:, 0]]
    est_matched_velocities = est_velocities[matching[:, 1]]
    # Find slope and intercept of line which produces best least-squares fit
    # between matched est and ref velocities
    slope, intercept = np.linalg.lstsq(
        np.vstack([est_matched_velocities,
                   np.ones(len(est_matched_velocities))]).T,
        ref_matched_velocities)[0]
    # Re-scale est velocities to match ref
    est_matched_velocities = slope*est_matched_velocities + intercept
    # Compute the absolute error of (rescaled) estimated velocities vs.
    # normalized reference velocities. Error will be in [0, 1]
    velocity_diff = np.abs(est_matched_velocities - ref_matched_velocities)
    # Check whether each error is within the provided tolerance
    velocity_within_tolerance = (velocity_diff < velocity_tolerance)
    # Only keep matches whose velocity was within the provided tolerance
    matching = matching[velocity_within_tolerance]
    # Convert back to list-of-tuple format
    matching = [tuple(_) for _ in matching]

    return matching
Match notes, taking note velocity into consideration.

    This function first calls :func:`mir_eval.transcription.match_notes` to
    match notes according to the supplied intervals, pitches, onset, offset,
    and pitch tolerances. The velocities of the matched notes are then used to
    estimate a slope and intercept which can rescale the estimated velocities
    so that they are as close as possible (in L2 sense) to their matched
    reference velocities. Velocities are then normalized to the range [0, 1]. A
    estimated note is then further only considered correct if its velocity is
    within ``velocity_tolerance`` of its matched (according to pitch and
    timing) reference note.

    Parameters
    ----------
    ref_intervals : np.ndarray, shape=(n,2)
        Array of reference notes time intervals (onset and offset times)
    ref_pitches : np.ndarray, shape=(n,)
        Array of reference pitch values in Hertz
    ref_velocities : np.ndarray, shape=(n,)
        Array of MIDI velocities (i.e. between 0 and 127) of reference notes
    est_intervals : np.ndarray, shape=(m,2)
        Array of estimated notes time intervals (onset and offset times)
    est_pitches : np.ndarray, shape=(m,)
        Array of estimated pitch values in Hertz
    est_velocities : np.ndarray, shape=(m,)
        Array of MIDI velocities (i.e. between 0 and 127) of estimated notes
    onset_tolerance : float > 0
        The tolerance for an estimated note's onset deviating from the
        reference note's onset, in seconds. Default is 0.05 (50 ms).
    pitch_tolerance : float > 0
        The tolerance for an estimated note's pitch deviating from the
        reference note's pitch, in cents. Default is 50.0 (50 cents).
    offset_ratio : float > 0 or None
        The ratio of the reference note's duration used to define the
        offset_tolerance. Default is 0.2 (20%), meaning the
        ``offset_tolerance`` will equal the ``ref_duration * 0.2``, or 0.05 (50
        ms), whichever is greater. If ``offset_ratio`` is set to ``None``,
        offsets are ignored in the matching.
    offset_min_tolerance : float > 0
        The minimum tolerance for offset matching. See offset_ratio description
        for an explanation of how the offset tolerance is determined. Note:
        this parameter only influences the results if ``offset_ratio`` is not
        ``None``.
    strict : bool
        If ``strict=False`` (the default), threshold checks for onset, offset,
        and pitch matching are performed using ``<=`` (less than or equal). If
        ``strict=True``, the threshold checks are performed using ``<`` (less
        than).
    velocity_tolerance : float > 0
        Estimated notes are considered correct if, after rescaling and
        normalization to [0, 1], they are within ``velocity_tolerance`` of a
        matched reference note.

    Returns
    -------
    matching : list of tuples
        A list of matched reference and estimated notes.
        ``matching[i] == (i, j)`` where reference note ``i`` matches estimated
        note ``j``.