def get_unique_seq(onsets, offsets, unique_onset_idxs=None, return_diff=False):
    """
    Get unique onsets of a sequence of notes
    """
    eps = np.finfo(np.float32).eps

    first_time = np.min(onsets)

    # ensure last score time is later than last onset
    last_time = max(np.max(onsets) + eps, np.max(offsets))

    total_dur = last_time - first_time

    if unique_onset_idxs is None:
        # unique_onset_idxs = unique_onset_idx(score[:, 0])
        unique_onset_idxs = get_unique_onset_idxs(onsets)

    u_onset = np.array([np.mean(onsets[uix]) for uix in unique_onset_idxs])
    # add last offset, so we have as many IOIs as notes
    u_onset = np.r_[u_onset, last_time]

    output_dict = dict(u_onset=u_onset,
                       total_dur=total_dur,
                       unique_onset_idxs=unique_onset_idxs)

    if return_diff:
        output_dict['diff_u_onset'] = np.diff(u_onset)

    return output_dict
    def encode(self,
               pitches,
               velocities,
               score_onsets,
               score_durations,
               unique_onset_idxs=None,
               return_u_onset_idx=False,
               *args,
               **kwargs):

        if unique_onset_idxs is None:
            unique_onset_idxs = get_unique_onset_idxs(score_onsets)

        velocity_trend = np.array(
            [np.max(velocities[uix]) for uix in unique_onset_idxs])

        parameters = np.zeros(len(pitches),
                              dtype=[(pn, 'f4')
                                     for pn in self.parameter_names])
        for i, jj in enumerate(unique_onset_idxs):
            parameters['velocity_trend'][jj] = velocity_trend[i] / 127.0
            parameters['velocity_dev'][jj] = (velocity_trend[i] -
                                              velocities[jj]) / 127.0

        if return_u_onset_idx:
            return parameters, unique_onset_idxs
        else:
            return parameters
示例#3
0
    def decode(self, parameters, *args, **kwargs):

        score_onsets = kwargs.get('score_onsets', None)
        if score_onsets is None:
            velocity = parameters['velocity_trend'] - parameters['velocity_dev']
        else:
            unique_onset_idxs = get_unique_onset_idxs(score_onsets)
            velocity = parameters['velocity_trend']
            vel_dev = parameters['velocity_dev']
            for uix in unique_onset_idxs:
                vd = vel_dev[uix]
                vd[vd.argmin()] = 0
                velocity[uix] -= vd
        return np.round(velocity * 127.0)
示例#4
0
    def predict(self, x, score_onsets):

        if x.ndim != 2:
            raise ValueError('The inputs should be a 2D array')

        unique_onset_idxs = get_unique_onset_idxs(score_onsets)

        _predictions = []

        for bf_idxs, model in zip(self.model_bf_idxs, self.models):
            # Get slice of the input corresponding to the bfs
            # used in the model
            model_input = x[:, bf_idxs]

            # aggregate bfs per onset
            if model.input_type == 'onsetwise':
                model_input = notewise_to_onsetwise(model_input,
                                                    unique_onset_idxs)
            # make predictions
            preds = model.predict(model_input)

            # expand predictions per each note
            if model.input_type == 'onsetwise':
                preds = onsetwise_to_notewise(preds, unique_onset_idxs)

            _predictions.append(preds)

        # structured array for holding expressive parameters
        predictions = np.zeros(len(score_onsets),
                               dtype=[(pn, 'f4') for pn in self.output_names])
        # assign predictions according to the overlapping strategy
        # or default value
        for pn in self.output_names:
            model_idxs = self.model_param_idxs[pn]
            if len(model_idxs) > 0:
                if self.overlapping_output_strategy == 'FIFO':
                    predictions[pn] = _predictions[model_idxs[0]][pn]

                elif self.overlapping_output_strategy == 'mean':
                    predictions[pn] = np.mean(
                        np.column_stack([_predictions[mix][pn] for mix in model_idxs]),
                        axis=1)
            else:
                predictions[pn] = np.ones(len(score_onsets)) * self.default_values[pn]
        return predictions
