"""Annotation classes.
This module defines the annotation classes of MusPy,
which represent expression markings present in music.
Classes
-------
- Arpeggio
- Articulation
- Bend
- ChordLine
- ChordSymbol
- Dynamic
- Fermata
- GlissandoSpanner
- HairPinSpanner
- Notehead
- Ornament
- OttavaSpanner
- PedalSpanner
- Point
- RehearsalMark
- SlurSpanner
- Spanner
- Subtype
- SubtypeSpanner
- Symbol
- TechAnnotation
- TempoSpanner
- Text
- TextSpanner
- Tremolo
- TremoloBar
- TrillSpanner
- VibratoSpanner
"""
from collections import OrderedDict
from typing import Any, List
from .base import Base, ComplexBase
from .classes import DEFAULT_VELOCITY
__all__ = [
"Arpeggio",
"Articulation",
"Bend",
"ChordLine",
"ChordSymbol",
"Dynamic",
"Fermata",
"GlissandoSpanner",
"HairPinSpanner",
"Notehead",
"Ornament",
"OttavaSpanner",
"PedalSpanner",
"Point",
"RehearsalMark",
"SlurSpanner",
"Spanner",
"Subtype",
"SubtypeSpanner",
"Symbol",
"TechAnnotation",
"TempoSpanner",
"Text",
"TextSpanner",
"Tremolo",
"TremoloBar",
"TrillSpanner",
"VibratoSpanner",
]
# pylint: disable=super-init-not-called
[docs]class Text(Base):
"""A container for text.
Meant to be stored as an annotation, so the class itself has no timestamp (the timestamp is stored in the annotation object).
Attributes
----------
text : str
The text contained in the text element.
is_system : bool, default: False
Is this text system-wide (True) or just for a specific staff (False)?
style : str, optional
The style of the text element.
"""
_attributes = OrderedDict([("text", str), ("is_system", bool), ("style", str)])
_optional_attributes = ["is_system", "style"]
def __init__(self, text: str, is_system: bool = False, style: str = None):
self.text = "" if text is None else text
self.is_system = bool(is_system)
self.style = style
[docs]class Subtype(Base):
"""A container for objects with the a subtype attribute.
Attributes
----------
subtype : Any
The subtype attribute.
"""
_attributes = OrderedDict([("subtype", object)])
def __init__(self, subtype):
self.subtype = subtype
[docs]class RehearsalMark(Text):
"""A container for rehearsal marks.
Attributes
----------
text : str
The text contained in the text element.
is_system : bool, default: True
Is this text system-wide (True) or just for a specific staff (False)?
style : str, optional
The style of the text.
"""
_attributes = OrderedDict([("text", str), ("is_system", bool), ("style", str)])
_optional_attributes = ["is_system", "style"]
def __init__(self, text: str, is_system: bool = True, style: str = None):
super().__init__(text = text, is_system = is_system, style = style)
[docs]class ChordSymbol(Text):
"""A container for chord symbols.
Attributes
----------
root_str : str
Root pitch as a string, useful for distinguishing, e.g., C# and Db.
name : str, default: 'Maj'
The text contained in the chord symbol element.
text : str, optional
The full text contained in the chord symbol.
is_system : bool, default: False
Is this text system-wide (True) or just for a specific staff (False)?
style : str, optional
The style of the text.
"""
_attributes = OrderedDict([("root_str", str), ("name", str), ("text", str), ("is_system", bool), ("style", str)])
_optional_attributes = ["name", "text", "is_system", "style"]
def __init__(self, root_str: str, name: str = "Maj", text: str = None, is_system: bool = False, style: str = None):
super().__init__(text = root_str + (name if name else "") if text is None else text, is_system = is_system, style = style)
self.root_str = root_str
self.name = name
[docs]class TechAnnotation(Text):
"""A container for technical annotations.
Attributes
----------
text : str
The text contained in the text element.
tech_type : str, optional
The type of technical annotation to play.
is_system : bool, default: False
Is this text system-wide (True) or just for a specific staff (False)?
style : str, optional
The style of the text.
"""
_attributes = OrderedDict([("text", str), ("tech_type", str), ("is_system", bool), ("style", str)])
_optional_attributes = ["tech_type", "is_system", "style"]
def __init__(self, text: str, tech_type: str = None, is_system: bool = False, style: str = None):
super().__init__(text = text, is_system = is_system, style = style)
self.tech_type = tech_type
[docs]class Dynamic(Subtype):
"""A container for dynamic markings.
Attributes
----------
subtype : str
The type of dynamic.
velocity : int, default: `muspy.DEFAULT_VELOCITY` (64)
The velocity associated with the dynamic marking.
"""
_attributes = OrderedDict([("subtype", str), ("velocity", int)])
_optional_attributes = ["velocity"]
def __init__(self, subtype: str, velocity: int = DEFAULT_VELOCITY):
super().__init__(subtype = subtype)
self.velocity = velocity
[docs]class Fermata(Subtype):
"""A container for fermatas.
Meant to be stored as an annotation, so the class itself has no timestamp (the timestamp is stored in the annotation object).
Attributes
----------
is_fermata_above : bool, default: True
Whether this fermata is above or below the note to which it applies.
subtype : str, optional
The subtype of fermata contained in the text element.
"""
_attributes = OrderedDict([("is_fermata_above", bool), ("subtype", str)])
_optional_attributes = ["is_fermata_above", "subtype"]
def __init__(self, is_fermata_above: bool = True, subtype: str = None):
self.is_fermata_above = bool(is_fermata_above)
if subtype is None:
subtype = "fermata above" if self.is_fermata_above else "fermata below"
super().__init__(subtype = subtype)
[docs]class Arpeggio(Subtype):
"""A container for arpeggios.
Attributes
----------
subtype : str, default: 'default'
Arpeggio subtype.
"""
_attributes = OrderedDict([("subtype", str)])
_optional_attributes = ["subtype"]
def __init__(self, subtype: str = "default"):
super().__init__(subtype = subtype)
[docs]class Tremolo(Subtype):
"""A container for tremolos.
Attributes
----------
subtype : str, default: 'r8'
Tremolo subtype.
"""
_attributes = OrderedDict([("subtype", str)])
_optional_attributes = ["subtype"]
def __init__(self, subtype: str = "r8"):
super().__init__(subtype = subtype)
[docs]class ChordLine(Subtype):
"""A container for MuseScore ChordLines.
Attributes
----------
subtype : str, default: 'fall'
Subtype of the ChordLine.
is_straight : bool, default: False
Is the ChordLine straight?
"""
_attributes = OrderedDict([("subtype", str), ("is_straight", bool)])
_optional_attributes = ["subtype", "is_straight"]
def __init__(self, subtype: str = "fall", is_straight: bool = False):
super().__init__(subtype = subtype)
self.is_straight = bool(is_straight)
[docs]class Ornament(Subtype):
"""A container for ornaments.
Attributes
----------
subtype : str
Ornament subtype.
"""
_attributes = OrderedDict([("subtype", str)])
def __init__(self, subtype: str):
super().__init__(subtype = subtype)
[docs]class Articulation(Subtype):
"""A container for articulations.
Attributes
----------
subtype : str
Articulation subtype.
"""
_attributes = OrderedDict([("subtype", str)])
def __init__(self, subtype: str):
super().__init__(subtype = subtype)
[docs]class Notehead(Subtype):
"""A container for noteheads.
Attributes
----------
subtype : str
Notehead subtype.
"""
_attributes = OrderedDict([("subtype", str)])
def __init__(self, subtype: str):
super().__init__(subtype = subtype)
[docs]class Symbol(Subtype):
"""A container for symbols.
Attributes
----------
subtype : str
Symbol subtype.
"""
_attributes = OrderedDict([("subtype", str)])
def __init__(self, subtype: str):
super().__init__(subtype = subtype)
[docs]class Point(Base):
"""A container for MuseScore Point objects.
Attributes
----------
time : int
The time of the point (in time steps).
pitch : int
The pitch of the point.
vibrato : int, default: 0
The vibrato.
"""
_attributes = OrderedDict([("time", int), ("pitch", int), ("vibrato", int)])
_optional_attributes = ["vibrato"]
def __init__(self, time: int, pitch: int, vibrato: int = 0):
self.time = int(time)
self.pitch = int(pitch)
self.vibrato = int(vibrato)
[docs]class Bend(ComplexBase):
"""A container for bends.
Attributes
----------
points : List[:class:`muspy.Point`]
List of points that make up the bend.
"""
_attributes = OrderedDict([("points", Point)])
_list_attributes = ["points"]
def __init__(self, points: List[Point]):
self.points = points
[docs]class TremoloBar(Bend):
"""A container for MuseScore TremoloBar objects.
Attributes
----------
points : List[:class:`muspy.Point`]
List of points that make up the TremoloBar.
"""
_attributes = OrderedDict([("points", Point)])
_list_attributes = ["points"]
def __init__(self, points: List[Point]):
super().__init__(points = points)
[docs]class Spanner(Base):
"""A parent-class container for MuseScore Spanners.
Meant to be stored as an annotation, so the class itself has no timestamp (the timestamp is stored in the annotation object).
Attributes
----------
duration : int
Duration of spanner, in time steps.
"""
_attributes = OrderedDict([("duration", int)])
def __init__(self, duration: int):
self.duration = duration
[docs]class SubtypeSpanner(Subtype, Spanner):
"""A container for spanners whose only attribute is a subtype.
Attributes
----------
duration : int
Duration of spanner, in time steps.
subtype : Any
Subtype.
"""
_attributes = OrderedDict([("duration", int), ("subtype", object)])
def __init__(self, duration: int, subtype: object):
Subtype.__init__(self = self, subtype = subtype)
Spanner.__init__(self = self, duration = duration)
[docs]class TempoSpanner(SubtypeSpanner):
"""A container for spanners relating to a tempo change.
Attributes
----------
duration : int
Duration of spanner, in time steps.
subtype : str
Type of tempo change.
"""
_attributes = OrderedDict([("duration", int), ("subtype", str)])
def __init__(self, duration: int, subtype: str):
super().__init__(duration = duration, subtype = subtype)
[docs]class TextSpanner(Text, Spanner):
"""A container for text that spans a specific duration.
Attributes
----------
duration : int
Duration of spanner, in time steps.
text : str
The text contained in the text element.
is_system : bool, default: False
Is this text system-wide (True) or just for a specific staff (False)?
style : str, optional
The style of the text.
"""
_attributes = OrderedDict([("duration", int), ("text", str), ("is_system", bool), ("style", str)])
_optional_attributes = ["is_system", "style"]
def __init__(self, duration: int, text: str, is_system: bool = False, style: str = None):
Text.__init__(self = self, text = text, is_system = is_system, style = style)
Spanner.__init__(self = self, duration = duration)
[docs]class HairPinSpanner(SubtypeSpanner):
"""A container for hairpins (crescendos, decrescendos).
Attributes
----------
duration : int
Duration of spanner, in time steps.
subtype : str, optional
The text associated with the hairpin spanner.
hairpin_type : int, default: -1
The type of hairpin found within the MusicXML element.
"""
_attributes = OrderedDict([("duration", int), ("subtype", str), ("hairpin_type", int)])
_optional_attributes = ["subtype", "hairpin_type"]
def __init__(self, duration: int, subtype: str = None, hairpin_type: int = -1):
super().__init__(duration = duration, subtype = subtype)
self.hairpin_type = hairpin_type
[docs]class SlurSpanner(SubtypeSpanner):
"""A container for slurs.
Attributes
----------
duration : int
Duration of spanner, in time steps.
is_slur : bool, default: True
Is this object a slur (True), meaning it connects different
pitches, or a tie (False), meaning it connects the same pitch?
subtype : str, optional
If not provided, `subtype` is set to 'slur' or 'tie', depending
on the `is_slur` argument.
"""
_attributes = OrderedDict([("duration", int), ("is_slur", bool), ("subtype", str)])
_optional_attributes = ["is_slur", "subtype"]
def __init__(self, duration: int, is_slur: bool = True, subtype: str = None):
self.is_slur = bool(is_slur)
if subtype is None:
subtype = "slur" if self.is_slur else "tie"
super().__init__(duration = duration, subtype = subtype)
[docs]class PedalSpanner(Spanner):
"""A container for pedal markings.
Attributes
----------
duration : int
Duration of spanner, in time steps.
"""
_attributes = OrderedDict([("duration", int)])
def __init__(self, duration: int):
super().__init__(duration = duration)
[docs]class TrillSpanner(SubtypeSpanner):
"""A container for trill spanners.
Attributes
----------
duration : int
Duration of spanner, in time steps.
subtype : str, default: 'trill'
Subtype of trill.
ornament : str, optional
Subtype of ornament associated with the trill.
"""
_attributes = OrderedDict([("duration", int), ("subtype", str), ("ornament", str)])
_optional_attributes = ["subtype", "ornament"]
def __init__(self, duration: int, subtype: str = "trill", ornament: str = None):
super().__init__(duration = duration, subtype = subtype)
self.ornament = ornament
[docs]class VibratoSpanner(SubtypeSpanner):
"""A container for MuseScore Vibrato elements.
Attributes
----------
duration : int
Duration of spanner, in time steps
subtype : str, default: 'vibratoSawtooth'
Subtype of vibrato
"""
_attributes = OrderedDict([("duration", int), ("subtype", str)])
_optional_attributes = ["subtype"]
def __init__(self, duration: int, subtype: str = "vibratoSawtooth"):
super().__init__(duration = duration, subtype = subtype)
[docs]class GlissandoSpanner(SubtypeSpanner):
"""A container for glissando markings.
Attributes
----------
duration : int
Duration of spanner, in time steps.
is_wavy : bool, optional, default: False
Is this Glissano wavy (True) or straight (False)?
subtype : str, optional, default: 'straight'
If not provided, `subtype` is set to 'wavy' or 'straight', depending
on the `is_wavy` argument.
"""
_attributes = OrderedDict([("duration", int), ("is_wavy", bool), ("subtype", str)])
_optional_attributes = ["is_wavy", "subtype"]
def __init__(self, duration: int, is_wavy: bool = False, subtype: str = None):
self.is_wavy = bool(is_wavy)
if subtype is None:
subtype = "wavy" if self.is_wavy else "straight"
super().__init__(duration = duration, subtype = subtype)
[docs]class OttavaSpanner(SubtypeSpanner):
"""A container for ottava markings.
Attributes
----------
duration : int
Duration of spanner, in time steps.
subtype : str, optional, default: '8va'
Subtype of ottava.
"""
_attributes = OrderedDict([("duration", int), ("subtype", str)])
_optional_attributes = ["subtype"]
def __init__(self, duration: int, subtype: str = "8va"):
super().__init__(duration = duration, subtype = subtype)