Source code for musicscore.accidental

from typing import Optional, Union

from musicxml import XMLAccidental

from musicscore.musictree import MusicTree
from musicscore.xmlwrapper import XMLWrapper

__all__ = [
    "STANDARD",
    "FLAT",
    "SHARP",
    "ENHARMONIC",
    "FORCESHARP",
    "FORCEFLAT",
    "SIGNS",
    "Accidental",
]
#:
STANDARD = {
    0: ("C", 0, 0),
    0.5: ("C", 0.5, 0),
    1: ("C", 1, 0),
    1.5: ("C", 1.5, 0),
    2: ("D", 0, 0),
    2.5: ("E", -1.5, 0),
    3: ("E", -1, 0),
    3.5: ("E", -0.5, 0),
    4: ("E", 0, 0),
    4.5: ("E", 0.5, 0),
    5: ("F", 0, 0),
    5.5: ("F", 0.5, 0),
    6: ("F", 1, 0),
    6.5: ("F", 1.5, 0),
    7: ("G", 0, 0),
    7.5: ("A", -1.5, 0),
    8: ("A", -1, 0),
    8.5: ("A", -0.5, 0),
    9: ("A", 0, 0),
    9.5: ("B", -1.5, 0),
    10: ("B", -1, 0),
    10.5: ("B", -0.5, 0),
    11: ("B", 0, 0),
    11.5: ("C", -0.5, 1),
}

#:
FLAT = {
    0: ("C", 0, 0),
    0.5: ("D", -1.5, 0),
    1: ("D", -1, 0),
    1.5: ("D", -0.5, 0),
    2: ("D", 0, 0),
    2.5: ("E", -1.5, 0),
    3: ("E", -1, 0),
    3.5: ("E", -0.5, 0),
    4: ("E", 0, 0),
    4.5: ("F", -0.5, 0),
    5: ("F", 0, 0),
    5.5: ("G", -1.5, 0),
    6: ("G", -1, 0),
    6.5: ("G", -0.5, 0),
    7: ("G", 0, 0),
    7.5: ("A", -1.5, 0),
    8: ("A", -1, 0),
    8.5: ("A", -0.5, 0),
    9: ("A", 0, 0),
    9.5: ("B", -1.5, 0),
    10: ("B", -1, 0),
    10.5: ("B", -0.5, 0),
    11: ("B", 0, 0),
    11.5: ("C", -0.5, 1),
}

#:
SHARP = {
    0: ("C", 0, 0),
    0.5: ("C", 0.5, 0),
    1: ("C", 1, 0),
    1.5: ("C", 1.5, 0),
    2: ("D", 0, 0),
    2.5: ("D", 0.5, 0),
    3: ("D", 1, 0),
    3.5: ("D", 1.5, 0),
    4: ("E", 0, 0),
    4.5: ("E", 0.5, 0),
    5: ("F", 0, 0),
    5.5: ("F", 0.5, 0),
    6: ("F", 1, 0),
    6.5: ("F", 1.5, 0),
    7: ("G", 0, 0),
    7.5: ("G", 0.5, 0),
    8: ("G", 1, 0),
    8.5: ("G", 1.5, 0),
    9: ("A", 0, 0),
    9.5: ("A", 0.5, 0),
    10: ("A", 1, 0),
    10.5: ("A", 1.5, 0),
    11: ("B", 0, 0),
    11.5: ("B", 0.5, 0),
}

#:
ENHARMONIC = {
    0: ("C", 0, 0),
    0.5: ("D", -1.5, 0),
    1: ("D", -1, 0),
    1.5: ("D", -0.5, 0),
    2: ("D", 0, 0),
    2.5: ("D", 0.5, 0),
    3: ("D", 1, 0),
    3.5: ("D", 1.5, 0),
    4: ("E", 0, 0),
    4.5: ("F", -0.5, 0),
    5: ("F", 0, 0),
    5.5: ("G", -1.5, 0),
    6: ("G", -1, 0),
    6.5: ("G", -0.5, 0),
    7: ("G", 0, 0),
    7.5: ("G", 0.5, 0),
    8: ("G", 1, 0),
    8.5: ("G", 1.5, 0),
    9: ("A", 0, 0),
    9.5: ("A", 0.5, 0),
    10: ("A", 1, 0),
    10.5: ("A", 1.5, 0),
    11: ("B", 0, 0),
    11.5: ("B", 0.5, 0),
}