def tempo_by_derivative(score_onsets,
                        performed_onsets,
                        score_durations,
                        performed_durations,
                        unique_onset_idxs=None,
                        input_onsets=None,
                        return_onset_idxs=False):
    """
    Computes a tempo curve using the derivative of the average performed
    onset times of all notes belonging to the same score onset with respect
    to that score onset. This results in a curve that is smoother than the
    tempo estimated using `tempo_by_average`.

    Parameters
    ----------
    score_onsets : np.ndarray
        Onset in beats of each note in the score.
    performed_onsets : np.ndarray
        Performed onsets in seconds of each note in the score.
    score_durations : np.ndarray
        Duration in beats of each note in the score.
    performed_durations : np.ndarray
        Performed duration in seconds of each note in the score.
    unique_onset_idxs : np.ndarray or None (optional)
        Indices of the notes with the same score onset. (By default is None,
        and is therefore, inferred from `score_onsets`).
    input_onsets : np.ndarray or None
        Input onset times in beats at which the tempo curve is to be
        sampled (by default is None, which means that the tempo curve
        is returned for each unique score onset)
    return_onset_idxs : bool
        Return the indices of the unique score onsets (Default is False)

    Returns
    -------
    tempo_curve : np.ndarray
        Tempo curve in seconds per beat (spb). If `input_onsets` was provided,
        this array contains the value of the tempo in spb for each onset
        in `input_onsets`. Otherwise, this array contains the value of the
        tempo in spb for each unique score onset.
    input_onsets : np.ndarray
        The score onsets corresponding to each value of the tempo curve.
    unique_onset_idxs: list
        Each element of the list is an array of the indices of the score
        corresponding to the elements in `tempo_curve`. Only returned if
        `return_onset_idxs` is True.
    """
    # use float64, float32 led to problems that x == x + eps evaluated
    # to True
    score_onsets = np.array(score_onsets).astype(np.float64, copy=False)
    performed_onsets = np.array(performed_onsets).astype(np.float64,
                                                         copy=False)
    score_durations = np.array(score_durations).astype(np.float64, copy=False)

    performed_durations = np.array(performed_durations).astype(np.float64,
                                                               copy=False)

    # Get unique onsets if no provided
    if unique_onset_idxs is None:
        # Get indices of the unique onsets (quantize score onsets)
        unique_onset_idxs = get_unique_onset_idxs(
            (1e4 * score_onsets).astype(np.int))

    # Get score information
    score_info = get_unique_seq(onsets=score_onsets,
                                offsets=score_onsets + score_durations,
                                unique_onset_idxs=unique_onset_idxs,
                                return_diff=False)
    # Get performance information
    perf_info = get_unique_seq(onsets=performed_onsets,
                               offsets=performed_onsets + performed_durations,
                               unique_onset_idxs=unique_onset_idxs,
                               return_diff=False)

    # unique score onsets
    unique_s_onsets = score_info['u_onset']
    # equivalent onsets
    eq_onsets = perf_info['u_onset']

    # Monotonize times
    eq_onset_mt, unique_s_onsets_mt = monotonize_times(eq_onsets,
                                                       deltas=unique_s_onsets)
    # Function that that interpolates the equivalent performed onsets
    # as a function of the score onset.
    onset_fun = interp1d(unique_s_onsets_mt,
                         eq_onset_mt,
                         kind='linear',
                         fill_value='extrapolate')

    if input_onsets is None:
        input_onsets = unique_s_onsets[:-1]

    tempo_curve = derivative(onset_fun, input_onsets, dx=0.5)

    output = [tempo_curve, input_onsets]

    if return_onset_idxs:
        output.append(unique_onset_idxs)

    return output
def tempo_by_average(score_onsets,
                     performed_onsets,
                     score_durations,
                     performed_durations,
                     unique_onset_idxs=None,
                     input_onsets=None,
                     return_onset_idxs=False):
    """
    Computes a tempo curve using the average of the onset times of all
    notes belonging to the same score onset.

    Parameters
    ----------
    score_onsets : np.ndarray
        Onset in beats of each note in the score.
    performed_onsets : np.ndarray
        Performed onsets in seconds of each note in the score.
    score_durations : np.ndarray
        Duration in beats of each note in the score.
    performed_durations : np.ndarray
        Performed duration in seconds of each note in the score.
    unique_onset_idxs : np.ndarray or None (optional)
        Indices of the notes with the same score onset. (By default is None,
        and is therefore, inferred from `score_onsets`).
    input_onsets : np.ndarray or None
        Input onset times in beats at which the tempo curve is to be
        sampled (by default is None, which means that the tempo curve
        is returned for each unique score onset)
    return_onset_idxs : bool
        Return the indices of the unique score onsets (Default is False)

    Returns
    -------
    tempo_curve : np.ndarray
        Tempo curve in seconds per beat (spb). If `input_onsets` was provided,
        this array contains the value of the tempo in spb for each onset
        in `input_onsets`. Otherwise, this array contains the value of the
        tempo in spb for each unique score onset.
    input_onsets : np.ndarray
        The score onsets corresponding to each value of the tempo curve.
    unique_onset_idxs: list
        Each element of the list is an array of the indices of the score
        corresponding to the elements in `tempo_curve`. Only returned if
        `return_onset_idxs` is True.
    """
    # use float64, float32 led to problems that x == x + eps evaluated
    # to True
    score_onsets = np.array(score_onsets).astype(np.float64, copy=False)
    performed_onsets = np.array(performed_onsets).astype(np.float64,
                                                         copy=False)
    score_durations = np.array(score_durations).astype(np.float64, copy=False)
    performed_durations = np.array(performed_durations).astype(np.float64,
                                                               copy=False)

    # Get unique onsets if no provided
    if unique_onset_idxs is None:
        # Get indices of the unique onsets (quantize score onsets)
        unique_onset_idxs = get_unique_onset_idxs(
            (1e4 * score_onsets).astype(np.int))

    # Get score information
    score_info = get_unique_seq(onsets=score_onsets,
                                offsets=score_onsets + score_durations,
                                unique_onset_idxs=unique_onset_idxs,
                                return_diff=False)
    # Get performance information
    perf_info = get_unique_seq(onsets=performed_onsets,
                               offsets=performed_onsets + performed_durations,
                               unique_onset_idxs=unique_onset_idxs,
                               return_diff=False)

    # unique score onsets
    unique_s_onsets = score_info['u_onset']
    # equivalent onsets
    eq_onsets = perf_info['u_onset']

    # Monotonize times
    eq_onset_mt, unique_s_onsets_mt = monotonize_times(eq_onsets,
                                                       deltas=unique_s_onsets)

    # Estimate Beat Period
    perf_iois = np.diff(eq_onset_mt)
    s_iois = np.diff(unique_s_onsets_mt)
    beat_period = perf_iois / s_iois

    tempo_fun = interp1d(unique_s_onsets_mt[:-1],
                         beat_period,
                         kind='zero',
                         bounds_error=False,
                         fill_value=(beat_period[0], beat_period[-1]))

    if input_onsets is None:
        input_onsets = unique_s_onsets[:-1]

    tempo_curve = tempo_fun(input_onsets)

    if return_onset_idxs:
        return tempo_curve, input_onsets, unique_onset_idxs
    else:
        return tempo_curve, input_onsets