Esempio n. 1
0
    def dynamic_ordinal_to_dynamic_name(dynamic_ordinal):
        r'''Changes `dynamic_ordinal` to dynamic name.

        ..  container:: example

            **Example 1.** Negative values change to quiet dynamics:

            ::

                >>> Dynamic.dynamic_ordinal_to_dynamic_name(-5)
                'pppp'

        ..  container:: example

            **Example 2.** Negative infinity changes to niente:

            ::

                >>> negative_infinity = mathtools.NegativeInfinity()
                >>> Dynamic.dynamic_ordinal_to_dynamic_name(negative_infinity)
                'niente'

        Returns string.
        '''
        if dynamic_ordinal == mathtools.NegativeInfinity():
            return 'niente'
        else:
            return Dynamic._dynamic_ordinal_to_dynamic_name[dynamic_ordinal]
Esempio n. 2
0
 def __init__(
         self,
         operator_string='<',
         duration=mathtools.Infinity(),
 ):
     Inequality.__init__(
         self,
         operator_string=operator_string,
     )
     infinities = (
         mathtools.Infinity(),
         mathtools.NegativeInfinity(),
     )
     if duration not in infinities:
         duration = durationtools.Duration(duration)
         assert 0 <= duration
     self._duration = duration
Esempio n. 3
0
 def __init__(
         self,
         operator_string='<',
         length=mathtools.Infinity(),
 ):
     Inequality.__init__(
         self,
         operator_string=operator_string,
     )
     assert 0 <= length
     infinities = (
         mathtools.Infinity(),
         mathtools.NegativeInfinity(),
     )
     if length not in infinities:
         length = int(length)
     self._length = length
Esempio n. 4
0
from abjad.tools import systemtools
from abjad.tools import datastructuretools
#from abjad.tools import mathtools

# load constants into __builtins__ namespace
if six.PY3:
    import builtins
else:
    import __builtin__ as builtins

builtins.Less = datastructuretools.OrdinalConstant('value', -1, 'Less')
builtins.More = datastructuretools.OrdinalConstant('value', 1, 'More')
builtins.Exact = datastructuretools.OrdinalConstant('value', 0, 'Exact')
builtins.Left = datastructuretools.OrdinalConstant('x', -1, 'Left')
builtins.Right = datastructuretools.OrdinalConstant('x', 1, 'Right')
builtins.Center = datastructuretools.OrdinalConstant('y', 0, 'Center')
builtins.Up = datastructuretools.OrdinalConstant('y', 1, 'Up')
builtins.Down = datastructuretools.OrdinalConstant('y', -1, 'Down')
from abjad.tools import mathtools

builtins.Infinity = mathtools.Infinity()
builtins.NegativeInfinity = mathtools.NegativeInfinity()
del (builtins)
del (six)

