Core
The Melody type used throughout the
package.
- class Melody(midi_data, tempo=None)[source]
Bases:
objectMelody representation backed by parallel note lists.
Construct directly with
from_notes(), or pass a midi_data dict with pitches, starts, and ends (as produced bymelody_features.io.midi.import_midi()). Legacy dicts that only provide MIDI Sequence are still supported via string parsing.- classmethod from_notes(pitches, starts, ends, *, tempo=100.0, melody_id='', time_signature='4/4', tempo_changes=None)[source]
Construct a melody from parallel note lists without reading MIDI.
- __init__(midi_data, tempo=None)[source]
Initialize a Melody object from MIDI sequence data.
- Args:
midi_data (dict): Dictionary containing MIDI sequence data tempo (float, optional): Tempo in BPM. If None, uses tempo from midi_data if available.
- property id: str
Get the ID (file path) of the MIDI file.
- Returns:
str: File path or ID of the MIDI file
- property tempo: float
Extract tempo from Class input.
- Returns:
float: Tempo of the melody in beats per minute
- property tempo_changes: list[tuple[float, float]]
Get tempo changes from the melody.
- Returns:
list[tuple[float, float]]: List of (time_in_seconds, tempo_in_bpm) tuples
- property meter: tuple[int, int]
Extract the first time signature from the melody.
- Returns:
- tuple[int, int]: First time signature as (numerator, denominator)
Defaults to (4, 4) if no time signature information available
- property time_signatures: list[tuple[float, int, int]]
Get all time signatures present in the melody.
- Returns:
- list[tuple[float, int, int]]: List of tuples (time_in_seconds, numerator, denominator).
If none are available, falls back to a single entry using the first meter at time 0.0.
- property proportion_of_time_in_first_meter: float
Calculate the proportion of time spent in the first time signature.
- Returns:
- float: Proportion (0.0 to 1.0) that the first time signature comprises
of the total melody duration. 1.0 means the melody uses only one time signature throughout.
- property total_duration: float
Get the total duration of the MIDI sequence in seconds.
- Returns:
- float: Total duration of the MIDI sequence in seconds, including any
leading or trailing silence. This matches jSymbolic’s DurationInSecondsFeature implementation.
- property key_signature: tuple
Get the first key signature in the melody.
- Returns:
- tuple or None: (key_name, mode) where key_name is a string like ‘C’, ‘Am’, ‘F#’
and mode is either ‘major’ or ‘minor’. Returns None if no key signature found.
- property key_signatures: list
Get all key signatures present in the melody.
- Returns:
- list[tuple]: List of tuples (key_name, mode) for all key signatures.
Empty list if no key signatures are found.
- property has_key_signature: bool
Check if the MIDI file contains any key signature information.
- Returns:
bool: True if at least one key signature was found, False otherwise.
- property key_fifths: int
Get the circle of fifths position of the first key signature.
- Returns:
- int or None: Position on circle of fifths (-7 to 7) where:
0 = C major / A minor Positive = sharps (G=1, D=2, A=3, E=4, B=5, F#=6, C#=7) Negative = flats (F=-1, Bb=-2, Eb=-3, Ab=-4, Db=-5, Gb=-6, Cb=-7) Returns None if no key signature found.
Helpers
- build_midi_data(pitches, starts, ends, *, melody_id='', tempo=100.0, time_signature='4/4', tempo_changes=None)[source]
Build a midi_data dict from parallel note lists.
This is the structured input expected by
Melodyand matches the shape returned bymelody_features.io.midi.import_midi().