Track API Reference

A Track object represents a single instrument track within a Score, containing its specific musical events.

Concepts: Track

Type Definition

Track is a generic class parameterized by time unit:

  • TrackTick (Track<Tick> in C++)
  • TrackQuarter (Track<Quarter> in C++)
  • TrackSecond (Track<Second> in C++)

Attributes

AttributeTypeDescription
namestrName of the track (e.g., "Piano", "Drums").
programintMIDI program number (instrument ID, 0-127).
is_drumboolTrue if the track is a percussion/drum track.
notesNoteListList-like container for Note events.
controlsControlChangeListList-like container for ControlChange events.
pitch_bendsPitchBendListList-like container for PitchBend events.
pedalsPedalListList-like container for Pedal events.
lyricsTextMetaListList-like container for lyric TextMeta events.

Properties (Read-Only Methods)

MethodReturn TypeDescription
ttypeTimeUnit objectReturns the time unit object (Tick, Quarter, Second).
start()int or floatStart time of the earliest event in the track.
end()int or floatEnd time of the latest event in the track.
note_num()intNumber of notes in the notes list.
empty()boolTrue if the track contains no events.

Constructors

from symusic import Track, TimeUnit

# Create an empty track
t = Track(name: str = "", program: int = 0, is_drum: bool = False, ttype: str | TimeUnit = "tick")

# Copy constructor (creates a deep copy)
t_copy = Track(other: Track)

Modification Methods

Modify the track's events. Use inplace=True to modify directly, otherwise a new Track is returned.

# Clip track events to a time range [start, end)
t_clipped = track.clip(
    start: int | float,
    end: int | float,
    clip_end: bool = False, # If True, also clip notes ending after 'end'
    inplace: bool = False
)

# Sort all event lists within the track
t_sorted = track.sort(reverse: bool = False, inplace: bool = False)

# Adjust event timings based on mapping original times to new times
t_adjusted = track.adjust_time(
    original_times: list[int | float],
    new_times: list[int | float],
    inplace: bool = False
)

# Shift time of all events by an offset
t_shifted = track.shift_time(offset: int | float, inplace: bool = False)

# Shift pitch of all notes by a semitone offset
t_transposed = track.shift_pitch(offset: int, inplace: bool = False)

# Shift velocity of all notes by an offset
t_dynamics_shifted = track.shift_velocity(offset: int, inplace: bool = False)

Conversion Methods

# Create a copy (deep by default)
track_copy = track.copy(deep: bool = True)

# Convert track to a different time unit
# Returns a NEW Track object with the converted time unit.
track_new_ttype = track.to(ttype: str | TimeUnit, min_dur: int | float | None = None)

# Convert track to piano roll (numpy array)
# Requires track to be in Tick time unit.
pr_array = track_tick.pianoroll(
    modes: list[str] = ["onset", "frame"],
    pitch_range: tuple[int, int] = (0, 128),
    encode_velocity: bool = False
) -> np.ndarray # Shape: (modes, pitch_bins, time_steps)

Event List Methods

The attributes notes, controls, pitch_bends, pedals, and lyrics are specialized list objects with additional methods beyond standard Python list methods:

# Example using track.notes (NoteList), other lists have similar methods
notes_list = track.notes

# Basic properties
start_time = notes_list.start()
end_time = notes_list.end()
is_empty = notes_list.empty()

# Copying
notes_copy = notes_list.copy(deep=True)

# Sorting (inplace by default)
# Default key sorts by time, duration, pitch, velocity
notes_list.sort(key=None, reverse=False, inplace=True)
# Sort by velocity (non-inplace)
notes_sorted_by_vel = notes_list.sort(key=lambda note: note.velocity, inplace=False)

# Check if sorted
is_sorted_by_default = notes_list.is_sorted(key=None, reverse=False)
is_sorted_by_pitch = notes_list.is_sorted(key=lambda note: note.pitch, reverse=False)

# Filtering (inplace by default)
# Keep only notes with pitch >= 60
notes_list.filter(lambda note: note.pitch >= 60, inplace=True)

# Time Adjustment (non-inplace by default)
adjusted_notes = notes_list.adjust_time([0, 480], [0, 500], inplace=False)

# Time Shifting (non-inplace by default)
shifted_notes = notes_list.shift_time(960, inplace=False)

# NumPy Conversion (for NoteList, ControlChangeList, etc.)
# Returns a dictionary mapping attribute names to numpy arrays
numpy_dict = notes_list.numpy()
# e.g., numpy_dict['time'], numpy_dict['duration'], ...

# Create list from NumPy arrays (Class Method)
from symusic import Note # Use the specific event factory
new_notes_list = Note.from_numpy(
    time=np_time_array,
    duration=np_duration_array,
    pitch=np_pitch_array,
    velocity=np_velocity_array,
    ttype=track.ttype # Important: Specify the time unit!
)

Serialization (Pickling)

Track objects support Python's pickle protocol.

import pickle

# Save track object to a pickle file
with open("track.pkl", "wb") as f:
    pickle.dump(track, f)

# Load track object from a pickle file
with open("track.pkl", "rb") as f:
    loaded_track = pickle.load(f)

# Internal methods (rarely called directly)
# state: bytes = track.__getstate__()
# track.__setstate__(state)

Comparison Methods

# Check if two Track objects are equal (deep comparison)
is_equal: bool = (track1 == track2)

# Check if two Track objects are not equal
is_not_equal: bool = (track1 != track2)

Equality comparison checks if metadata and all event lists are identical.

String Representation

# Get a string summary of the track using repr()
repr_string: str = repr(track)
# Or simply print the track (which calls repr())
print(track)

The string representation (obtained via repr() or print()) provides a summary including name, program, drum status, and event counts. There is no separate .summary() method.