#:
FORCESHARP = {
    0: ("B", 1, -1),
    0.5: ("B", 1.5, -1),
    1: ("B", 2, -1),
    1.5: ("C", 1.5, 0),
    2: ("C", 2, 0),
    2.5: ("D", 0.5, 0),
    3: ("D", 1, 0),
    3.5: ("D", 1.5, 0),
    4: ("D", 2, 0),
    4.5: ("E", 0.5, 0),
    5: ("E", 1, 0),
    5.5: ("E", 1.5, 0),
    6: ("E", 2, 0),
    6.5: ("F", 1.5, 0),
    7: ("F", 2, 0),
    7.5: ("G", 0.5, 0),
    8: ("G", 1, 0),
    8.5: ("G", 1.5, 0),
    9: ("G", 2, 0),
    9.5: ("A", 0.5, 0),
    10: ("A", 1, 0),
    10.5: ("A", 1.5, 0),
    11: ("A", 2, 0),
    11.5: ("B", 0.5, 0),
}

#:
FORCEFLAT = {
    0: ("D", -2, 0),
    0.5: ("D", -1.5, 0),
    1: ("D", -1, 0),
    1.5: ("D", -0.5, 0),
    2: ("E", -2, 0),
    2.5: ("E", -1.5, 0),
    3: ("F", -2, 0),
    3.5: ("F", -1.5, 0),
    4: ("F", -1, 0),
    4.5: ("F", -0.5, 0),
    5: ("G", -2, 0),
    5.5: ("G", -1.5, 0),
    6: ("G", -1, 0),
    6.5: ("G", -0.5, 0),
    7: ("A", -2, 0),
    7.5: ("A", -1.5, 0),
    8: ("A", -1, 0),
    8.5: ("A", -0.5, 0),
    9: ("B", -2, 0),
    9.5: ("B", -1.5, 0),
    10: ("C", -2, 1),
    10.5: ("C", -1.5, 1),
    11: ("C", -1, 1),
    11.5: ("C", -0.5, 1),
}

#:
SIGNS = {
    -2: "flat-flat",
    -1.5: "three-quarters-flat",
    -1: "flat",
    -0.5: "quarter-flat",
    0: "natural",
    0.5: "quarter-sharp",
    1: "sharp",
    1.5: "three-quarters-sharp",
    2: "double-sharp",
}


