o
    siB                     @   sn   d Z ddlZddlZddlmZ ddlmZ dd Z				
			dddZ				
				dddZ	dd Z
dS )a  
Transcription evaluation, as defined in :mod:`mir_eval.transcription`, does not
take into account the velocities of reference and estimated notes. This
submodule implements a variant of
:func:`mir_eval.transcription.precision_recall_f1_overlap` which
additionally considers note velocity when determining whether a note is
correctly transcribed. This is done by defining a new function
:func:`mir_eval.transcription_velocity.match_notes` which first calls
:func:`mir_eval.transcription.match_notes` to get a note matching based on
onset, offset, and pitch. Then, we follow the evaluation procedure described in
[#hawthorne2018onsets]_ to test whether an estimated note should be considered
correct:

1. Reference velocities are re-scaled to the range [0, 1].

2. A linear regression is performed to estimate global scale and offset
   parameters which minimize the L2 distance between matched estimated and
   (rescaled) reference notes.

3. The scale and offset parameters are used to rescale estimated
   velocities.

4. An estimated/reference note pair which has been matched according to the
   onset, offset, and pitch is further only considered correct if the rescaled
   velocities are within a predefined threshold, defaulting to 0.1.

:func:`mir_eval.transcription_velocity.match_notes` is used to define a new
variant :func:`mir_eval.transcription_velocity.precision_recall_f1_overlap`
which considers velocity.

Conventions
-----------

This submodule follows the conventions of :mod:`mir_eval.transcription` and
additionally requires velocities to be provided as MIDI velocities in the range
[0, 127].

Metrics
-------

* :func:`mir_eval.transcription_velocity.precision_recall_f1_overlap`: The
  precision, recall, F-measure, and Average Overlap Ratio of the note
  transcription, where an estimated note is considered correct if its pitch,
  onset, velocity and (optionally) offset are sufficiently close to a reference
  note.

References
----------
  .. [#hawthorne2018onsets] Curtis Hawthorne, Erich Elsen, Jialin Song, Adam
      Roberts, Ian Simon, Colin Raffel, Jesse Engel, Sageev Oore, and Douglas
      Eck, "Onsets and Frames: Dual-Objective Piano Transcription", Proceedings
      of the 19th International Society for Music Information Retrieval
      Conference, 2018.
    N   )transcription)utilc                 C   s   t | ||| |jd |jd kstd|jd |jd ks$td|jdkr4t|dk r4td|jdkrDt|dk rFtddS dS )a.  Check that the input annotations have valid time intervals, pitches,
    and velocities, and throws helpful errors if not.

    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
    r   zHReference velocities must have the same length as pitches and intervals.zHEstimated velocities must have the same length as pitches and intervals.z&Reference velocities must be positive.z&Estimated velocities must be positive.N)r   validateshape
ValueErrorsizenpmin)ref_intervalsref_pitchesref_velocitiesest_intervalsest_pitchesest_velocities r   S/home/ubuntu/.local/lib/python3.10/site-packages/mir_eval/transcription_velocity.pyr   >   s   r   皙?      I@皙?F皙?c                 C   s   t | |||||||	|
	}t|t|}}td|| }|| t| }t|}|jdkr3g S ||dddf  }||dddf  }tjj	t
|tt|gj|ddd \}}|| | }t|| }||k }|| }dd |D }|S )a  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``.
    r   r   N)rcondc                 S   s   g | ]}t |qS r   )tuple).0_r   r   r   
<listcomp>   s    zmatch_notes.<locals>.<listcomp>)r   match_notesr	   r
   maxfloatarrayr   linalglstsqvstackoneslenTabs)r   r   r   r   r   r   onset_tolerancepitch_toleranceoffset_ratiooffset_min_tolerancestrictvelocity_tolerancematchingmin_velocitymax_velocityvelocity_rangeref_matched_velocitiesest_matched_velocitiesslope	interceptvelocity_diffvelocity_within_tolerancer   r   r   r   k   s@   K

r         ?c                 C   s   t | ||||| t|dkst|dkrdS t| |||||||||	|
|}tt|t| }tt|t| }tj|||d}t| ||}||||fS )a  Compute the Precision, Recall and F-measure of correct vs incorrectly
    transcribed notes, and the Average Overlap Ratio for correctly transcribed
    notes (see :func:`mir_eval.transcription.average_overlap_ratio`).
    "Correctness" is determined based on note onset, velocity, pitch and
    (optionally) offset. An estimated note is considered correct if

    1. Its onset is within ``onset_tolerance`` (default +-50ms) of a
       reference note
    2. Its pitch (F0) is within +/- ``pitch_tolerance`` (default one
       quarter tone, 50 cents) of the corresponding reference note
    3. Its velocity, after normalizing reference velocities to the range
       [0, 1] and globally rescaling estimated velocities to minimize L2
       distance between matched reference notes, is within
       ``velocity_tolerance`` (default 0.1) the corresponding reference note
    4. If ``offset_ratio`` is ``None``, note offsets are ignored in the
       comparison. Otherwise, on top of the above requirements, a correct
       returned note is required to have an offset value within
       `offset_ratio`` (default 20%) of the reference note's duration around
       the reference note's offset, or within ``offset_min_tolerance``
       (default 50 ms), whichever is larger.

    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=(n,)
        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
        ``offset_min_tolerance`` (0.05 by default, i.e. 50 ms), whichever is
        greater. If ``offset_ratio`` is set to ``None``, offsets are ignored in
        the evaluation.
    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.
    beta : float > 0
        Weighting factor for f-measure (default value = 1.0).

    Returns
    -------
    precision : float
        The computed precision score
    recall : float
        The computed recall score
    f_measure : float
        The computed F-measure score
    avg_overlap_ratio : float
        The computed Average Overlap Ratio score
    r   )        r8   r8   r8   )beta)r   r$   r   r   r   	f_measurer   average_overlap_ratio)r   r   r   r   r   r   r'   r(   r)   r*   r+   r,   r9   r-   	precisionrecallr:   avg_overlap_ratior   r   r   precision_recall_f1_overlap   s>   [	r?   c                 K   s   t  }|dd |d dur+tjt| |||||fi |\|d< |d< |d< |d< d|d< tjt| |||||fi |\|d< |d	< |d
< |d< |S )a$  Compute all metrics for the given reference and estimated annotations.

    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=(n,)
        Array of MIDI velocities (i.e. between 0 and 127) of estimated notes
    **kwargs
        Additional keyword arguments which will be passed to the
        appropriate metric or preprocessing functions.

    Returns
    -------
    scores : dict
        Dictionary of scores, where the key is the metric name (str) and
        the value is the (float) score achieved.
    r)   r   N	PrecisionRecallz	F-measureAverage_Overlap_RatioPrecision_no_offsetRecall_no_offsetzF-measure_no_offsetAverage_Overlap_Ratio_no_offset)collectionsOrderedDict
setdefaultr   filter_kwargsr?   )r   r   r   r   r   r   kwargsscoresr   r   r   evaluateg  sJ   $rL   )r   r   r   r   Fr   )r   r   r   r   Fr   r7   )__doc__rF   numpyr	    r   r   r   r   r?   rL   r   r   r   r   <module>   s0    74
 
 