Source code for mutwo.music_events.music
"""Event classes which are designated for musical usage."""
import typing
from mutwo import core_events
from mutwo import core_constants
from mutwo import music_events
from mutwo import music_parameters
__all__ = ("NoteLike",)
PitchOrPitchSequence = (
music_parameters.abc.Pitch | typing.Sequence | core_constants.Real | None
)
Volume = music_parameters.abc.Volume | core_constants.Real | str
GraceNotes = core_events.Consecution[core_events.SimpleEvent]
[docs]class NoteLike(core_events.SimpleEvent):
""":class:`NoteLike` represents traditional discreet musical objects.
:param pitch_list: The pitch or pitches of the event. This can
be a pitch object (any class that inherits from ``mutwo.music_parameters.abc.Pitch``)
or a list of pitch objects. Furthermore mutwo supports syntactic sugar
to convert other objects on the fly to pitch objects: Atring can be
read as pitch class names to build
:class:`mutwo.music_parameters.WesternPitch` objects or as ratios to
build :class:`mutwo.music_parameters.JustIntonationPitch` objects.
Fraction will also build :class:`mutwo.music_parameters.JustIntonationPitch`
objects. Other numbers (integer and float) will be read as pitch class numbers
to make :class:`mutwo.music_parameters.WesternPitch` objects.
:param duration: The duration of ``NoteLike``. This can be any number.
The unit of the duration is up to the interpretation of the user and the
respective converter routine that will be used.
:param volume: The volume of the event. Can either be a object of
:mod:`mutwo.music_parameters.abc.Volume`, a number or a string. If the number
ranges from 0 to 1, mutwo automatically generates a
:class:`mutwo.music_parameters.DirectVolume` object (and the number
will be interpreted as the amplitude). If the
number is smaller than 0, automatically generates a
:class:`mutwo.music_parameters.volumes.DecibelVolume` object (and the number
will be interpreted as decibel). If the argument is a string,
`mutwo` will try to initialise a :class:`mutwo.music_parameters.volumes.WesternVolume`
object.
:param grace_note_consecution:
:type grace_note_consecution: core_events.Consecution[NoteLike]
:param after_grace_note_consecution:
:type after_grace_note_consecution: core_events.Consecution[NoteLike]
:param playing_indicator_collection: A :class:`~mutwo.music_parameters.playing_indicator_collection.PlayingIndicatorCollection`.
Playing indicators alter the sound of :class:`NoteLike` (e.g.
tremolo, fermata, pizzicato).
:type playing_indicator_collection: music_parameters.playing_indicator_collection.PlayingIndicatorCollection
:param notation_indicator_collection: A :class:`~mutwo.music_parameters.notation_indicator_collection.NotationIndicatorCollection`.
Notation indicators alter the visual representation of :class:`NoteLike`
(e.g. ottava, clefs) without affecting the resulting sound.
:type notation_indicator_collection: music_parameters.notation_indicator_collection.NotationIndicatorCollection
:param lyric:
:type lyric: core_parameters.abc.Lyric
:param instrument_list: If an event is played with one or more specifc
:class:`mutwo.music_parameters.abc.Instrument`, these instruments can be
assigned here. Default is an empty list.
:type instrument_list: list[music_parameters.abc.Instrument]
``mutwo.music`` doesn't differentiate between Tones, Chords and
Rests, but rather simply implements one general class which can
represent any of the mentioned definitions (e.g. a `NoteLike` object
with several pitches may be called a 'Chord' and a `NoteLike` object
with only one pitch may be called a 'Tone').
**Example:**
>>> from mutwo import music_parameters
>>> from mutwo import music_events
>>> tone = music_events.NoteLike(music_parameters.WesternPitch('a'), 1, 1)
>>> other_tone = music_events.NoteLike('3/2', 1, 0.5)
>>> chord = music_events.NoteLike(
... [music_parameters.WesternPitch('a'), music_parameters.JustIntonationPitch('3/2')], 1, 1
... )
>>> other_chord = music_events.NoteLike('c4 dqs3 10/7', 1, 3)
"""
def __init__(
self,
pitch_list: PitchOrPitchSequence = [],
duration: core_constants.DurationType = 1,
volume: Volume = "mf",
grace_note_consecution: typing.Optional[GraceNotes] = None,
after_grace_note_consecution: typing.Optional[GraceNotes] = None,
playing_indicator_collection: typing.Optional[
music_parameters.PlayingIndicatorCollection
] = None,
notation_indicator_collection: typing.Optional[
music_parameters.NotationIndicatorCollection
] = None,
lyric: music_parameters.abc.Lyric = music_parameters.DirectLyric(""),
instrument_list: list[music_parameters.abc.Instrument] = [],
):
self.pitch_list = pitch_list
self.volume = volume
super().__init__(duration)
self.grace_note_consecution = (
grace_note_consecution or core_events.Consecution([])
)
self.after_grace_note_consecution = (
after_grace_note_consecution or core_events.Consecution([])
)
self.playing_indicator_collection = (
playing_indicator_collection
or music_events.configurations.DEFAULT_PLAYING_INDICATORS_COLLECTION_CLASS()
)
self.notation_indicator_collection = (
notation_indicator_collection
or music_events.configurations.DEFAULT_NOTATION_INDICATORS_COLLECTION_CLASS()
)
self.lyric = lyric
self.instrument_list = instrument_list
# ###################################################################### #
# properties #
# ###################################################################### #
@property
def _parameter_to_print_tuple(self) -> tuple[str, ...]:
"""Return tuple of attribute names which shall be printed for repr."""
return tuple(
attribute
for attribute in self._parameter_to_compare_tuple
if attribute
# Avoid too verbose and long attributes
not in (
"playing_indicator_collection",
"notation_indicator_collection",
"grace_note_consecution",
"after_grace_note_consecution",
)
)
@property
def pitch_list(self) -> typing.Any:
"""The pitch or pitches of the event."""
return self._pitch_list
@pitch_list.setter
def pitch_list(self, pitch_list: typing.Any):
# make sure pitch_list always become assigned to a list of pitches,
# to be certain of the returned type
if not isinstance(pitch_list, str) and isinstance(pitch_list, typing.Iterable):
parsed_pitch_list = []
for pitch in pitch_list:
parsed_pitch_list.extend(
music_events.configurations.UNKNOWN_OBJECT_TO_PITCH_LIST(pitch)
)
pitch_list = parsed_pitch_list
else:
pitch_list = music_events.configurations.UNKNOWN_OBJECT_TO_PITCH_LIST(
pitch_list
)
self._pitch_list = pitch_list
@property
def volume(self) -> typing.Any:
"""The volume of the event."""
return self._volume
@volume.setter
def volume(self, volume: typing.Any):
self._volume = music_events.configurations.UNKNOWN_OBJECT_TO_VOLUME(volume)
@property
def grace_note_consecution(self) -> GraceNotes:
""":class:`core_events.Consecution` before :class:`NoteLike`"""
return self._grace_note_consecution
@grace_note_consecution.setter
def grace_note_consecution(
self,
grace_note_consecution: GraceNotes | core_events.SimpleEvent,
):
self._grace_note_consecution = (
music_events.configurations.UNKNOWN_OBJECT_TO_GRACE_NOTE_SEQUENTIAL_EVENT(
grace_note_consecution
)
)
@property
def after_grace_note_consecution(self) -> GraceNotes:
""":class:`core_events.Consecution` after :class:`NoteLike`"""
return self._after_grace_note_consecution
@after_grace_note_consecution.setter
def after_grace_note_consecution(
self, after_grace_note_consecution: GraceNotes | core_events.SimpleEvent
):
self._after_grace_note_consecution = (
music_events.configurations.UNKNOWN_OBJECT_TO_GRACE_NOTE_SEQUENTIAL_EVENT(
after_grace_note_consecution
)
)