systemtools.ImportManager.import_structured_package(
    __path__[0],
    globals(),
    delete_systemtools=False,
    ignored_names=['abjadbooktools'],
)
Esempio n. 5
0
class Dynamic(AbjadValueObject):
    r'''Dynamic.

    ..  container:: example

        Initializes from dynamic name:

        >>> voice = abjad.Voice("c'8 d'8 e'8 f'8")
        >>> dynamic = abjad.Dynamic('f')
        >>> abjad.attach(dynamic, voice[0])

        ..  docs::

            >>> abjad.f(voice)
            \new Voice
            {
                c'8
                \f
                d'8
                e'8
                f'8
            }

        >>> abjad.show(voice) # doctest: +SKIP

    ..  container:: example

        Initializes from other dynamic:

        >>> dynamic_1 = abjad.Dynamic('f')
        >>> dynamic_2 = abjad.Dynamic(dynamic_1)

        >>> dynamic_1
        Dynamic('f')

        >>> dynamic_2
        Dynamic('f')

    ..  container:: example

        Initializes niente:

        >>> dynamic = abjad.Dynamic('niente')
        >>> format(dynamic, 'lilypond')
        ''

    ..  container:: example

        Simultaneous dynamics in a single staff:

        >>> voice_1 = abjad.Voice("e'8 g'8 f'8 a'8")
        >>> abjad.attach(abjad.Dynamic('f'), voice_1[0], context='Voice')
        >>> abjad.attach(abjad.LilyPondLiteral(r'\voiceOne'), voice_1)
        >>> abjad.override(voice_1).dynamic_line_spanner.direction = abjad.Up
        >>> voice_2 = abjad.Voice("c'2")
        >>> abjad.attach(abjad.LilyPondLiteral(r'\voiceTwo'), voice_2)
        >>> abjad.attach(abjad.Dynamic('mf'), voice_2[0], context='Voice')
        >>> staff = abjad.Staff([voice_1, voice_2], is_simultaneous=True)
        >>> abjad.show(staff) # doctest: +SKIP

        ..  docs::

            >>> abjad.f(staff)
            \new Staff
            <<
                \new Voice
                \with
                {
                    \override DynamicLineSpanner.direction = #up
                }
                {
                    \voiceOne
                    e'8
                    \f
                    g'8
                    f'8
                    a'8
                }
                \new Voice
                {
                    \voiceTwo
                    c'2
                    \mf
                }
            >>

        >>> for leaf in abjad.select(staff).leaves():
        ...     leaf, abjad.inspect(leaf).get_effective(abjad.Dynamic)
        ...
        (Note("e'8"), Dynamic('f'))
        (Note("g'8"), Dynamic('f'))
        (Note("f'8"), Dynamic('f'))
        (Note("a'8"), Dynamic('f'))
        (Note("c'2"), Dynamic('mf'))

    '''

    ### CLASS VARIABLES ###

    __slots__ = (
        '_command',
        '_direction',
        '_hide',
        '_name',
        '_name_is_textual',
        '_ordinal',
        '_sforzando',
    )

    _composite_dynamic_name_to_steady_state_dynamic_name = {
        'fp': 'p',
        'sf': 'f',
        'sff': 'ff',
        'sfp': 'p',
        'sfpp': 'pp',
        'sffp': 'p',
        'sffpp': 'pp',
        'sfz': 'f',
        'sp': 'p',
        'spp': 'pp',
        'rfz': 'f',
    }

    _context = 'Voice'

    _dynamic_name_to_dynamic_ordinal = {
        'ppppp': -6,
        'pppp': -5,
        'ppp': -4,
        'pp': -3,
        'p': -2,
        'niente': mathtools.NegativeInfinity(),
        'mp': -1,
        'mf': 1,
        'f': 2,
        'ff': 3,
        'fff': 4,
        'ffff': 5,
        'fffff': 6,
    }

    _dynamic_names = (
        'ppppp',
        'pppp',
        'ppp',
        'pp',
        'p',
        'mp',
        'mf',
        'f',
        'ff',
        'fff',
        'ffff',
        'fffff',
        'fp',
        'sf',
        'sff',
        'sp',
        'spp',
        'sfz',
        'sffz',
        'sfffz',
        'sffp',
        'sffpp',
        'sfp',
        'sfpp',
        'rfz',
        'niente',
    )

    _dynamic_ordinal_to_dynamic_name = {
        -6: 'ppppp',
        -5: 'pppp',
        -4: 'ppp',
        -3: 'pp',
        -2: 'p',
        -1: 'mp',
        mathtools.NegativeInfinity(): 'niente',
        1: 'mf',
        2: 'f',
        3: 'ff',
        4: 'fff',
        5: 'ffff',
        6: 'fffff',
    }

    _format_slot = 'right'

    _lilypond_dynamic_commands = [
        _ for _ in _dynamic_names if not _ == 'niente'
    ]

    _lilypond_dynamic_alphabet = 'fmprsz'

    _persistent = True

    _to_width = {
        '"f"': 2,
        '"mf"': 3.5,
        '"mp"': 3.5,
        '"p"': 2,
        'sfz': 2.5,
    }

    ### INITIALIZER ###

    def __init__(
        self,
        name: typing.Union[str, 'Dynamic'] = 'f',
        command: str = None,
        direction: OrdinalConstant = None,
        hide: bool = None,
        name_is_textual: bool = None,
        ordinal: typing.Union[int, Infinity, NegativeInfinity] = None,
        sforzando: bool = None,
    ) -> None:
        if name is not None:
            assert isinstance(name, (str, type(self))), repr(name)
        if isinstance(name, type(self)):
            name_ = name.name
        elif isinstance(name, str):
            name_ = name
        if name_ == 'niente':
            if name_is_textual not in (None, True):
                raise Exception('niente dynamic name is always textual.')
            name_is_textual = True
        if not name_is_textual:
            for letter in name_.strip('"'):
                assert letter in self._lilypond_dynamic_alphabet, repr(letter)
        self._name = name_
        if command is not None:
            assert isinstance(command, str), repr(command)
            assert command.startswith('\\'), repr(command)
        self._command = command
        if direction is not None:
            assert direction in (Down, Up), repr(direction)
        self._direction = direction
        if hide is not None:
            hide = bool(hide)
        self._hide = hide
        if name_is_textual is not None:
            name_is_textual = bool(name_is_textual)
        self._name_is_textual = name_is_textual
        if ordinal is not None:
            assert isinstance(ordinal, (int, Infinity, NegativeInfinity))
        self._ordinal = ordinal
        if sforzando is not None:
            sforzando = bool(sforzando)
        self._sforzando = sforzando

    ### SPECIAL METHODS ###

    def __eq__(self, argument) -> bool:
        r'''Is true when ``argument`` equals dynamic.

        ..  container:: example

            >>> dynamic_1 = abjad.Dynamic('p')
            >>> dynamic_2 = abjad.Dynamic('p')
            >>> dynamic_3 = abjad.Dynamic('f')

            >>> dynamic_1 == dynamic_1
            True
            >>> dynamic_1 == dynamic_2
            True
            >>> dynamic_1 == dynamic_3
            False

            >>> dynamic_2 == dynamic_1
            True
            >>> dynamic_2 == dynamic_2
            True
            >>> dynamic_2 == dynamic_3
            False

            >>> dynamic_3 == dynamic_1
            False
            >>> dynamic_3 == dynamic_2
            False
            >>> dynamic_3 == dynamic_3
            True

        '''
        if not isinstance(argument, type(self)):
            return False
        if self.name == argument.name and self.ordinal == argument.ordinal:
            return True
        return False

    def __format__(self, format_specification='') -> str:
        r'''Formats dynamic.

        ..  container:: example

            Gets storage format:

            >>> dynamic = abjad.Dynamic('f')
            >>> print(format(dynamic))
            abjad.Dynamic('f')

            Gets LilyPond format:

            >>> dynamic = abjad.Dynamic('f')
            >>> print(format(dynamic, 'lilypond'))
            \f

        '''
        if format_specification == 'lilypond':
            if self.name == 'niente':
                return ''
            elif self.name.strip('"') not in self._lilypond_dynamic_commands:
                message = f'{self.name!r} is not a LilyPond dynamic command.'
                raise Exception(message)
            return self._get_lilypond_format()
        return super(
            Dynamic,
            self).__format__(format_specification=format_specification)

    def __hash__(self) -> int:
        r'''Hashes dynamic.
        '''
        return super(Dynamic, self).__hash__()

    ### PRIVATE PROPERTIES ###

    @property
    def _contents_repr_string(self):
        return repr(self._name)

    ### PRIVATE METHODS ###

    def _attachment_test_all(self, component_expression):
        import abjad
        if not isinstance(component_expression, abjad.Leaf):
            return False
        return True

    def _format_effort_dynamic(self):
        name = self.name.strip('"')
        before = {
            'f': -0.4,
            'm': -0.1,
            'p': -0.1,
            'r': -0.1,
            's': -0.3,
            'z': -0.2,
        }[name[0]]
        after = {
            'f': -0.2,
            'm': -0.1,
            'p': -0.25,
            'r': 0,
            's': 0,
            'z': -0.2,
        }[name[-1]]
        direction = self.direction
        direction = String.to_tridirectional_lilypond_symbol(direction)
        strings = []
        strings.append(f'{direction} #(make-dynamic-script')
        strings.append('    (markup')
        strings.append('        #:whiteout')
        strings.append('        #:line (')
        strings.append(
            '            #:general-align Y -2 #:normal-text #:larger "“"')
        strings.append(f'            #:hspace {before}')
        strings.append(f'            #:dynamic "{name}"')
        strings.append(f'            #:hspace {after}')
        strings.append(
            '            #:general-align Y -2 #:normal-text #:larger "”"')
        strings.append('            )')
        strings.append('        )')
        strings.append('    )')
        string = '\n'.join(strings)
        return string

    @staticmethod
    def _format_textual(direction, string):
        if direction is None:
            direction = Down
        direction = String.to_tridirectional_lilypond_symbol(direction)
        assert isinstance(string, str), repr(string)
        string = f'(markup #:whiteout #:normal-text #:italic "{string}")'
        string = f'{direction} #(make-dynamic-script {string})'
        return string

    def _get_format_specification(self):
        keywords = ['command', 'direction', 'hide']
        if self._ordinal is not None:
            keywords.append('ordinal')
        keywords.append('name_is_textual')
        if self._sforzando is not None:
            keywords.append('sforzando')
        return FormatSpecification(
            self,
            repr_is_indented=False,
            storage_format_args_values=[self.name],
            storage_format_is_indented=False,
            storage_format_kwargs_names=keywords,
        )

    def _get_lilypond_format(self):
        if self.command:
            return self.command
        if self.effort:
            return self._format_effort_dynamic()
        if self.name_is_textual:
            return self._format_textual(self.direction, self.name)
        return rf'\{self.name}'

    def _get_lilypond_format_bundle(self, component=None):
        bundle = LilyPondFormatBundle()
        if not self.hide:
            string = self._get_lilypond_format()
            bundle.right.articulations.append(string)
        return bundle

    ### PUBLIC PROPERTIES ###

    @property
    def command(self) -> typing.Optional[str]:
        r'''Gets explicit command.

        ..  container:: example

            >>> abjad.Dynamic('f', command=r'\sub_f').command
            '\\sub_f'

        Use to override LilyPond output when a custom dynamic has been defined
        in an external stylesheet. (In the example above, ``\sub_f`` is a
        nonstandard LilyPond dynamic. LilyPond will interpret the output above
        only when the command ``\sub_f`` is defined somewhere in an external
        stylesheet.)
        '''
        return self._command

    @property
    def context(self) -> str:
        r'''Returns (historically conventional) context ``'Voice'``.

        ..  container:: example

            >>> abjad.Dynamic('f').context
            'Voice'

        Class constant.

        Override with ``abjad.attach(..., context='...')``.
        '''
        return self._context

    @property
    def direction(self) -> typing.Optional[OrdinalConstant]:
        r'''Gets direction for effort dynamics only.

        ..  container:: example

            Effort dynamics default to down:

            >>> abjad.Dynamic('"f"').direction
            Down

            And may be overriden:

            >>> abjad.Dynamic('"f"', direction=abjad.Up).direction
            Up

        '''
        if self._direction is not None:
            return self._direction
        elif self.name == 'niente' or self.effort:
            return Down
        else:
            return None

    @property
    def effort(self) -> typing.Optional[bool]:
        r'''Is true when double quotes enclose dynamic.

        ..  container:: example

            >>> voice = abjad.Voice("c'4 r d' r e' r f' r")
            >>> abjad.attach(abjad.Dynamic('"pp"'), voice[0])
            >>> abjad.attach(abjad.Dynamic('"mp"'), voice[2])
            >>> abjad.attach(abjad.Dynamic('"mf"'), voice[4])
            >>> abjad.attach(abjad.Dynamic('"ff"'), voice[6])
            >>> abjad.override(voice).dynamic_line_spanner.staff_padding = 4
            >>> abjad.show(voice) # doctest: +SKIP

            ..  docs::

                >>> abjad.f(voice)
                \new Voice
                \with
                {
                    \override DynamicLineSpanner.staff-padding = #4
                }
                {
                    c'4
                    _ #(make-dynamic-script
                        (markup
                            #:whiteout
                            #:line (
                                #:general-align Y -2 #:normal-text #:larger "“"
                                #:hspace -0.1
                                #:dynamic "pp"
                                #:hspace -0.25
                                #:general-align Y -2 #:normal-text #:larger "”"
                                )
                            )
                        )
                    r4
                    d'4
                    _ #(make-dynamic-script
                        (markup
                            #:whiteout
                            #:line (
                                #:general-align Y -2 #:normal-text #:larger "“"
                                #:hspace -0.1
                                #:dynamic "mp"
                                #:hspace -0.25
                                #:general-align Y -2 #:normal-text #:larger "”"
                                )
                            )
                        )
                    r4
                    e'4
                    _ #(make-dynamic-script
                        (markup
                            #:whiteout
                            #:line (
                                #:general-align Y -2 #:normal-text #:larger "“"
                                #:hspace -0.1
                                #:dynamic "mf"
                                #:hspace -0.2
                                #:general-align Y -2 #:normal-text #:larger "”"
                                )
                            )
                        )
                    r4
                    f'4
                    _ #(make-dynamic-script
                        (markup
                            #:whiteout
                            #:line (
                                #:general-align Y -2 #:normal-text #:larger "“"
                                #:hspace -0.4
                                #:dynamic "ff"
                                #:hspace -0.2
                                #:general-align Y -2 #:normal-text #:larger "”"
                                )
                            )
                        )
                    r4
                }

        ..  container:: example

            >>> voice = abjad.Voice("c'4 r d' r e' r f' r")
            >>> abjad.attach(abjad.Dynamic('"sf"'), voice[0])
            >>> abjad.attach(abjad.Dynamic('"sfz"'), voice[2])
            >>> abjad.attach(abjad.Dynamic('"rf"'), voice[4])
            >>> abjad.attach(abjad.Dynamic('"rfz"'), voice[6])
            >>> abjad.override(voice).dynamic_line_spanner.staff_padding = 4
            >>> abjad.show(voice) # doctest: +SKIP

            ..  docs::

                >>> abjad.f(voice)
                \new Voice
                \with
                {
                    \override DynamicLineSpanner.staff-padding = #4
                }
                {
                    c'4
                    _ #(make-dynamic-script
                        (markup
                            #:whiteout
                            #:line (
                                #:general-align Y -2 #:normal-text #:larger "“"
                                #:hspace -0.3
                                #:dynamic "sf"
                                #:hspace -0.2
                                #:general-align Y -2 #:normal-text #:larger "”"
                                )
                            )
                        )
                    r4
                    d'4
                    _ #(make-dynamic-script
                        (markup
                            #:whiteout
                            #:line (
                                #:general-align Y -2 #:normal-text #:larger "“"
                                #:hspace -0.3
                                #:dynamic "sfz"
                                #:hspace -0.2
                                #:general-align Y -2 #:normal-text #:larger "”"
                                )
                            )
                        )
                    r4
                    e'4
                    _ #(make-dynamic-script
                        (markup
                            #:whiteout
                            #:line (
                                #:general-align Y -2 #:normal-text #:larger "“"
                                #:hspace -0.1
                                #:dynamic "rf"
                                #:hspace -0.2
                                #:general-align Y -2 #:normal-text #:larger "”"
                                )
                            )
                        )
                    r4
                    f'4
                    _ #(make-dynamic-script
                        (markup
                            #:whiteout
                            #:line (
                                #:general-align Y -2 #:normal-text #:larger "“"
                                #:hspace -0.1
                                #:dynamic "rfz"
                                #:hspace -0.2
                                #:general-align Y -2 #:normal-text #:larger "”"
                                )
                            )
                        )
                    r4
                }

        '''
        return bool(self.name) and self.name[0] == '"'

    @property
    def hide(self) -> typing.Optional[bool]:
        r'''Is true when dynamic should not appear in output (but should
        still determine effective dynamic).

        ..  container:: example

            >>> voice = abjad.Voice("c'4 d' e' f'")
            >>> abjad.attach(abjad.Dynamic('f'), voice[0]) 
            >>> abjad.attach(abjad.Dynamic('mf', hide=True), voice[2]) 
            >>> abjad.show(voice) # doctest: +SKIP

            >>> abjad.f(voice)
            \new Voice
            {
                c'4
                \f
                d'4
                e'4
                f'4
            }

            >>> for leaf in abjad.iterate(voice).leaves():
            ...     leaf, abjad.inspect(leaf).get_effective(abjad.Dynamic)
            ...
            (Note("c'4"), Dynamic('f'))
            (Note("d'4"), Dynamic('f'))
            (Note("e'4"), Dynamic('mf', hide=True))
            (Note("f'4"), Dynamic('mf', hide=True))

        '''
        return self._hide

    @property
    def name(self) -> str:
        r'''Gets name.

        ..  container:: example

            >>> abjad.Dynamic('f').name
            'f'

            >>> abjad.Dynamic('p').name
            'p'

            >>> abjad.Dynamic('sffz').name
            'sffz'

            >>> abjad.Dynamic('sffp').name
            'sffp'

            >>> abjad.Dynamic('"f"').name
            '"f"'

        ..  container:: example

            Niente dynamics format like this:

            >>> voice = abjad.Voice("c'4 r r c'4")
            >>> abjad.attach(abjad.Dynamic('p'), voice[0])
            >>> abjad.attach(abjad.Dynamic('niente'), voice[1])
            >>> abjad.attach(abjad.Dynamic('p'), voice[3])
            >>> abjad.override(voice).dynamic_line_spanner.staff_padding = 4
            >>> abjad.show(voice) # doctest: +SKIP

            ..  docs::

                >>> abjad.f(voice)
                \new Voice
                \with
                {
                    \override DynamicLineSpanner.staff-padding = #4
                }
                {
                    c'4
                    \p
                    r4
                    _ #(make-dynamic-script (markup #:whiteout #:normal-text #:italic "niente"))
                    r4
                    c'4
                    \p
                }

        '''
        return self._name

    @property
    def name_is_textual(self) -> typing.Optional[bool]:
        r'''Is true when name is textual.

        ..  container:: example

            >>> abjad.Dynamic('f').name_is_textual is None
            True

            >>> abjad.Dynamic('niente').name_is_textual
            True

            >>> dynamic = abjad.Dynamic('appena udibile', name_is_textual=True)
            >>> dynamic.name_is_textual
            True

        ..  container:: example

            Textual dynamics format like this when initialized without an
            explicit command:

            >>> voice = abjad.Voice("c'4 d' e' f'")
            >>> dynamic = abjad.Dynamic('appena udibile', name_is_textual=True)
            >>> abjad.attach(dynamic, voice[0])
            >>> abjad.override(voice).dynamic_line_spanner.staff_padding = 4
            >>> abjad.override(voice).dynamic_text.X_extent = (0, 0)
            >>> abjad.override(voice).dynamic_text.self_alignment_X = abjad.Left
            >>> abjad.show(voice) # doctest: +SKIP

            ..  docs::

                >>> abjad.f(voice)
                \new Voice
                \with
                {
                    \override DynamicLineSpanner.staff-padding = #4
                    \override DynamicText.X-extent = #'(0 . 0)
                    \override DynamicText.self-alignment-X = #left
                }
                {
                    c'4
                    _ #(make-dynamic-script (markup #:whiteout #:normal-text #:italic "appena udibile"))
                    d'4
                    e'4
                    f'4
                }

        ..  container:: example

            Textual dynamics format like this when initialized with an
            explicit command:

            >>> voice = abjad.Voice("c'4 d' e' f'")
            >>> dynamic = abjad.Dynamic(
            ...     'appena udibile',
            ...     command=r'\appena_udibile',
            ...     name_is_textual=True,
            ...     )
            >>> abjad.attach(dynamic, voice[0])

            Only LilyPond output is shown here because dynamic commands (like
            ``\appena_udibile`` shown here) are meant to be user-defined (and
            not included in Abjad):

            >>> abjad.f(voice)
            \new Voice
            {
                c'4
                \appena_udibile
                d'4
                e'4
                f'4
            }

        ..  container:: example

            REGRESSION. Textual names work with new:

            >>> dynamic = abjad.Dynamic('niente')
            >>> abjad.new(dynamic)
            Dynamic('niente', direction=Down, ordinal=NegativeInfinity, name_is_textual=True, sforzando=False)

            >>> dynamic = abjad.Dynamic('appena udibile', name_is_textual=True)
            >>> abjad.new(dynamic)
            Dynamic('appena udibile', name_is_textual=True, sforzando=False)

        '''
        return self._name_is_textual

    @property
    #def ordinal(self) -> typing.Union[int, Infinity, NegativeInfinity]:
    def ordinal(self):
        r'''Gets ordinal.

        ..  container:: example

            >>> abjad.Dynamic('f').ordinal
            2

            >>> abjad.Dynamic('p').ordinal
            -2

        ..  container:: example

            >>> abjad.Dynamic('niente').ordinal
            NegativeInfinity

        ..  container:: example

            >>> abjad.Dynamic('"f"').ordinal
            2

            >>> abjad.Dynamic('"p"').ordinal
            -2

        ..  container:: example

            User-defined ordinals:

            >>> barely_audible = abjad.Dynamic(
            ...     'barely audible',
            ...     name_is_textual=True,
            ...     ordinal=-99,
            ...     )
            >>> barely_audible.ordinal
            -99

            >>> extremely_loud = abjad.Dynamic(
            ...     'extremely loud',
            ...     name_is_textual=True,
            ...     ordinal=99,
            ...     )
            >>> extremely_loud.ordinal
            99

        ..  container:: example

            REGRESSION. Textual names without explicit ordinal return none:

            >>> dynamic = abjad.Dynamic('appena udibile', name_is_textual=True)
            >>> dynamic.ordinal is None
            True

        '''
        if self._ordinal is not None:
            return self._ordinal
        name = None
        if self.name:
            name = self.name.strip('"')
        if name in self._composite_dynamic_name_to_steady_state_dynamic_name:
            name = self._composite_dynamic_name_to_steady_state_dynamic_name[
                name]
        ordinal = self._dynamic_name_to_dynamic_ordinal.get(name)
        return ordinal

    @property
    def persistent(self) -> bool:
        r'''Is true.

        ..  container:: example

            >>> abjad.Dynamic('f').persistent
            True

        '''
        return self._persistent

    @property
    def sforzando(self) -> typing.Optional[bool]:
        r'''Is true when dynamic name begins in s- and ends in -z.

        ..  container:: example

            >>> abjad.Dynamic('f').sforzando
            False

            >>> abjad.Dynamic('sfz').sforzando
            True

            >>> abjad.Dynamic('sffz').sforzando
            True

            >>> abjad.Dynamic('sfp').sforzando
            False

            >>> abjad.Dynamic('sf').sforzando
            False

            >>> abjad.Dynamic('rfz').sforzando
            False

        Returns true or false.
        '''
        if self._sforzando is not None:
            return self._sforzando
        if (self.name and self.name.startswith('s')
                and self.name.endswith('z')):
            return True
        return False

    ### PUBLIC METHODS ###

    @staticmethod
    def composite_dynamic_name_to_steady_state_dynamic_name(name) -> str:
        r'''Changes composite `name` to steady state dynamic name.

        ..  container:: example

            >>> abjad.Dynamic.composite_dynamic_name_to_steady_state_dynamic_name('sfp')
            'p'

            >>> abjad.Dynamic.composite_dynamic_name_to_steady_state_dynamic_name('rfz')
            'f'

        '''
        return Dynamic._composite_dynamic_name_to_steady_state_dynamic_name[
            name]

    @staticmethod
    #def dynamic_name_to_dynamic_ordinal(name) -> typing.Union[
    #    int, Infinity, NegativeInfinity,
    #    ]:
    def dynamic_name_to_dynamic_ordinal(name):
        r'''Changes `name` to dynamic ordinal.

        ..  container:: example

            >>> abjad.Dynamic.dynamic_name_to_dynamic_ordinal('fff')
            4

            >>> abjad.Dynamic.dynamic_name_to_dynamic_ordinal('niente')
            NegativeInfinity

        '''
        try:
            return Dynamic._dynamic_name_to_dynamic_ordinal[name]
        except KeyError:
            name = Dynamic.composite_dynamic_name_to_steady_state_dynamic_name(
                name)
            return Dynamic._dynamic_name_to_dynamic_ordinal[name]

    @staticmethod
    def dynamic_ordinal_to_dynamic_name(dynamic_ordinal) -> str:
        r'''Changes `dynamic_ordinal` to dynamic name.

        ..  container:: example

            >>> abjad.Dynamic.dynamic_ordinal_to_dynamic_name(-5)
            'pppp'

            >>> negative_infinity = abjad.mathtools.NegativeInfinity()
            >>> abjad.Dynamic.dynamic_ordinal_to_dynamic_name(negative_infinity)
            'niente'

        '''
        if dynamic_ordinal == NegativeInfinity():
            return 'niente'
        else:
            return Dynamic._dynamic_ordinal_to_dynamic_name[dynamic_ordinal]

    @staticmethod
    def is_dynamic_name(argument) -> bool:
        r'''Is true when `argument` is dynamic name.

        ..  container:: example

            >>> abjad.Dynamic.is_dynamic_name('f')
            True

            >>> abjad.Dynamic.is_dynamic_name('sfz')
            True

            >>> abjad.Dynamic.is_dynamic_name('niente')
            True

        '''
        return argument in Dynamic._dynamic_names
