from typing import Optional, Union
import abjad
from ._HarmonicParent import _HarmonicParent
[docs]class HarmonicNote(abjad.Note, _HarmonicParent):
r"""Creates a note with tweaked note head for harmonics. This is a child
class of |abjad.Note|.
Basic usage:
Usage is similar to |abjad.Note|:
>>> harm = auxjad.HarmonicNote(r"c''4")
>>> harm.style
"#'harmonic"
>>> abjad.show(harm)
.. docs::
\tweak style #'harmonic
c''4
.. figure:: ../_images/HarmonicNote-jslykzpz7en.png
And similarly to |abjad.Note|, pitch and duration can be input in
many different ways:
>>> harm1 = auxjad.HarmonicNote(r"c''4")
>>> harm2 = auxjad.HarmonicNote(r"c''", 1 / 4)
>>> harm3 = auxjad.HarmonicNote(12, 0.25)
>>> harm4 = auxjad.HarmonicNote(12, abjad.Duration(1, 4))
>>> staff = abjad.Staff([harm1, harm2, harm3, harm4])
>>> abjad.show(staff)
.. docs::
\new Staff
{
\tweak style #'harmonic
c''4
\tweak style #'harmonic
c''4
\tweak style #'harmonic
c''4
\tweak style #'harmonic
c''4
}
.. figure:: ../_images/HarmonicNote-kdx8pmkdspn.png
:attr:`style`:
When instantiating this class, use the keyword argument :attr:`style`
to set a different type of note head, such as ``"#'harmonic-mixed"``:
>>> harm = auxjad.HarmonicNote(r"c''4",
... style="#'harmonic-mixed",
... )
>>> harm.style
"#'harmonic-mixed"
>>> abjad.show(harm)
.. docs::
\tweak style #'harmonic-mixed
c''4
.. figure:: ../_images/HarmonicNote-z48i5il6vf.png
:attr:`~abjad.core.Note.Note.multiplier`:
Similarly to |abjad.Note|, this class can take multipliers:
>>> harm = auxjad.HarmonicNote(r"c''4",
... multiplier=(2, 3),
... )
>>> harm.multiplier
abjad.Multiplier(2, 3)
>>> abjad.show(harm)
.. docs::
\tweak style #'harmonic
c''4 * 2/3
.. figure:: ../_images/HarmonicNote-4qbhly2hfi.png
Properties:
All properties of |abjad.Note| are also available to be read. This
class also includes a new property named :attr:`style`:
>>> harm = auxjad.HarmonicNote(r"c''4")
>>> harm.written_pitch
"c''"
>>> harm.written_duration
1/4
>>> harm.style
"#'harmonic"
All these properties can be set to different values after
initialisation:
>>> harm.written_pitch = 18
>>> harm.written_duration = abjad.Duration(1, 8)
>>> harm.style = "#'harmonic-mixed"
>>> harm.written_pitch
"fs''"
>>> harm.written_duration
1/8
>>> harm.style
"#'harmonic-mixed"
Setting :attr:`style` to ``'flageolet'``:
To create a harmonic note with a regular note head and with a flageolet
circle above it, use the style ``'flageolet'``:
>>> harm = auxjad.HarmonicNote(r"c''1",
... style='flageolet',
... )
>>> harm.style
'flageolet'
>>> abjad.show(harm)
.. docs::
c''1
\flageolet
.. figure:: ../_images/HarmonicNote-4q2q7rz65lj.png
:attr:`markup`:
To add a markup expression to the harmonic note, use the :attr:`markup`
optional keyword argument, which takes strings. By default, the markup
position is above the harmonic note, but this can be overridden using
the keyword :attr:`direction`, which can take strings as well as
``abjad.Up`` and ``abjad.Down``:
>>> harm1 = auxjad.HarmonicNote(r"d''1")
>>> harm2 = auxjad.HarmonicNote(r"d''1",
... markup='III.',
... )
>>> harm3 = auxjad.HarmonicNote(r"d''1",
... markup='III.',
... direction=abjad.Down)
>>> staff = abjad.Staff([harm1, harm2, harm3])
>>> abjad.show(staff)
.. docs::
\new Staff
{
\tweak style #'harmonic
d''1
\once \override TextScript.parent-alignment-X = 0
\once \override TextScript.self-alignment-X = 0
\tweak style #'harmonic
d''1
^ \markup { III. }
\once \override TextScript.parent-alignment-X = 0
\once \override TextScript.self-alignment-X = 0
\tweak style #'harmonic
d''1
_ \markup { III. }
}
.. figure:: ../_images/HarmonicNote-v9uer4i864.png
Setting :attr:`markup` to ``None`` will remove the markup from the
note.
>>> harm = auxjad.HarmonicNote(r"d''1",
... markup='III.',
... )
>>> harm.markup = None
>>> abjad.show(harm)
.. docs::
\tweak style #'harmonic
d''1
.. figure:: ../_images/HarmonicNote-2gqky0o8dgt.png
:attr:`centre_markup`:
When a markup expression is added to the harmonic note by using the
:attr:`markup` optional keyword argument, it will be automatically
centred above the note (as the main purpose of this markup is to show
string numbers). To disable this behaviour, set :attr:`centre_markup`
to ``False``. Compare:
>>> harm1 = auxjad.HarmonicNote(r"d''1",
... markup='III.',
... )
>>> abjad.show(harm1)
.. docs::
\once \override TextScript.parent-alignment-X = 0
\once \override TextScript.self-alignment-X = 0
\tweak style #'harmonic
d''1
^ \markup { III. }
.. figure:: ../_images/HarmonicNote-Vb1lf8wt7O.png
>>> harm2 = auxjad.HarmonicNote(r"d''1",
... markup='III.',
... centre_markup=False,
... )
>>> abjad.show(harm2)
.. docs::
\tweak style #'harmonic
d''1
^ \markup { III. }
.. figure:: ../_images/HarmonicNote-ZxHdPOas1z.png
.. error::
If another markup is attached to the harmonic note, trying to set the
:attr:`markup` to ``None`` will raise an :exc:`Exception`:
>>> harm = auxjad.HarmonicNote(r"d''1")
>>> abjad.attach(abjad.Markup('test'), harm)
>>> harm.markup = 'III.'
>>> harm.markup = None
Exception: multiple indicators attached to client.
"""
### CLASS VARIABLES ###
__slots__ = ('_style',
'_direction',
'_markup',
'_centre_markup'
)
### INITIALISER ###
[docs] def __init__(self,
*arguments,
multiplier: Optional[abjad.typings.DurationTyping] = None,
tag: Optional[abjad.Tag] = None,
style: str = "#'harmonic",
markup: Optional[str] = None,
centre_markup: bool = True,
direction: Union[str, abjad.enums.VerticalAlignment] = 'up',
) -> None:
r'Initialises self.'
super().__init__(*arguments, multiplier=multiplier, tag=tag)
self.style = style
self._direction = direction
self.centre_markup = centre_markup
self.markup = markup
### PRIVATE METHODS ###
def _attach_centre_markup(self) -> None:
r'Attaches the centre markup tweaks.'
literal1 = abjad.LilyPondLiteral(
r'\once \override TextScript.parent-alignment-X = 0'
)
literal2 = abjad.LilyPondLiteral(
r'\once \override TextScript.self-alignment-X = 0'
)
abjad.attach(literal1, self)
abjad.attach(literal2, self)
def _detach_centre_markup(self) -> None:
r'Detaches the centre markup tweaks.'
literal1 = abjad.LilyPondLiteral(
r'\once \override TextScript.parent-alignment-X = 0'
)
literal2 = abjad.LilyPondLiteral(
r'\once \override TextScript.self-alignment-X = 0'
)
if abjad.get.indicator(self, literal1):
abjad.detach(literal1, self)
if abjad.get.indicator(self, literal2):
abjad.detach(literal2, self)
### PUBLIC PROPERTIES ###
@property
def style(self) -> str:
r'The style of the harmonic note head.'
return self._style
@style.setter
def style(self,
style: str,
) -> None:
if not isinstance(style, str):
raise TypeError("'style' must be 'str'")
self._style = style
if not self._style.endswith('flageolet'):
abjad.tweak(self._note_head).style = self._style
else:
flageolet = abjad.LilyPondLiteral(r'\flageolet',
format_slot='after',
)
abjad.attach(flageolet, self)
@property
def centre_markup(self) -> bool:
r"""Tweaks the markup of the harmonic note head to be centred or not
as LilyPond doesn't centralises markups above note heads by default.
"""
return self._centre_markup
@centre_markup.setter
def centre_markup(self,
centre_markup: bool,
) -> None:
if not isinstance(centre_markup, bool):
raise TypeError("'style' must be 'bool'")
self._centre_markup = centre_markup
@property
def markup(self) -> str:
r'The markup of the harmonic note head.'
return self._markup
@markup.setter
def markup(self,
markup: str,
) -> None:
if markup is not None:
if not isinstance(markup, str):
raise TypeError("'markup' must be 'str'")
self._markup = markup
markup = abjad.Markup(self._markup,
direction=self._direction,
)
abjad.attach(markup, self)
if self._centre_markup:
self._attach_centre_markup()
else:
self._detach_centre_markup()
else:
self._markup = markup
if abjad.get.indicator(self, abjad.Markup):
abjad.detach(abjad.Markup, self)
self._detach_centre_markup()