Transcription Models
Data models for musical transcription data.
Core Models
Piece
- class idtap.Piece(options: dict | None = None)[source]
Bases:
object- property section_starts_grid: List[List[int]]
Compute section starts from phrase-level is_section_start flags.
- property assemblages: List['Assemblage']
- fill_remaining_duration(target_duration: float, track: int = 0) None[source]
Add a silent trajectory to fill the remaining duration to reach target_duration.
- Parameters:
target_duration – The desired total duration for the piece
track – Which instrument track to add the silence to (default: 0)
- add_trajectory(trajectory_data: Trajectory | Dict[str, Any], inst_track: int, start_time: float) bool[source]
Add a trajectory to the piece by replacing part of a silent trajectory.
- Parameters:
trajectory_data – Either a Trajectory object or dict with trajectory parameters
inst_track – Index of the instrument track to add the trajectory to
start_time – Start time in the piece (in seconds)
- Returns:
True if trajectory was successfully added, False otherwise
- Return type:
- property sections_grid: List[List['Section']]
- property sections: List['Section']
- all_trajectories(inst: int = 0, string_idx: int = 0) List[Trajectory][source]
Get all trajectories for a given instrument track and string index.
- Parameters:
inst – Instrument track index (default 0).
string_idx – String index within the instrument (default 0). For Sitar/Sarangi, string 0 is main, string 1 is jor/second.
- track_from_traj(traj: Trajectory) int[source]
- string_from_traj(traj: Trajectory) int[source]
Determine which string index contains a given trajectory.
Searches all phrases across all strings by unique_id. Returns the string index (0 or 1). Raises ValueError if not found.
- ensure_string_synchronization() None[source]
For Sitar/Sarangi, ensure trajectory_grid[1] exists and is synchronized.
If string 1 is empty or contains only silent trajectories (id=12), fill it with a single silent trajectory matching the phrase duration.
- traj_from_uid(uid: str, track: int = 0) Trajectory[source]
- chikari_freqs(inst_idx: int = 0) List[float][source]
Return 4 chikari frequencies derived from the raga.
Returns 0.0 for strings that are silent (None pitch).
- traj_start_times(inst: int = 0, string_idx: int = 0) List[float][source]
Get start times for all trajectories in a given string.
For string 0: cumulative duration (standard sequential timing). For string > 0: phrase-boundary based (phrase.start_time + traj.start_time).
- most_recent_traj(time: float, inst: int = 0) Trajectory[source]
Phrase
Trajectory
- class idtap.Trajectory(options: dict | None = None)[source]
Bases:
object- id4(x: float, lf: List[float] | None = None, sl: float | None = None, da: List[float] | None = None) float[source]
- id5(x: float, lf: List[float] | None = None, sl: float | None = None, da: List[float] | None = None) float[source]
- static from_json(obj: Dict, ratios=None, fundamental=None) Trajectory[source]
Pitch
- class idtap.Pitch(options: PitchOptionsType | None = None)[source]
Bases:
object- property frequency
- property non_offset_frequency
- property non_offset_log_freq
- property log_freq
- property sargam_letter
- property numbered_pitch
- property chroma
Musical Elements
Raga
- class idtap.Raga(options: RagaOptionsType | None = None, preserve_ratios: bool = False, client=None)[source]
Bases:
object- __init__(options: RagaOptionsType | None = None, preserve_ratios: bool = False, client=None) None[source]
- get_pitches(low: float = 100, high: float = 800) List[Pitch][source]
Get all pitches in the given frequency range.
When ratios have been preserved from transcription data, we generate pitches based on those actual ratios rather than the rule_set.
- property stratified_ratios: List[float | List[float]]
Get stratified ratios matching the structure of the rule_set.
When ratios were preserved from transcription data (preserve_ratios=True), they may not match the rule_set structure. In this case, we use the tuning values directly since the ratios represent the actual transcribed pitches, not the theoretical rule_set structure.
- property chikari_pitches: List[Pitch | None]
Derive 4 chikari pitches from the raga rule set.
Returns list of 4 pitches (or None for silent strings): [0] Sa oct 2 (always present) [1] Sa oct 1 (always present) [2] Pa oct 1 (present if Pa is in the raga, else None) [3] Ga oct 1 (present if exactly one Ga variant, else None)
Section
Meter
- class idtap.Meter(hierarchy: List[int | List[int]] | None = None, start_time: float = 0.0, tempo: float = 60.0, unique_id: str | None = None, repetitions: int = 1, tala_name: TalaName | None = None, vibhaga: List[str | int] | None = None)[source]
Bases:
object- tala_presets: Dict[TalaName, TalaDefinition] = {TalaName.AdaChautal: {'hierarchy': [[2, 2, 2, 2, 2, 2, 2], 4], 'vibhaga': ['X', 'O', 2, 'O', 3, 4, 'O']}, TalaName.Dadra: {'hierarchy': [[3, 3], 4], 'vibhaga': ['X', 'O']}, TalaName.DeepchandiDhrupad: {'hierarchy': [[4, 2, 4, 2], 4], 'vibhaga': ['X', 2, 'O', 3]}, TalaName.DeepchandiThumri: {'hierarchy': [[3, 4, 3, 4], 4], 'vibhaga': ['X', 'O', 2, 3]}, TalaName.Dhamar: {'hierarchy': [[5, 2, 3, 4], 4], 'vibhaga': ['X', 2, 'O', 3]}, TalaName.Ektal: {'hierarchy': [[2, 2, 2, 2, 2, 2], 4], 'vibhaga': ['X', 'O', 2, 'O', 3, 4]}, TalaName.Jhaptal: {'hierarchy': [[2, 3, 2, 3], 4], 'vibhaga': ['X', 2, 'O', 3]}, TalaName.Jhoomra: {'hierarchy': [[3, 4, 3, 4], 4], 'vibhaga': ['X', 2, 'O', 3]}, TalaName.Keherwa: {'hierarchy': [4, 4], 'vibhaga': ['X', 'O']}, TalaName.Rupak: {'hierarchy': [3, 2, 2], 'vibhaga': ['X', 2, 3]}, TalaName.SoolTaal: {'hierarchy': [[2, 2, 2, 2, 2], 4], 'vibhaga': ['X', 2, 'O', 3, 4]}, TalaName.Tilwada: {'hierarchy': [[4, 4, 4, 4], 4], 'vibhaga': ['X', 2, 'O', 3]}, TalaName.Tintal: {'hierarchy': [[4, 4, 4, 4], 4], 'vibhaga': ['X', 2, 'O', 3]}, TalaName.Tivra: {'hierarchy': [[3, 2, 2], 4], 'vibhaga': ['X', 2, 3]}}
- __init__(hierarchy: List[int | List[int]] | None = None, start_time: float = 0.0, tempo: float = 60.0, unique_id: str | None = None, repetitions: int = 1, tala_name: TalaName | None = None, vibhaga: List[str | int] | None = None) None[source]
- classmethod from_tala(name: TalaName, start_time: float, tempo: float, repetitions: int) Meter[source]
Create a Meter from a predefined tala preset.
- Parameters:
name – The tala name (e.g., TalaName.Tintal)
start_time – Start time in seconds
tempo – Tempo in BPM (at matra level)
repetitions – Number of tala cycles
- Returns:
A Meter configured with the tala preset
- get_tempo_at_layer(layer: int) float[source]
Get the tempo at a specific hierarchical layer.
- Parameters:
layer – The hierarchy layer (0 = coarsest/vibhag, higher = finer subdivisions)
- Returns:
The tempo (BPM) at that layer
- Raises:
ValueError – If layer is out of bounds
- property all_pulses: List[Pulse]
Get all pulses from the finest layer (lowest level) of the hierarchy.
This concatenates pulses from all pulse structures in the last layer, matching the TypeScript implementation: lastLayer.map(ps => ps.pulses).flat()
- static from_time_points(time_points: List[float], hierarchy: List[int | List[int]], repetitions: int = 1, layer: int = 0) Meter[source]
Create a Meter from actual pulse time points, handling timing variations.
This method creates a meter that accurately represents actual pulse timing (including rubato and tempo variations) rather than theoretical even spacing. Uses timing regularization algorithm to handle extreme deviations.
- Parameters:
time_points – List of actual pulse times in seconds
hierarchy – Meter hierarchy (e.g., [4, 4, 2])
repetitions – Number of cycle repetitions
layer – Which hierarchical layer the time points represent (0 or 1)
- Returns:
Meter object with pulses positioned at the provided time points
- get_segment_boundary_indices() List[int][source]
Get the indices of matra pulses that are at segment (vibhag) boundaries.
For Tintal [[4,4,4,4], 4]: returns [0, 4, 8, 12] per cycle For Jhoomra [[3,4,3,4], 4]: returns [0, 3, 7, 10] per cycle Returns empty list if hierarchy[0] is not compound.
- get_matra_pulses() List[Pulse][source]
Get only the matra-level pulses (pulses that correspond to matras/beats).
For a hierarchy like [[4,4,4,4], 4] (Tintal): - Total pulses = 64 (16 matras × 4 subdivisions) - Returns only the 16 matra pulses (every 4th pulse)
These are the pulses that correspond to beats in the tala structure.
- get_segment_for_matra_index(matra_idx: int) Dict[str, int] | None[source]
Get the segment range (start and end matra indices) for a given matra index.
Returns None if the hierarchy doesn’t have compound first layer.
- Parameters:
matra_idx – The matra index to find the segment for
- Returns:
Dict with ‘start’ and ‘end’ keys, or None
- offset_segment_boundary(pulse: Pulse, offset: float) bool[source]
Offset a segment boundary pulse and proportionally adjust all matra pulses within that segment.
This makes nudging a vibhag boundary move all the matras within that vibhag proportionally.
- Parameters:
pulse – The pulse to offset (must be at a segment boundary)
offset – The time offset in seconds
- Returns:
True if segment-aware offset was applied, False if regular offset should be used
- get_musical_time(real_time: float, reference_level: int | None = None) 'MusicalTime' | Literal[False][source]
Convert real time to musical time within this meter.
- Parameters:
real_time – Time in seconds
reference_level – Hierarchical level for fractional calculation (0=beat, 1=subdivision, etc.). Defaults to finest level.
- Returns:
MusicalTime object if time falls within meter boundaries, False otherwise
Advanced Models
Articulation
Assemblage
Automation
- class idtap.Automation(options: AutomationOptionsType | None = None)[source]
Bases:
object- static compress(automations: List[Automation], dur_array: List[float]) Automation[source]
- static from_json(obj: Dict) Automation[source]