Esempio n. 6
0
# -*- encoding: utf-8 -*-
from abjad.tools import systemtools
from abjad.tools import datastructuretools
from abjad.tools import mathtools


# load constants into __builtins__ namespace
__builtins__['Less'] = datastructuretools.OrdinalConstant('value', -1, 'Less')
__builtins__['More'] = datastructuretools.OrdinalConstant('value', 1, 'More')
__builtins__['Exact'] = datastructuretools.OrdinalConstant(
    'value', 0, 'Exact')
__builtins__['Left'] = datastructuretools.OrdinalConstant('x', -1, 'Left')
__builtins__['Right'] = datastructuretools.OrdinalConstant('x', 1, 'Right')
__builtins__['Center'] = datastructuretools.OrdinalConstant('y', 0, 'Center')
__builtins__['Up'] = datastructuretools.OrdinalConstant('y', 1, 'Up')
__builtins__['Down'] = datastructuretools.OrdinalConstant('y', -1, 'Down')
__builtins__['Infinity'] = mathtools.Infinity()
__builtins__['NegativeInfinity'] = mathtools.NegativeInfinity()

systemtools.ImportManager.import_structured_package(
    __path__[0],
    globals(),
    delete_systemtools=False,
    )
Esempio n. 7
0
class Dynamic(AbjadValueObject):
    r'''A dynamic.

    ..  container:: example

        **Example 1.** Initializes from dynamic name:

        ::

            >>> staff = Staff("c'8 d'8 e'8 f'8")
            >>> dynamic = Dynamic('f')
            >>> attach(dynamic, staff[0])

        ..  doctest::

            >>> print(format(staff))
            \new Staff {
                c'8 \f
                d'8
                e'8
                f'8
            }

        ::

            >>> show(staff) # doctest: +SKIP

    ..  container:: example

        **Example 2.** Initializes from other dynamic:

        ::

            >>> dynamic_1 = Dynamic('f')
            >>> dynamic_2 = Dynamic(dynamic_1)

        ::

            >>> dynamic_1
            Dynamic(name='f')

        ::

            >>> dynamic_2
            Dynamic(name='f')

    '''

    ### CLASS VARIABLES ###

    __slots__ = (
        '_default_scope',
        '_name',
    )

    _format_slot = 'right'

    _composite_dynamic_name_to_steady_state_dynamic_name = {
        'fp': 'p',
        'sf': 'f',
        'sff': 'ff',
        'sp': 'p',
        'spp': 'pp',
        'sfz': 'f',
        'sfp': 'p',
        'rfz': 'f',
    }

    _dynamic_name_to_dynamic_ordinal = {
        'ppppp': -6,
        'pppp': -5,
        'ppp': -4,
        'pp': -3,
        'p': -2,
        'niente': mathtools.NegativeInfinity(),
        'mp': -1,
        'mf': 1,
        'f': 2,
        'ff': 3,
        'fff': 4,
        'ffff': 5,
        'fffff': 6,
    }

    _dynamic_names = (
        'ppppp',
        'pppp',
        'ppp',
        'pp',
        'p',
        'mp',
        'mf',
        'f',
        'ff',
        'fff',
        'ffff',
        'fffff',
        'fp',
        'sf',
        'sff',
        'sp',
        'spp',
        'sfz',
        'sfp',
        'rfz',
        'niente',
    )

    _dynamic_ordinal_to_dynamic_name = {
        -6: 'ppppp',
        -5: 'pppp',
        -4: 'ppp',
        -3: 'pp',
        -2: 'p',
        -1: 'mp',
        mathtools.NegativeInfinity(): 'niente',
        1: 'mf',
        2: 'f',
        3: 'ff',
        4: 'fff',
        5: 'ffff',
        6: 'fffff',
    }

    ### INITIALIZER ###

    def __init__(self, name='f'):
        from abjad.tools import scoretools
        if isinstance(name, type(self)):
            name = name.name
        self._name = name
        self._default_scope = scoretools.Staff

    ### SPECIAL METHODS ###

    def __format__(self, format_specification=''):
        r'''Formats dynamic.

        Set `format_specification` to `''`, `'lilypond'` or `'storage'`.
        Interprets `''` equal to `'storage'`.

        ..  container:: example

            **Example 1.** Gets storage format of forte:

            ::

                >>> dynamic = Dynamic('f')
                >>> print(format(dynamic))
                indicatortools.Dynamic(
                    name='f',
                    )

        ..  container:: example

            **Example 2.** Gets LilyPond format of forte:

            ::

                >>> dynamic = Dynamic('f')
                >>> print(format(dynamic, 'lilypond'))
                \f

        Returns string.
        '''
        if format_specification == 'lilypond':
            return self._lilypond_format
        superclass = super(Dynamic, self)
        return superclass.__format__(format_specification=format_specification)

    ### PRIVATE PROPERTIES ###

    @property
    def _contents_repr_string(self):
        return repr(self._name)

    @property
    def _lilypond_format(self):
        return r'\{}'.format(self.name)

    ### PUBLIC PROPERTIES ###

    @property
    def default_scope(self):
        r'''Gets default scope of dynamic.

        ..  container:: example

            **Example 1.** Forte:

            ::

                >>> dynamic = Dynamic('f')
                >>> dynamic.default_scope
                <class 'abjad.tools.scoretools.Staff.Staff'>

        ..  container:: example

            **Example 2.** Piano:

            ::

                >>> dynamic = Dynamic('p')
                >>> dynamic.default_scope
                <class 'abjad.tools.scoretools.Staff.Staff'>

        Dynamics are staff-scoped by default.

        Returns staff.
        '''
        return self._default_scope

    @property
    def name(self):
        r'''Gets name of dynamic.

        ..  container:: example

            **Example 1.** Forte:

            ::

                >>> Dynamic('f').name
                'f'

        ..  container:: example

            **Example 2.** Piano:

            ::

                >>> Dynamic('p').name
                'p'

        Returns string.
        '''
        return self._name

    @property
    def ordinal(self):
        r'''Gets ordinal value of dynamic.

        ..  container:: example

            **Example 1.** Forte:

            ::

                >>> Dynamic('f').ordinal
                2

        ..  container:: example

            **Example 2.** Piano:

            ::

                >>> Dynamic('p').ordinal
                -2
        
        Returns integer.
        '''
        name = self.name
        if name in self._composite_dynamic_name_to_steady_state_dynamic_name:
            name = self._composite_dynamic_name_to_steady_state_dynamic_name[
                name]
        ordinal = self._dynamic_name_to_dynamic_ordinal[name]
        return ordinal

    ### PUBLIC METHODS ###

    @staticmethod
    def composite_dynamic_name_to_steady_state_dynamic_name(name):
        r'''Changes composite `name` to steady state dynamic name.

        ..  container:: example

            **Example 1.** Steady state of sfp is piano:

            ::

                >>> Dynamic.composite_dynamic_name_to_steady_state_dynamic_name('sfp')
                'p'

        ..  container:: example

            **Example 2.** Steady state of rfz is forte:

            ::

                >>> Dynamic.composite_dynamic_name_to_steady_state_dynamic_name('rfz')
                'f'

        Returns string.
        '''
        return Dynamic._composite_dynamic_name_to_steady_state_dynamic_name[
            name]

    @staticmethod
    def dynamic_name_to_dynamic_ordinal(name):
        r'''Changes `name` to dynamic ordinal.

        ..  container:: example

            **Example 1.** Louder dynamics change to positive integers:

            ::

                >>> Dynamic.dynamic_name_to_dynamic_ordinal('fff')
                4

        ..  container:: example

            **Example 2.** Niente changes to negative infinity:

            ::

                >>> Dynamic.dynamic_name_to_dynamic_ordinal('niente')
                NegativeInfinity

        Returns integer or negative infinity.
        '''
        try:
            return Dynamic._dynamic_name_to_dynamic_ordinal[name]
        except KeyError:
            name = Dynamic.composite_dynamic_name_to_steady_state_dynamic_name(
                name)
            return Dynamic._dynamic_name_to_dynamic_ordinal[name]

    @staticmethod
    def dynamic_ordinal_to_dynamic_name(dynamic_ordinal):
        r'''Changes `dynamic_ordinal` to dynamic name.

        ..  container:: example

            **Example 1.** Negative values change to quiet dynamics:

            ::

                >>> Dynamic.dynamic_ordinal_to_dynamic_name(-5)
                'pppp'

        ..  container:: example

            **Example 2.** Negative infinity changes to niente:

            ::

                >>> negative_infinity = mathtools.NegativeInfinity()
                >>> Dynamic.dynamic_ordinal_to_dynamic_name(negative_infinity)
                'niente'

        Returns string.
        '''
        if dynamic_ordinal == mathtools.NegativeInfinity():
            return 'niente'
        else:
            return Dynamic._dynamic_ordinal_to_dynamic_name[dynamic_ordinal]

    @staticmethod
    def is_dynamic_name(arg):
        r'''Is true when `arg` is dynamic name. Otherwise false.

        ..  container:: example

            **Example 1.** Some usual dynamic names:

            ::

                >>> Dynamic.is_dynamic_name('f')
                True

            ::

                >>> Dynamic.is_dynamic_name('sfz')
                True

        ..  container:: example

            **Example 2.** Niente is also a dynamic name:

            ::

                >>> Dynamic.is_dynamic_name('niente')
                True

        Returns boolean.
        '''
        return arg in Dynamic._dynamic_names