Python music theory and MIDI processing library for programmers, musicians, composers, and researchers.
—
Data structures for representing and manipulating musical information at different hierarchical levels - from individual notes to complete compositions. These classes store and organize musical data for analysis, manipulation, and playback.
Represents a single musical note with pitch, octave, dynamics, and MIDI properties.
class Note:
"""Single musical note with pitch and performance attributes."""
def __init__(self, name: str = "C", octave: int = 4, dynamics: Any = None, velocity: int = None, channel: int = None):
"""
Create Note object.
Parameters:
- name: Note name (e.g., "C", "F#", "Bb")
- octave: Octave number (typically 0-9)
- dynamics: Dynamic marking (pp, p, mp, mf, f, ff, etc.)
- velocity: MIDI velocity (0-127)
- channel: MIDI channel (1-16)
"""
@property
def name(self) -> str:
"""Note name (e.g., "C#")."""
@property
def octave(self) -> int:
"""Octave number."""
@property
def dynamics(self) -> Any:
"""Dynamic marking."""
@property
def velocity(self) -> int:
"""MIDI velocity (0-127)."""
@property
def channel(self) -> int:
"""MIDI channel (1-16)."""
def set_note(self, name: str = "C", octave: int = 4, dynamics: Any = None, velocity: int = None, channel: int = None) -> None:
"""
Set note properties.
Parameters:
- name: Note name
- octave: Octave number
- dynamics: Dynamic marking
- velocity: MIDI velocity
- channel: MIDI channel
"""
def empty(self) -> None:
"""Clear note to default values."""
def augment(self) -> None:
"""Augment note (raise by semitone)."""
def diminish(self) -> None:
"""Diminish note (lower by semitone)."""
def transpose(self, interval: str, up: bool = True) -> None:
"""
Transpose note by interval.
Parameters:
- interval: Interval to transpose (e.g., "3", "5", "b7")
- up: Direction (True for up, False for down)
"""
def change_octave(self, diff: int) -> None:
"""
Change octave by difference.
Parameters:
- diff: Octave difference (positive or negative)
"""
def octave_up(self) -> None:
"""Move up one octave."""
def octave_down(self) -> None:
"""Move down one octave."""
def to_hertz(self, standard_pitch: float = 440) -> float:
"""
Convert to frequency in Hz.
Parameters:
- standard_pitch: A4 frequency reference
Returns:
Frequency in Hz
"""
def from_hertz(self, hertz: float, standard_pitch: float = 440) -> None:
"""
Set note from frequency.
Parameters:
- hertz: Frequency in Hz
- standard_pitch: A4 frequency reference
"""
def measure(self, other: 'Note') -> int:
"""
Measure interval to other note in half steps.
Parameters:
- other: Other Note object
Returns:
Interval in half steps
"""
def to_shorthand(self) -> str:
"""
Convert to shorthand notation.
Returns:
Shorthand notation string
"""
def from_shorthand(self, shorthand: str) -> None:
"""
Set from shorthand notation.
Parameters:
- shorthand: Shorthand notation string
"""Container for holding multiple notes, representing chords, intervals, or simultaneous note combinations.
class NoteContainer:
"""Container for multiple notes (chords, intervals)."""
def __init__(self, notes: List[Union[str, Note]] = None):
"""
Create NoteContainer.
Parameters:
- notes: List of note names or Note objects
"""
def empty(self) -> None:
"""Empty container of all notes."""
def add_note(self, note: Union[str, Note], octave: int = None, dynamics: Any = None) -> bool:
"""
Add note to container.
Parameters:
- note: Note name or Note object
- octave: Octave for note name
- dynamics: Dynamic marking
Returns:
True if note was added successfully
"""
def add_notes(self, notes: List[Union[str, Note]]) -> None:
"""
Add multiple notes to container.
Parameters:
- notes: List of note names or Note objects
"""
def remove_note(self, note: Union[str, Note], octave: int = -1) -> bool:
"""
Remove note from container.
Parameters:
- note: Note name or Note object to remove
- octave: Specific octave to remove (-1 for any)
Returns:
True if note was removed
"""
def remove_notes(self, notes: List[Union[str, Note]]) -> None:
"""
Remove multiple notes from container.
Parameters:
- notes: List of notes to remove
"""
def from_chord(self, shorthand: str) -> bool:
"""
Create container from chord shorthand.
Parameters:
- shorthand: Chord shorthand (e.g., "CM7", "Am", "F#dim")
Returns:
True if chord was created successfully
"""
def from_interval(self, startnote: str, shorthand: str, up: bool = True) -> bool:
"""
Create container from interval.
Parameters:
- startnote: Starting note
- shorthand: Interval shorthand (e.g., "3", "5", "b7")
- up: Direction (True for up, False for down)
Returns:
True if interval was created successfully
"""
def determine(self, shorthand: bool = False) -> str:
"""
Determine chord name.
Parameters:
- shorthand: Return shorthand notation
Returns:
Chord name or description
"""
def sort(self) -> None:
"""Sort notes by pitch (lowest to highest)."""
def transpose(self, interval: str, up: bool = True) -> None:
"""
Transpose all notes by interval.
Parameters:
- interval: Interval to transpose
- up: Direction (True for up, False for down)
"""
def augment(self) -> None:
"""Augment all notes."""
def diminish(self) -> None:
"""Diminish all notes."""
def is_consonant(self, include_fourths: bool = True) -> bool:
"""
Test if container contains consonant intervals.
Parameters:
- include_fourths: Include perfect fourths as consonant
Returns:
True if all intervals are consonant
"""
def is_dissonant(self, include_fourths: bool = False) -> bool:
"""
Test if container contains dissonant intervals.
Parameters:
- include_fourths: Include perfect fourths as dissonant
Returns:
True if any intervals are dissonant
"""
def get_note_names(self) -> List[str]:
"""
Get list of note names.
Returns:
List of note names in container
"""
def remove_duplicate_notes(self) -> None:
"""Remove duplicate notes from container."""Represents a musical bar/measure containing notes with durations and timing information.
class Bar:
"""Musical bar/measure with notes and timing."""
def __init__(self, key: str = "C", meter: Tuple[int, int] = (4, 4)):
"""
Create Bar object.
Parameters:
- key: Key signature
- meter: Time signature (numerator, denominator)
"""
@property
def key(self) -> str:
"""Key signature."""
@property
def meter(self) -> Tuple[int, int]:
"""Time signature tuple."""
def empty(self) -> None:
"""Empty bar of all notes."""
def set_meter(self, meter: Tuple[int, int]) -> None:
"""
Set time signature.
Parameters:
- meter: Time signature tuple
"""
def place_notes(self, notes: Union[str, List[str], Note, NoteContainer], duration: int) -> bool:
"""
Place notes with duration in bar.
Parameters:
- notes: Notes to place (various formats accepted)
- duration: Note duration (1=whole, 2=half, 4=quarter, etc.)
Returns:
True if notes were placed successfully
"""
def place_notes_at(self, notes: Union[str, List[str], Note, NoteContainer], at: float) -> bool:
"""
Place notes at specific position in bar.
Parameters:
- notes: Notes to place
- at: Position in bar (0.0 to 1.0)
Returns:
True if notes were placed successfully
"""
def place_rest(self, duration: int) -> bool:
"""
Place rest with duration.
Parameters:
- duration: Rest duration
Returns:
True if rest was placed successfully
"""
def is_full(self) -> bool:
"""
Check if bar is full.
Returns:
True if bar contains a full measure worth of notes/rests
"""
def space_left(self) -> float:
"""
Get remaining space in bar.
Returns:
Remaining space as fraction (0.0 to 1.0)
"""
def value_left(self) -> int:
"""
Get remaining value in bar.
Returns:
Remaining note value
"""
def remove_last_entry(self) -> bool:
"""
Remove last entry from bar.
Returns:
True if entry was removed
"""
def transpose(self, interval: str, up: bool = True) -> None:
"""
Transpose all notes in bar.
Parameters:
- interval: Interval to transpose
- up: Direction (True for up, False for down)
"""
def augment(self) -> None:
"""Augment all notes in bar."""
def diminish(self) -> None:
"""Diminish all notes in bar."""
def determine_chords(self, shorthand: bool = False) -> List[str]:
"""
Determine chords in bar.
Parameters:
- shorthand: Return shorthand notation
Returns:
List of chord names
"""
def determine_progression(self, shorthand: bool = False) -> List[str]:
"""
Determine chord progression in bar.
Parameters:
- shorthand: Return shorthand notation
Returns:
List of chord progressions
"""
def get_range(self) -> Tuple[Note, Note]:
"""
Get note range in bar.
Returns:
Tuple of (lowest_note, highest_note)
"""
def get_note_names(self) -> List[str]:
"""
Get all note names in bar.
Returns:
List of note names
"""Represents a musical track containing a sequence of bars, typically for a single instrument or voice.
class Track:
"""Musical track containing sequence of bars."""
def __init__(self, instrument: Any = None):
"""
Create Track object.
Parameters:
- instrument: Associated instrument object
"""
@property
def instrument(self) -> Any:
"""Associated instrument."""
@property
def name(self) -> str:
"""Track name."""
def add_bar(self, bar: Bar) -> None:
"""
Add bar to track.
Parameters:
- bar: Bar object to add
"""
def add_notes(self, note: Union[str, Note, NoteContainer], duration: int = None) -> None:
"""
Add notes with duration to track.
Parameters:
- note: Notes to add
- duration: Note duration
"""
def get_notes(self) -> List[Note]:
"""
Get all notes in track.
Returns:
List of all Note objects in track
"""
def from_chords(self, chords: List[str], duration: int = 1) -> None:
"""
Create track from chord list.
Parameters:
- chords: List of chord shorthands
- duration: Duration for each chord
"""
def transpose(self, interval: str, up: bool = True) -> None:
"""
Transpose entire track.
Parameters:
- interval: Interval to transpose
- up: Direction (True for up, False for down)
"""
def augment(self) -> None:
"""Augment all notes in track."""
def diminish(self) -> None:
"""Diminish all notes in track."""
def get_tuning(self) -> Any:
"""
Get instrument tuning.
Returns:
Tuning object if instrument has tuning
"""
def set_tuning(self, tuning: Any) -> None:
"""
Set instrument tuning.
Parameters:
- tuning: Tuning object
"""
def test_integrity(self) -> bool:
"""
Test track integrity.
Returns:
True if track structure is valid
"""Represents a complete musical composition containing multiple tracks with metadata.
class Composition:
"""Complete musical composition with multiple tracks."""
def __init__(self):
"""Create Composition object."""
@property
def title(self) -> str:
"""Composition title."""
@property
def subtitle(self) -> str:
"""Composition subtitle."""
@property
def author(self) -> str:
"""Author name."""
@property
def email(self) -> str:
"""Author email."""
def empty(self) -> None:
"""Empty composition of all tracks."""
def reset(self) -> None:
"""Reset composition to initial state."""
def add_track(self, track: Track) -> None:
"""
Add track to composition.
Parameters:
- track: Track object to add
"""
def add_note(self, note: Union[str, Note]) -> None:
"""
Add note to first track.
Parameters:
- note: Note to add
"""
def set_title(self, title: str = "Untitled", subtitle: str = "") -> None:
"""
Set composition title and subtitle.
Parameters:
- title: Main title
- subtitle: Subtitle
"""
def set_author(self, author: str = "", email: str = "") -> None:
"""
Set author information.
Parameters:
- author: Author name
- email: Author email
"""Represents a suite containing multiple compositions.
class Suite:
"""Suite containing multiple compositions."""
def __init__(self):
"""Create Suite object."""
def add_composition(self, composition: Composition) -> None:
"""
Add composition to suite.
Parameters:
- composition: Composition object to add
"""
def set_author(self, author: str, email: str = "") -> None:
"""
Set author information.
Parameters:
- author: Author name
- email: Author email
"""
def set_title(self, title: str, subtitle: str = "") -> None:
"""
Set suite title and subtitle.
Parameters:
- title: Main title
- subtitle: Subtitle
"""Classes representing various musical instruments with range validation and specific capabilities.
class Instrument:
"""Base instrument class."""
def __init__(self):
"""Create Instrument object."""
def set_range(self, range: Tuple[Note, Note]) -> None:
"""
Set instrument range.
Parameters:
- range: Tuple of (lowest_note, highest_note)
"""
def note_in_range(self, note: Note) -> bool:
"""
Check if note is in instrument range.
Parameters:
- note: Note to check
Returns:
True if note is in range
"""
def notes_in_range(self, notes: List[Note]) -> bool:
"""
Check if all notes are in range.
Parameters:
- notes: List of notes to check
Returns:
True if all notes are in range
"""
def can_play_notes(self, notes: List[Note]) -> bool:
"""
Check if instrument can play notes.
Parameters:
- notes: List of notes to check
Returns:
True if instrument can play all notes
"""
class Piano(Instrument):
"""Piano instrument with 88-key range."""
def __init__(self):
"""Create Piano object with standard range."""
class Guitar(Instrument):
"""Guitar instrument with standard tuning."""
def __init__(self):
"""Create Guitar object with standard tuning."""
class MidiInstrument(Instrument):
"""Generic MIDI instrument."""
def __init__(self, name: str = ""):
"""
Create MIDI instrument.
Parameters:
- name: Instrument name
"""
class MidiPercussionInstrument(MidiInstrument):
"""MIDI percussion instrument with drum methods."""
def __init__(self):
"""Create MIDI percussion instrument."""
def acoustic_bass_drum(self) -> Note:
"""Return acoustic bass drum note."""
def snare(self) -> Note:
"""Return snare drum note."""
def hi_hat(self) -> Note:
"""Return hi-hat note."""
def crash_cymbal(self) -> Note:
"""Return crash cymbal note."""
def ride_cymbal(self) -> Note:
"""Return ride cymbal note."""
def open_hi_hat(self) -> Note:
"""Return open hi-hat note."""
def closed_hi_hat(self) -> Note:
"""Return closed hi-hat note."""
# Additional percussion methods available...from mingus.containers import Note
# Create notes
note1 = Note("C", 4) # Middle C
note2 = Note("F#", 5, velocity=80, channel=1)
# Manipulate notes
note1.transpose("5") # Transpose up a fifth to G
note1.octave_up() # Move to octave 5
# Convert to frequency
freq = note1.to_hertz() # Get frequency in Hz
print(f"G5 frequency: {freq} Hz")from mingus.containers import NoteContainer
# Create chord from shorthand
chord = NoteContainer()
chord.from_chord("CM7") # C major 7th chord
# Analyze chord
chord_name = chord.determine() # Returns chord name
print(f"Chord: {chord_name}")
# Manipulate chord
chord.transpose("2") # Transpose up a whole step
chord.sort() # Sort notes by pitchfrom mingus.containers import Bar, Track, Composition
# Create a bar with notes
bar = Bar("C", (4, 4)) # 4/4 time in C major
bar.place_notes("C", 4) # Quarter note C
bar.place_notes(["E", "G"], 4) # Quarter note E and G together
bar.place_rest(2) # Half rest
# Create track and composition
track = Track()
track.add_bar(bar)
composition = Composition()
composition.add_track(track)
composition.set_title("Simple Melody")Install with Tessl CLI
npx tessl i tessl/pypi-mingus