partitura.utils

Top level of the utilities module.

partitura.utils.compute_pianoroll(note_info: np.ndarray | ScoreLike | PerformanceLike, time_unit: str = 'auto', time_div: str | int = 'auto', onset_only: bool = False, note_separation: bool = False, pitch_margin: int = -1, time_margin: int = 0, return_idxs: bool = False, piano_range: bool = False, remove_drums: bool = True, remove_silence: bool = True, end_time: int | None = None, binary: bool = False)[source]

Computes a piano roll from a score-like, performance-like or a note array.

A piano roll is a 2D matrix of size (pitch_range, num_time_steps), where each row represents a MIDI pitch and each column represents a time step. The (i,j)-th element specifies whether pitch i is active (i.e., non-zero) at time step j.

The pitch_range is specified by the parameters piano_range and pitch_margin, (see below), but it defaults to 128 (the standard range of MIDI note numbers), or 88 if piano_range is True. The num_time_steps are specified by the temporal resolution of the piano roll and the length of the piece, and can be controlled with parameters time_div, time_unit and time_margin below.

Parameters:
  • note_info (np.ndarray, ScoreLike, PerformanceLike) – Note information

  • time_unit (('auto', 'beat', 'quarter', 'div', 'sec')) – The time unit to use for computing the piano roll. If “auto”, the time unit defaults to “beat” for score-like objects and “sec” for performance-like objects.

  • time_div (int, optional) – How many sub-divisions for each time unit (beats for a score or seconds for a performance. See is_performance below).

  • onset_only (bool, optional) – If True, code only the onsets of the notes, otherwise code onset and duration.

  • pitch_margin (int, optional) – If pitch_margin > -1, the resulting array will have pitch_margin empty rows above and below the highest and lowest pitches, respectively; if pitch_margin == -1, the resulting pianoroll will have span the fixed pitch range between (and including) 1 and 127.

  • time_margin (int, optional) – The resulting array will have time_margin * time_div empty columns before and after the piano roll

  • return_idxs (bool, optional) – If True, return the indices (i.e., the coordinates) of each note in the piano roll.

  • piano_range (bool, optional) – If True, the pitch axis of the piano roll is in piano keys instead of MIDI note numbers (and there are only 88 pitches). This is equivalent as slicing piano_range_pianoroll = pianoroll[21:109, :].

  • remove_drums (bool, optional) – If True, removes the drum track (i.e., channel 9) from the notes to be considered in the piano roll. This option is only relevant for piano rolls generated from a PerformedPart. Default is True.

  • remove_silence (bool, optional) – If True, the first frame of the pianoroll starts at the onset of the first note, not at time 0 of the timeline.

  • end_time (int, optional) – The time corresponding to the ending of the last pianoroll frame (in time_unit). If None this is set to the last note offset.

  • binary (bool, optional) – Ensure a strictly binary piano roll.