[docs]class Accidental(MusicTree, XMLWrapper): """ Parent type: :obj:`~musicscore.midi.Midi` Child type: None Accidental is the class for managing :obj:`musicscore.midi.Midi`'s accidental sign and its pitch parameters: step, alter, octave. The parameter mode ('standard', 'enharmonic', 'flat', 'sharp', 'force-flat', 'force-sharp') can be used to set different enharmonic variants of the same pitch. """ _ATTRIBUTES = {"mode", "show", "parent_midi"} XMLClass = XMLAccidental def __init__(self, mode="standard", show: Optional[bool] = None, **kwargs): super().__init__() self._xml_object = self.XMLClass(value_="natural", **kwargs) self._mode = None self._show = None self.show = show self.mode = mode def _update(self): self._update_parent_midi() self._update_xml_object() def _update_parent_midi(self): if self.parent_midi and self.parent_midi.value != 0: self.parent_midi._update_pitch_parameters() def _update_xml_object(self): if self.sign: self._xml_object.value_ = self.sign @XMLWrapper.xml_object.getter def xml_object(self) -> Optional[XMLClass]: """ If an attribute is not found directly in a :obj:`~musicscore.musictree.MusicTree` class which inherits this class, it wll be passed on to ``__get_attribute__`` and ``__set__attribute__`` methods of ``xml_object``. It can also use the short cut attributes of :obj:`~musicxml.xmlelement.xmlelement.XMLElement` to get or set the first child. :return: wrapped MusicXML element of type :obj:`XMLClass` """ if self.parent_midi and self.parent_midi.value == 0: return None if self.show is True: return self._xml_object elif self.show is False: return None @property def mode(self): """ permitted modes: ``standard``, ``flat``, ``sharp``, ``enharmonic``, ``force-sharp``, ``force-flat`` :return: accidental mode which corresponds to global variables :obj:`~musicscore.accidental.STANDARD`, :obj:`~musicscore.accidental.FLAT`, :obj:`~musicscore.accidental.SHARP`, :obj:`~musicscore.accidental.ENHARMONIC`, :obj:`~musicscore.accidental.FORCESHARP`, :obj:`~musicscore.accidental.FORCEFLAT` """ return self._mode @mode.setter def mode(self, value): permitted = ( "standard", "flat", "sharp", "enharmonic", "force-sharp", "force-flat", ) if value not in permitted: raise TypeError(f"accidental_mode.value {value} must be in {permitted}") self._mode = value self._update_xml_object() self._update_parent_midi() @property def parent_midi(self) -> "Midi": """ :return: The midi parent of Accidental in the :obj:`~musicscore.musictree.MusicTree` structure. It is equivalent to :obj:`up` or :obj:`get_parent()` :rtype: :obj:`musicscore.midi.Midi` """ return self.up @parent_midi.setter def parent_midi(self, val): val.add_child(self) @property def sign(self) -> Optional[str]: """ Converts ``alter`` parameter of :obj:`~get_pitch_parameters` into an actual ``sign`` depending on :obj:`~mode`. :obj:`~parent_midi` must be set first. :return: Possible values: ``flat-flat``, ``three-quarters-flat``, ``flat``, ``quarter-flat``, ``natural``, ``quarter-sharp``, ``sharp``, ``three-quarters-sharp``, ``double-sharp`` """ try: alter = self.get_pitch_parameters()[1] return SIGNS[alter] except TypeError: return None @property def show(self) -> bool: """ If ``False`` ``xml_object`` will be ``None`` and no accidental is shown in the :obj:`~musicscore.score.Score`. If ``True`` the accidental is shown. If the value of one of the following xml_object :obj:`~musicxml.xmlelement.xmlelement.XMLAccidental` properties:``self.parentheses``, ``self.editorial``. ``self.cautionary`` or ``self.bracket`` is set to yes, the accidental is always shown regardless of this property """ if "yes" in [self.parentheses, self.editorial, self.cautionary, self.bracket]: return True return self._show @show.setter def show(self, val): if val is not None and not isinstance(val, bool): raise TypeError if val != self._show: self._show = val try: self.up.up._update_xml_accidental() except AttributeError: pass
[docs] def get_pitch_parameters( self, midi_value: Optional[Union[int, float]] = None ) -> Optional[tuple]: """ :param: a valid midi value or ``None``. If ``midi_value == 0`` (for a rest) return value is ``None``. If ``midi_value is None`` and a :obj:`~parent_midi` exists, parent_midi's value will be used. :return: A tuple consisting of pitch step name, alter value and octave value: ``(step, alter, octave)`` .. seealso:: :obj:`~mode` """ if midi_value is None: if self.parent_midi: midi_value = self.parent_midi.value else: return None if midi_value == 0: return None if self.mode == "standard": output = STANDARD[midi_value % 12] elif self.mode == "enharmonic": output = ENHARMONIC[midi_value % 12] elif self.mode == "force-sharp": output = FORCESHARP[midi_value % 12] elif self.mode == "force-flat": output = FORCEFLAT[midi_value % 12] elif self.mode == "flat": output = FLAT[midi_value % 12] elif self.mode == "sharp": output = SHARP[midi_value % 12] else: raise ValueError return output[0], output[1], output[2] + (int(midi_value // 12)) - 1
def __copy__(self): return self.__class__(mode=self.mode, show=self.show)