Returns:

  • pianoroll (scipy.sparse.csr_matrix) – A sparse int matrix of size representing the pianoroll; The first dimension is pitch, the second is time; The sizes of the dimensions vary with the parameters pitch_margin, time_margin, time_div, remove silence, and end_time.

  • pr_idx (ndarray) – Indices of the onsets and offsets of the notes in the piano roll (in the same order as the input note_array). This is only` returned if return_idxs is True. The indices have 4 columns (vertical_position_in_piano_roll, onset, offset, original_midi_pitch). The vertical_position_in_piano_roll might be different from original_midi_pitch depending on the pitch_margin and piano_range arguments.

Examples

>>> import numpy as np
>>> from partitura.utils import compute_pianoroll
>>> note_array = np.array([(60, 0, 1)],                          dtype=[('pitch', 'i4'),                                 ('onset_beat', 'f4'),                                 ('duration_beat', 'f4')])
>>> pr = compute_pianoroll(note_array, pitch_margin=2, time_div=2)
>>> pr.toarray()
array([[0, 0],
       [0, 0],
       [1, 1],
       [0, 0],
       [0, 0]])

Notes

The default values in this function assume that the input note_array represents a score.

partitura.utils.compute_pitch_class_pianoroll(note_info: ScoreLike | PerformanceLike | np.ndarray, normalize: bool = True, time_unit: str = 'auto', time_div: int = 'auto', onset_only: bool = False, note_separation: bool = False, time_margin: int = 0, return_idxs: int = False, remove_silence: bool = True, end_time: float | None = None, binary: bool = False) np.ndarray[source]

Compute a pitch class piano roll from a score-like or performance-like objects, or from a note array as a structured numpy array.

A pitch class piano roll is a 2D matrix of size (12, num_time_steps), where each row represents a pitch class (C=0, C#=1, D=2, etc.) and each column represents a time step. The (i,j)-th element specifies whether pitch class i is active at time step j.

See compute_pianoroll for more details.

Parameters:
  • note_info (np.ndarray, ScoreLike, PerformanceLike) – Note information.

  • normalize (bool) – Normalize the piano roll. If True, each slice (i.e., time-step) will be normalized to sum to one. The resulting output is a piano roll where each time step is the pitch class distribution.

  • time_unit (('auto', 'beat', 'quarter', 'div', 'sec')) – The time unit to use for computing the piano roll. If “auto”, the time unit defaults to “beat” for score-like objects and “sec” for performance-like objects.

  • time_div (int, optional) – How many sub-divisions for each time unit (beats for a score or seconds for a performance. See is_performance below).

  • onset_only (bool, optional) – If True, code only the onsets of the notes, otherwise code onset and duration.

  • time_margin (int, optional) – The resulting array will have time_margin * time_div empty columns before and after the piano roll

  • return_idxs (bool, optional) – If True, return the indices (i.e., the coordinates) of each note in the piano roll.

  • piano_range (bool, optional) – If True, the pitch axis of the piano roll is in piano keys instead of MIDI note numbers (and there are only 88 pitches). This is equivalent as slicing piano_range_pianoroll = pianoroll[21:109, :].

  • remove_drums (bool, optional) – If True, removes the drum track (i.e., channel 9) from the notes to be considered in the piano roll. This option is only relevant for piano rolls generated from a PerformedPart. Default is True.

  • remove_silence (bool, optional) – If True, the first frame of the pianoroll starts at the onset of the first note, not at time 0 of the timeline.

  • end_time (int, optional) – The time corresponding to the ending of the last pianoroll frame (in time_unit). If None this is set to the last note offset.

  • binary (bool, optional) – Ensure a strictly binary piano roll.

Returns:

  • pc_pianoroll (np.ndarray) – The pitch class piano roll. The sizes of the dimensions vary with the parameters pitch_margin, time_margin, time_div, remove silence, and end_time.

  • pr_idx (ndarray) – Indices of the onsets and offsets of the notes in the piano roll (in the same order as the input note_array). This is only returned if return_idxs is True. The indices have 4 columns (pitch_class, onset, offset, original_midi_pitch).

partitura.utils.ensure_notearray(notearray_or_part, *args, **kwargs)[source]

Ensures to get a structured note array from the input.

Parameters:
  • notearray_or_part (structured ndarray, Score, Part, PerformedPart) – Input score information

  • kwargs (dict) – Additional arguments to be passed to partitura.utils.note_array_from_part().

Returns:

Structured array containing score information.

Return type:

structured ndarray

partitura.utils.ensure_rest_array(restarray_or_part, *args, **kwargs)[source]

Ensures to get a structured note array from the input.

Parameters:

restarray_or_part (structured ndarray, Part or PerformedPart) – Input score information

Returns:

Structured array containing score information.

Return type:

structured ndarray

partitura.utils.fifths_mode_to_key_name(fifths, mode=None)[source]

Return the key signature name corresponding to a number of sharps or flats and a mode. A negative value for fifths denotes the number of flats (i.e. -3 means three flats), and a positive number the number of sharps. The mode is specified as ‘major’ or ‘minor’. If mode is None, the key is assumed to be major.

Parameters:
  • fifths (int) – Number of fifths

  • mode ({'major', 'minor', None, -1, 1}) – Mode of the key signature

Returns:

The name of the key signature, e.g. ‘Am’

Return type:

str

Examples

>>> fifths_mode_to_key_name(0, 'minor')
'Am'
>>> fifths_mode_to_key_name(0, 'major')
'C'
>>> fifths_mode_to_key_name(3, 'major')
'A'
>>> fifths_mode_to_key_name(-1, 1)
'F'
partitura.utils.key_mode_to_int(mode)[source]

Return the mode of a key as an integer (1 for major and -1 for minor).

Parameters:

mode ({'major', 'minor', None, 1, -1}) – Mode of the key

Returns:

Integer representation of the mode.

Return type:

int

partitura.utils.key_name_to_fifths_mode(key_name)[source]

Return the number of sharps or flats and the mode of a key signature name. A negative number denotes the number of flats (i.e. -3 means three flats), and a positive number the number of sharps. The mode is specified as ‘major’ or ‘minor’.

Parameters:

name (str) – Name of the key signature, i.e. Am, E#, etc

Returns:

Tuple containing the number of fifths and the mode

Return type:

(int, str)

Examples

>>> key_name_to_fifths_mode('Am')
(0, 'minor')
>>> key_name_to_fifths_mode('C')
(0, 'major')
>>> key_name_to_fifths_mode('A')
(3, 'major')
partitura.utils.normalize(in_array, norm_funcs={'articulation_log': {'func': <function range_normalize>, 'kwargs': {'max_value': 3, 'min_value': -4}}, 'beat_period': {'func': <function range_normalize>, 'kwargs': {'log2': True, 'max_value': 2, 'min_value': -3}}, 'duration_beat': {'func': <function range_normalize>, 'kwargs': {'log2': True, 'max_value': 3, 'min_value': -3}}, 'onset_beat': {'func': <function minmaxrange_normalize>, 'kwargs': {}}, 'pitch': {'func': <function range_normalize>, 'kwargs': {'max_value': 127, 'min_value': 0}}, 'timing': {'func': <function range_normalize>, 'kwargs': {'max_value': 0.2, 'min_value': -0.2}}, 'velocity': {'func': <function range_normalize>, 'kwargs': {'max_value': 127, 'min_value': 0}}}, norm_func_fallback=<function minmaxrange_normalize>, default_value=inf)[source]

Normalize a note array. May include note features as well as performance features. All input columns must be of numeric types, everything is cast to single precision float.

Parameters:
  • array (np.ndarray) – The performance array to be normalized.

  • norm_funcs (dict) – A dictionary of normalization functions for each feature.

Returns:

array – The normalized performance array.

Return type:

np.ndarray

partitura.utils.note_array_from_part(part, include_pitch_spelling=False, include_key_signature=False, include_time_signature=False, include_metrical_position=False, include_grace_notes=False, include_staff=False, include_divs_per_quarter=False)[source]

Create a structured array with note information from a Part object.

Parameters:
  • part (partitura.score.Part) – An object representing a score part.

  • include_pitch_spelling (bool (optional)) – It’s a dummy attribute for consistancy between note_array_from_part and note_array_from_part_list. Default is False

  • include_pitch_spelling – If True, includes pitch spelling information for each note. Default is False

  • include_key_signature (bool (optional)) – If True, includes key signature information, i.e., the key signature at the onset time of each note (all notes starting at the same time have the same key signature). Default is False

  • include_time_signature (bool (optional)) – If True, includes time signature information, i.e., the time signature at the onset time of each note (all notes starting at the same time have the same time signature). Default is False

  • include_metrical_position (bool (optional)) – If True, includes metrical position information, i.e., the position of the onset time of each note with respect to its measure (all notes starting at the same time have the same metrical position). Default is False

  • include_grace_notes (bool (optional)) – If True, includes grace note information, i.e. if a note is a grace note and the grace type “” for non grace notes). Default is False

  • include_staff (bool (optional)) – If True, includes staff information Default is False

  • include_divs_per_quarter (bool (optional)) – If True, include the number of divs (e.g. MIDI ticks, MusicXML ppq) per quarter note of the current part. Default is False

Returns:

note_array

A structured array containing note information. The fields are
  • ’onset_beat’: onset time of the note in beats

  • ’duration_beat’: duration of the note in beats

  • ’onset_quarter’: onset time of the note in quarters

  • ’duration_quarter’: duration of the note in quarters

  • ’onset_div’: onset of the note in divs (e.g., MIDI ticks, divisions in MusicXML)

  • ’duration_div’: duration of the note in divs

  • ’pitch’: MIDI pitch of a note.

  • ’voice’: Voice number of a note (if given in the score)

  • ’id’: Id of the note

If include_pitch_spelling is True:
  • ’step’: name of the note (“C”, “D”, “E”, “F”, “G”, “A”, “B”)

  • ’alter’: alteration (0=natural, -1=flat, 1=sharp, 2=double sharp, etc.)

  • ’octave’: octave of the note.

If include_key_signature is True:
  • ’ks_fifths’: Fifths starting from C in the circle of fifths

  • ’mode’: major or minor

If include_time_signature is True:
  • ’ts_beats’: number of beats in a measure

  • ’ts_beat_type’: type of beats (denominator of the time signature)

  • ’ts_mus_beat’ : number of musical beats is it’s set, otherwise ts_beats

If include_metrical_position is True:
  • ’is_downbeat’: 1 if the note onset is on a downbeat, 0 otherwise

  • ’rel_onset_div’: number of divs elapsed from the beginning of the note measure

  • ’tot_measure_divs’ : total number of divs in the note measure

If ‘include_grace_notes’ is True:
  • ’is_grace’: 1 if the note is a grace 0 otherwise

  • ’grace_type’ : the type of the grace notes “” for non grace notes

If ‘include_staff’ is True:
  • ’staff’ : the staff number for each note

If ‘include_divs_per_quarter’ is True:
  • ’divs_pq’: the number of divs per quarter note

Return type:

structured array

Examples

>>> from partitura import load_musicxml, EXAMPLE_MUSICXML
>>> from partitura.utils import note_array_from_part
>>> part = load_musicxml(EXAMPLE_MUSICXML)
>>> note_array_from_part(part, True, True, True) 
array([(0., 4., 0., 4.,  0, 48, 69, 1, 'n01', 'A', 0, 4, 0, 1, 4, 4),
       (2., 2., 2., 2., 24, 24, 72, 2, 'n02', 'C', 0, 5, 0, 1, 4, 4),
       (2., 2., 2., 2., 24, 24, 76, 2, 'n03', 'E', 0, 5, 0, 1, 4, 4)],
      dtype=[('onset_beat', '<f4'),
             ('duration_beat', '<f4'),
             ('onset_quarter', '<f4'),
             ('duration_quarter', '<f4'),
             ('onset_div', '<i4'),
             ('duration_div', '<i4'),
             ('pitch', '<i4'),
             ('voice', '<i4'),
             ('id', '<U256'),
             ('step', '<U256'),
             ('alter', '<i4'),
             ('octave', '<i4'),
             ('ks_fifths', '<i4'),
             ('ks_mode', '<i4'),
             ('ts_beats', '<i4'),
             ('ts_beat_type', '<i4')])
partitura.utils.pianoroll_to_notearray(pianoroll, time_div=8, time_unit='sec')[source]

Extract a structured note array from a piano roll.

For now, the structured note array is considered a “performance”.

Parameters:
  • pianoroll (array-like) – 2D array containing a piano roll. The first dimension is pitch, and the second is time. The value of each “pixel” in the piano roll is considered to be the MIDI velocity, and it is supposed to be between 0 and 127.

  • time_div (int) – How many sub-divisions for each time unit (see notearray_to_pianoroll).

  • time_unit ({'beat', 'quarter', 'div', 'sec'}) – time unit of the output note array.

Returns:

Structured array with pitch, onset, duration, velocity and note id fields.

Return type:

np.ndarray

Notes

Please note that all non-zero pixels will contribute to a note. For the case of piano rolls with continuous values between 0 and 1 (as might be the case of those piano rolls produced using probabilistic/generative models), we recomend to either 1) hard- threshold the piano roll to have only 0s (note-off) or 1s (note- on) or, 2) soft-threshold the notes (values below a certain threshold are considered as not active and scale the active notes to lie between 1 and 127).

partitura.utils.show_diff(a, b)[source]

Show the difference between two strings, using the difflib package. The difference is printed to stdout.

Parameters:
  • a (str) – First string

  • b (str) – Second string

partitura.utils.slice_notearray_by_time(note_array, start_time, end_time, time_unit='auto', clip_onset_duration=True)[source]

Get a slice of a structured note array by time

Parameters:
  • note_array (structured array) – Structured array with score information.

  • start_time (float) – Starting time

  • end_time (float) – End time

  • time_unit ({'auto', 'beat', 'quarter', 'second', 'div'} optional) – Time unit. If ‘auto’, the default time unit will be inferred from the note_array.

  • clip_onset_duration (bool optional) – Clip duration of the notes in the array to fit within the specified window

Returns:

note_array_slice – Structured array with only the score information between start_time and end_time.

Return type:

stuctured array

partitura.utils.synthesize(note_info, samplerate: int = 44100, envelope_fun: str = 'linear', tuning: str | Callable = 'equal_temperament', tuning_kwargs: Dict[str, Any] = {'a4': 440.0}, harmonic_dist: str | int | None = None, bpm: float | ndarray | Callable = 60) ndarray[source]

Synthesize a partitura object with note information using additive synthesis

Parameters:
  • note_info (ScoreLike, PerformanceLike or np.ndarray) – A partitura object with note information.

  • samplerate (int) – The sample rate of the audio file in Hz.

  • envelope_fun ({"linear", "exp" }) – The type of envelop to apply to the individual sine waves.

  • tuning ({"equal_temperament", "natural"} or callable.) – The tuning system to use. If the value is “equal_temperament”, 12 tone equal temperament implemented in midi_pitch_to_frequency will be used. If the value is “natural”, the function midi_pitch_to_tempered_frequency will be used. Note that midi_pitch_to_tempered_frequency computes the intervals (and thus, frequencies) with respect to a reference note (A4 by default) and uses the interval ratios specified by FIVE_LIMIT_INTERVAL_RATIOS. See the documentation of these functions for more information. If a callable is provided, function should get MIDI pitch as input and return frequency in Hz as output.

  • tuning_kwargs (dict) –

    Dictionary of keyword arguments to be passed to the tuning function

    specified in tuning. See midi_pitch_to_tempered_frequency and

    midi_pitch_to_frequency for more information on their keyword arguments.

  • harmonic_dist (int, "shepard" or None (optional)) – Distribution of harmonics. If an integer, it is the number of harmonics to be considered. If “shepard”, it uses Shepard tones. Default is None (i.e., only consider the fundamental frequency)

  • bpm (float, np.ndarray or callable) – The bpm to render the output (if the input is a score-like object). See partitura.utils.music.performance_notearray_from_score_notearray for more information on this parameter.

Returns:

audio_signal – Audio signal as a 1D array.

Return type:

np.ndarray