def _get_measure_start_offsets(self, component): wrappers = [] prototype = TimeSignature root = abjad_inspect(component).parentage().root for component_ in self._iterate_entire_score(root): wrappers_ = abjad_inspect(component_).wrappers(prototype) wrappers.extend(wrappers_) pairs = [] for wrapper in wrappers: component = wrapper.component start_offset = abjad_inspect(component).timespan().start_offset time_signature = wrapper.indicator pair = start_offset, time_signature pairs.append(pair) offset_zero = Offset(0) default_time_signature = TimeSignature((4, 4)) default_pair = (offset_zero, default_time_signature) if pairs and not pairs[0] == offset_zero: pairs.insert(0, default_pair) elif not pairs: pairs = [default_pair] pairs.sort(key=lambda x: x[0]) score_stop_offset = abjad_inspect(root).timespan().stop_offset dummy_last_pair = (score_stop_offset, None) pairs.append(dummy_last_pair) measure_start_offsets = [] for current_pair, next_pair in Sequence(pairs).nwise(): current_start_offset, current_time_signature = current_pair next_start_offset, next_time_signature = next_pair measure_start_offset = current_start_offset while measure_start_offset < next_start_offset: measure_start_offsets.append(measure_start_offset) measure_start_offset += current_time_signature.duration return measure_start_offsets
def _attach_lilypond_one_voice(self): from .Voice import Voice anchor_leaf = self._get_on_beat_anchor_leaf() anchor_voice = abjad_inspect(anchor_leaf).parentage().get(Voice) final_anchor_leaf = abjad_inspect(anchor_voice).leaf(-1) next_leaf = abjad_inspect(final_anchor_leaf).leaf(1) literal = LilyPondLiteral(r"\oneVoice") if abjad_inspect(next_leaf).has_indicator(literal): return site = "abjad.OnBeatGraceContainer._attach_lilypond_one_voice()" tag = Tag(site) attach(literal, next_leaf, tag=tag)
def _get_before_grace_leaf_offsets(leaf): container = leaf._parent main_leaf = container._main_leaf main_leaf_start_offset = main_leaf._start_offset assert main_leaf_start_offset is not None displacement = -abjad_inspect(leaf).duration() sibling = leaf._sibling(1) while sibling is not None and sibling._parent is container: displacement -= abjad_inspect(sibling).duration() sibling = sibling._sibling(1) start_offset = Offset(main_leaf_start_offset, displacement=displacement) displacement += abjad_inspect(leaf).duration() stop_offset = Offset(main_leaf_start_offset, displacement=displacement) return start_offset, stop_offset
def _update_now( self, component, offsets=False, offsets_in_seconds=False, indicators=False, ): assert offsets or offsets_in_seconds or indicators if component._is_forbidden_to_update: return parentage = abjad_inspect(component).parentage() for parent in parentage: if parent._is_forbidden_to_update: return ( offsets_are_current, indicators_are_current, offsets_in_seconds_are_current, ) = self._get_score_tree_state_flags(parentage) root = parentage.root if offsets and not offsets_are_current: self._update_all_offsets(root) if offsets_in_seconds and not offsets_in_seconds_are_current: self._update_all_offsets_in_seconds(root) if indicators and not indicators_are_current: self._update_all_indicators(root)
def _update_measure_numbers(self, component): measure_start_offsets = self._get_measure_start_offsets(component) root = abjad_inspect(component).parentage().root for component in self._iterate_entire_score(root): measure_number = self._to_measure_number(component, measure_start_offsets) component._measure_number = measure_number
def _set_leaf_durations(self): if self.leaf_duration is None: return for leaf in select(self).leaves(): duration = abjad_inspect(leaf).duration() if duration != self.leaf_duration: multiplier = self.leaf_duration / duration leaf.multiplier = multiplier
def _attach_lilypond_one_voice(self): from .Voice import Voice anchor_leaf = self._get_on_beat_anchor_leaf() anchor_voice = abjad_inspect(anchor_leaf).parentage().get(Voice) final_anchor_leaf = abjad_inspect(anchor_voice).leaf(-1) next_leaf = abjad_inspect(final_anchor_leaf).leaf(1) literal = LilyPondLiteral(r"\oneVoice", format_slot="absolute_before") if abjad_inspect(next_leaf).has_indicator(literal): return if isinstance(next_leaf._parent, OnBeatGraceContainer): return if next_leaf._parent._is_on_beat_anchor_voice(): return site = "abjad.OnBeatGraceContainer._attach_lilypond_one_voice()" tag = Tag(site) tag = tag.append(abjad_tags.ONE_VOICE_COMMAND) attach(literal, next_leaf, tag=tag)
def _get_on_beat_grace_leaf_offsets(leaf): container = leaf._parent anchor_leaf = container._get_on_beat_anchor_leaf() anchor_leaf_start_offset = anchor_leaf._start_offset assert anchor_leaf_start_offset is not None anchor_leaf_start_offset = Offset(anchor_leaf_start_offset.pair) start_displacement = Duration(0) sibling = leaf._sibling(-1) while sibling is not None and sibling._parent is container: start_displacement += abjad_inspect(sibling).duration() sibling = sibling._sibling(-1) stop_displacement = start_displacement + abjad_inspect(leaf).duration() if start_displacement == 0: start_displacement = None start_offset = Offset(anchor_leaf_start_offset.pair, displacement=start_displacement) stop_offset = Offset(anchor_leaf_start_offset.pair, displacement=stop_displacement) return start_offset, stop_offset
def _update_all_indicators(self, root): """ Updating indicators does not update offsets. On the other hand, getting an effective indicator does update offsets when at least one indicator of the appropriate type attaches to score. """ components = self._iterate_entire_score(root) for component in components: for wrapper in abjad_inspect(component).wrappers(): if wrapper.context is not None: wrapper._update_effective_context() component._indicators_are_current = True
def _get_after_grace_leaf_offsets(leaf): container = leaf._parent main_leaf = container._main_leaf main_leaf_stop_offset = main_leaf._stop_offset assert main_leaf_stop_offset is not None displacement = -abjad_inspect(leaf).duration() sibling = leaf._sibling(1) while sibling is not None and sibling._parent is container: displacement -= abjad_inspect(sibling).duration() sibling = sibling._sibling(1) if leaf._parent is not None and leaf._parent._main_leaf is not None: main_leaf = leaf._parent._main_leaf sibling = main_leaf._sibling(1) if (sibling is not None and hasattr(sibling, "_before_grace_container") and sibling._before_grace_container is not None): before_grace_container = sibling._before_grace_container duration = abjad_inspect(before_grace_container).duration() displacement -= duration start_offset = Offset(main_leaf_stop_offset, displacement=displacement) displacement += abjad_inspect(leaf).duration() stop_offset = Offset(main_leaf_stop_offset, displacement=displacement) return start_offset, stop_offset
def _match_anchor_leaf(self): from .Chord import Chord from .Note import Note first_grace = abjad_inspect(self).leaf(0) if not isinstance(first_grace, (Note, Chord)): message = f"must start with note or chord:\n" message += f" {repr(self)}" raise Exception(message) anchor_leaf = self._get_on_beat_anchor_leaf() if isinstance(anchor_leaf, (Note, Chord)) and isinstance(first_grace, (Note, Chord)): if isinstance(first_grace, Note): chord = Chord(first_grace) mutate(first_grace).replace(chord) first_grace = chord anchor_pitches = abjad_inspect(anchor_leaf).pitches() highest_pitch = list(sorted(anchor_pitches))[-1] if highest_pitch not in first_grace.note_heads: first_grace.note_heads.append(highest_pitch) grace_mate_head = first_grace.note_heads.get(highest_pitch) tweak(grace_mate_head).font_size = 0 tweak(grace_mate_head).transparent = True
def _to_measure_number(self, component, measure_start_offsets): component_start_offset = ( abjad_inspect(component).timespan().start_offset) displacement = component_start_offset.displacement if displacement is not None: component_start_offset = Offset(component_start_offset, displacement=None) # score-initial grace music only: if displacement < 0 and component_start_offset == 0: measure_number = 0 return measure_number measure_start_offsets = measure_start_offsets[:] measure_start_offsets.append(mathtools.Infinity()) pairs = Sequence(measure_start_offsets) pairs = pairs.nwise() for measure_index, pair in enumerate(pairs): if pair[0] <= component_start_offset < pair[-1]: measure_number = measure_index + 1 return measure_number message = f"can not find measure number for {repr(component)}:\n" message += f" {repr(measure_start_offsets)}" raise ValueError(message)
def on_beat_grace_container( contents, anchor_voice_selection, *, anchor_voice_number=2, do_not_beam=None, do_not_slash=None, do_not_slur=None, do_not_stop_polyphony=None, font_size=-3, grace_voice_number=1, leaf_duration=None, ): r""" Makes on-beat grace container and wraps around ``selection``. .. container:: example GRACE NOTES ABOVE. Note-to-note anchor: >>> music_voice = abjad.Voice("c'4 d' e' f'", name="Music_Voice") >>> string = "g'8 a' b' c'' d'' c'' b' a' b' c'' d''" >>> result = abjad.on_beat_grace_container( ... string, music_voice[1:3], leaf_duration=(1, 30) ... ) >>> staff = abjad.Staff([music_voice]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \context Voice = "Music_Voice" { c'4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 %! abjad.on_beat_grace_container(1) \slash %! abjad.on_beat_grace_container(2) \voiceOne %! abjad.on_beat_grace_container(3) < \tweak font-size #0 \tweak transparent ##t d' g' >8 * 4/15 [ ( a'8 * 4/15 b'8 * 4/15 c''8 * 4/15 d''8 * 4/15 c''8 * 4/15 b'8 * 4/15 a'8 * 4/15 b'8 * 4/15 c''8 * 4/15 d''8 * 4/15 ) ] } \context Voice = "Music_Voice" { \voiceTwo %! abjad.on_beat_grace_container(4) d'4 e'4 } >> \oneVoice %! abjad.on_beat_grace_container(5) f'4 } } Note-to-chord anchor: >>> music_voice = abjad.Voice( ... "<a c'>4 <b d'> <c' e'> <d' f'>", name="Music_Voice" ... ) >>> string = "g'8 a' b' c'' d'' c'' b' a' b' c'' d''" >>> result = abjad.on_beat_grace_container( ... string, music_voice[1:3], leaf_duration=(1, 30) ... ) >>> staff = abjad.Staff([music_voice]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \context Voice = "Music_Voice" { <a c'>4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 %! abjad.on_beat_grace_container(1) \slash %! abjad.on_beat_grace_container(2) \voiceOne %! abjad.on_beat_grace_container(3) < \tweak font-size #0 \tweak transparent ##t d' g' >8 * 4/15 [ ( a'8 * 4/15 b'8 * 4/15 c''8 * 4/15 d''8 * 4/15 c''8 * 4/15 b'8 * 4/15 a'8 * 4/15 b'8 * 4/15 c''8 * 4/15 d''8 * 4/15 ) ] } \context Voice = "Music_Voice" { \voiceTwo %! abjad.on_beat_grace_container(4) <b d'>4 <c' e'>4 } >> \oneVoice %! abjad.on_beat_grace_container(5) <d' f'>4 } } Chord-to-note anchor: >>> music_voice = abjad.Voice("c'4 d' e' f'", name="Music_Voice") >>> string = "<g' b'>8 a' b' c'' d'' c'' b' a' b' c'' d''" >>> result = abjad.on_beat_grace_container( ... string, music_voice[1:3], leaf_duration=(1, 30) ... ) >>> staff = abjad.Staff([music_voice]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \context Voice = "Music_Voice" { c'4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 %! abjad.on_beat_grace_container(1) \slash %! abjad.on_beat_grace_container(2) \voiceOne %! abjad.on_beat_grace_container(3) < \tweak font-size #0 \tweak transparent ##t d' g' b' >8 * 4/15 [ ( a'8 * 4/15 b'8 * 4/15 c''8 * 4/15 d''8 * 4/15 c''8 * 4/15 b'8 * 4/15 a'8 * 4/15 b'8 * 4/15 c''8 * 4/15 d''8 * 4/15 ) ] } \context Voice = "Music_Voice" { \voiceTwo %! abjad.on_beat_grace_container(4) d'4 e'4 } >> \oneVoice %! abjad.on_beat_grace_container(5) f'4 } } Chord-to-chord anchor: >>> music_voice = abjad.Voice( ... "<a c'>4 <b d'> <c' e'> <d' f'>", name="Music_Voice" ... ) >>> string = "<g' b'>8 a' b' c'' d'' c'' b' a' b' c'' d''" >>> result = abjad.on_beat_grace_container( ... string, music_voice[1:3], leaf_duration=(1, 30) ... ) >>> staff = abjad.Staff([music_voice]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \context Voice = "Music_Voice" { <a c'>4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 %! abjad.on_beat_grace_container(1) \slash %! abjad.on_beat_grace_container(2) \voiceOne %! abjad.on_beat_grace_container(3) < \tweak font-size #0 \tweak transparent ##t d' g' b' >8 * 4/15 [ ( a'8 * 4/15 b'8 * 4/15 c''8 * 4/15 d''8 * 4/15 c''8 * 4/15 b'8 * 4/15 a'8 * 4/15 b'8 * 4/15 c''8 * 4/15 d''8 * 4/15 ) ] } \context Voice = "Music_Voice" { \voiceTwo %! abjad.on_beat_grace_container(4) <b d'>4 <c' e'>4 } >> \oneVoice %! abjad.on_beat_grace_container(5) <d' f'>4 } } .. container:: example GRACE NOTES BELOW. Note-to-note anchor: >>> music_voice = abjad.Voice("c'4 d' e' f'", name="Music_Voice") >>> string = "g8 a b c' d' c' b a b c' d'" >>> result = abjad.on_beat_grace_container( ... string, ... music_voice[1:3], ... anchor_voice_number=1, ... grace_voice_number=2, ... leaf_duration=(1, 30), ... ) >>> staff = abjad.Staff([music_voice]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \context Voice = "Music_Voice" { c'4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 %! abjad.on_beat_grace_container(1) \slash %! abjad.on_beat_grace_container(2) \voiceTwo %! abjad.on_beat_grace_container(3) < g \tweak font-size #0 \tweak transparent ##t d' >8 * 4/15 [ ( a8 * 4/15 b8 * 4/15 c'8 * 4/15 d'8 * 4/15 c'8 * 4/15 b8 * 4/15 a8 * 4/15 b8 * 4/15 c'8 * 4/15 d'8 * 4/15 ) ] } \context Voice = "Music_Voice" { \voiceOne %! abjad.on_beat_grace_container(4) d'4 e'4 } >> \oneVoice %! abjad.on_beat_grace_container(5) f'4 } } Note-to-chord anchor: >>> music_voice = abjad.Voice( ... "<c' e'>4 <d' f'> <e' g'> <f' a'>", name="Music_Voice" ... ) >>> string = "g8 a b c' d' c' b a b c' d'" >>> result = abjad.on_beat_grace_container( ... string, ... music_voice[1:3], ... anchor_voice_number=1, ... grace_voice_number=2, ... leaf_duration=(1, 30), ... ) >>> staff = abjad.Staff([music_voice]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \context Voice = "Music_Voice" { <c' e'>4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 %! abjad.on_beat_grace_container(1) \slash %! abjad.on_beat_grace_container(2) \voiceTwo %! abjad.on_beat_grace_container(3) < g \tweak font-size #0 \tweak transparent ##t f' >8 * 4/15 [ ( a8 * 4/15 b8 * 4/15 c'8 * 4/15 d'8 * 4/15 c'8 * 4/15 b8 * 4/15 a8 * 4/15 b8 * 4/15 c'8 * 4/15 d'8 * 4/15 ) ] } \context Voice = "Music_Voice" { \voiceOne %! abjad.on_beat_grace_container(4) <d' f'>4 <e' g'>4 } >> \oneVoice %! abjad.on_beat_grace_container(5) <f' a'>4 } } Chord-to-note anchor: >>> music_voice = abjad.Voice("c'4 d' e' f'", name="Music_Voice") >>> string = "<e g>8 a b c' d' c' b a b c' d'" >>> result = abjad.on_beat_grace_container( ... string, ... music_voice[1:3], ... anchor_voice_number=1, ... grace_voice_number=2, ... leaf_duration=(1, 30), ... ) >>> staff = abjad.Staff([music_voice]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \context Voice = "Music_Voice" { c'4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 %! abjad.on_beat_grace_container(1) \slash %! abjad.on_beat_grace_container(2) \voiceTwo %! abjad.on_beat_grace_container(3) < e g \tweak font-size #0 \tweak transparent ##t d' >8 * 4/15 [ ( a8 * 4/15 b8 * 4/15 c'8 * 4/15 d'8 * 4/15 c'8 * 4/15 b8 * 4/15 a8 * 4/15 b8 * 4/15 c'8 * 4/15 d'8 * 4/15 ) ] } \context Voice = "Music_Voice" { \voiceOne %! abjad.on_beat_grace_container(4) d'4 e'4 } >> \oneVoice %! abjad.on_beat_grace_container(5) f'4 } } Chord-to-chord anchor: >>> music_voice = abjad.Voice( ... "<c' e'>4 <d' f'> <e' g'> <f' a'>", name="Music_Voice" ... ) >>> string = "<e g>8 a b c' d' c' b a b c' d'" >>> result = abjad.on_beat_grace_container( ... string, ... music_voice[1:3], ... anchor_voice_number=1, ... grace_voice_number=2, ... leaf_duration=(1, 30), ... ) >>> staff = abjad.Staff([music_voice]) >>> abjad.show(staff) # doctest: +SKIP .. docs:: >>> abjad.f(staff) \new Staff { \context Voice = "Music_Voice" { <c' e'>4 << \context Voice = "On_Beat_Grace_Container" { \set fontSize = #-3 %! abjad.on_beat_grace_container(1) \slash %! abjad.on_beat_grace_container(2) \voiceTwo %! abjad.on_beat_grace_container(3) < e g \tweak font-size #0 \tweak transparent ##t f' >8 * 4/15 [ ( a8 * 4/15 b8 * 4/15 c'8 * 4/15 d'8 * 4/15 c'8 * 4/15 b8 * 4/15 a8 * 4/15 b8 * 4/15 c'8 * 4/15 d'8 * 4/15 ) ] } \context Voice = "Music_Voice" { \voiceOne %! abjad.on_beat_grace_container(4) <d' f'>4 <e' g'>4 } >> \oneVoice %! abjad.on_beat_grace_container(5) <f' a'>4 } } .. container:: example Raises exception when duration of on-beat grace container exceeds duration of anchor container: >>> music_voice = abjad.Voice("c'4 d' e' f'", name="Music_Voice") >>> string = "g'8 a' b' c'' d'' c'' b' a' b' c'' d''" >>> result = abjad.on_beat_grace_container( ... string, music_voice[1:2], leaf_duration=(1, 8) ... ) Traceback (most recent call last): ... Exception: grace Duration(11, 8) exceeds anchor Duration(1, 4). """ from .Container import Container from .Selection import Selection from .Voice import Voice from abjad.spanners import beam from abjad.spanners import slur def _site(n): return Tag(f"abjad.on_beat_grace_container({n})") assert isinstance(anchor_voice_selection, Selection) if not anchor_voice_selection.are_contiguous_same_parent( ignore_before_after_grace=True): message = "selection must be contiguous in same parent:\n" message += f" {repr(anchor_voice_selection)}" raise Exception(message) on_beat_grace_container = OnBeatGraceContainer(contents, leaf_duration=leaf_duration) if not isinstance(anchor_voice_selection, Selection): raise Exception(f"must be selection:\n {repr(anchor_voice_selection)}") anchor_leaf = abjad_inspect(anchor_voice_selection).leaf(0) anchor_voice = abjad_inspect(anchor_leaf).parentage().get(Voice) if anchor_voice.name is None: raise Exception( f"anchor voice must be named:\n {repr(anchor_voice)}") anchor_voice_insert = Voice(name=anchor_voice.name) mutate(anchor_voice_selection).wrap(anchor_voice_insert) container = Container(simultaneous=True) mutate(anchor_voice_insert).wrap(container) container.insert(0, on_beat_grace_container) on_beat_grace_container._match_anchor_leaf() on_beat_grace_container._set_leaf_durations() insert_duration = abjad_inspect(anchor_voice_insert).duration() grace_container_duration = abjad_inspect( on_beat_grace_container).duration() if insert_duration < grace_container_duration: message = f"grace {repr(grace_container_duration)}" message += f" exceeds anchor {repr(insert_duration)}." raise Exception(message) if font_size is not None: string = rf"\set fontSize = #{font_size}" literal = LilyPondLiteral(string) attach(literal, on_beat_grace_container, tag=_site(1)) if not do_not_beam: beam(on_beat_grace_container[:]) if not do_not_slash: literal = LilyPondLiteral(r"\slash") attach(literal, on_beat_grace_container[0], tag=_site(2)) if not do_not_slur: slur(on_beat_grace_container[:]) voice_number_to_string = { 1: r"\voiceOne", 2: r"\voiceTwo", 3: r"\voiceThree", 4: r"\voiceFour", } first_grace = abjad_inspect(on_beat_grace_container).leaf(0) one_voice_literal = LilyPondLiteral(r"\oneVoice", format_slot="absolute_before") string = voice_number_to_string.get(grace_voice_number, None) if string is not None: literal detach(one_voice_literal, anchor_leaf) attach(LilyPondLiteral(string), first_grace, tag=_site(3)) string = voice_number_to_string.get(anchor_voice_number, None) if string is not None: detach(one_voice_literal, anchor_leaf) attach(LilyPondLiteral(string), anchor_leaf, tag=_site(4)) if not do_not_stop_polyphony: last_anchor_leaf = abjad_inspect(anchor_voice_selection).leaf(-1) next_leaf = abjad_inspect(last_anchor_leaf).leaf(1) if next_leaf is not None: literal = LilyPondLiteral(r"\oneVoice", format_slot="absolute_before") attach(literal, next_leaf, tag=_site(5)) return on_beat_grace_container
def _update_component_offsets(class_, component): from abjad.core.AfterGraceContainer import AfterGraceContainer from abjad.core.BeforeGraceContainer import BeforeGraceContainer from abjad.core.OnBeatGraceContainer import OnBeatGraceContainer if isinstance(component, BeforeGraceContainer): pair = class_._get_before_grace_leaf_offsets(component[0]) start_offset = pair[0] pair = class_._get_before_grace_leaf_offsets(component[-1]) stop_offset = pair[-1] elif isinstance(component._parent, BeforeGraceContainer): pair = class_._get_before_grace_leaf_offsets(component) start_offset, stop_offset = pair elif isinstance(component, OnBeatGraceContainer): pair = class_._get_on_beat_grace_leaf_offsets(component[0]) start_offset = pair[0] pair = class_._get_on_beat_grace_leaf_offsets(component[-1]) stop_offset = pair[-1] elif isinstance(component._parent, OnBeatGraceContainer): pair = class_._get_on_beat_grace_leaf_offsets(component) start_offset, stop_offset = pair elif isinstance(component, AfterGraceContainer): pair = class_._get_after_grace_leaf_offsets(component[0]) start_offset = pair[0] pair = class_._get_after_grace_leaf_offsets(component[-1]) stop_offset = pair[-1] elif isinstance(component._parent, AfterGraceContainer): pair = class_._get_after_grace_leaf_offsets(component) start_offset, stop_offset = pair else: previous = component._sibling(-1) if previous is not None: start_offset = previous._stop_offset else: start_offset = Offset(0) # on-beat anchor leaf: if (component._parent is not None and component._parent._is_on_beat_anchor_voice() and component is component._parent[0]): anchor_voice = component._parent assert anchor_voice._is_on_beat_anchor_voice() on_beat_grace_container = None on_beat_wrapper = anchor_voice._parent assert on_beat_wrapper._is_on_beat_wrapper() index = on_beat_wrapper.index(anchor_voice) if index == 0: on_beat_grace_container = on_beat_wrapper[1] else: on_beat_grace_container = on_beat_wrapper[0] if on_beat_grace_container is not None: durations = [ abjad_inspect(_).duration() for _ in on_beat_grace_container ] start_displacement = sum(durations) start_offset = Offset(start_offset, displacement=start_displacement) stop_offset = start_offset + component._get_duration() component._start_offset = start_offset component._stop_offset = stop_offset component._timespan._start_offset = start_offset component._timespan._stop_offset = stop_offset
def rhythm( class_, selections, divisions=None, attach_lilypond_voice_commands=None, implicit_scaling=None, pitched_staff=None, simultaneous_selections=None, time_signatures=None, ): r""" Makes rhythm-styled LilyPond file. .. container:: example Makes rhythmic staff: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.beam(selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file[abjad.Score] >>> abjad.f(score) \new Score << \new GlobalContext { \time 3/4 s1 * 3/4 \time 4/8 s1 * 1/2 \time 1/4 s1 * 1/4 } \new RhythmicStaff { c'8 [ c'8 c'8 c'8 c'8 c'8 ] c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] c'8 [ c'8 ] } >> .. container:: example Set time signatures explicitly: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.beam(selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... [(6, 8), (4, 8), (2, 8)], ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file[abjad.Score] >>> abjad.f(score) \new Score << \new GlobalContext { \time 6/8 s1 * 3/4 \time 4/8 s1 * 1/2 \time 2/8 s1 * 1/4 } \new RhythmicStaff { c'8 [ c'8 c'8 c'8 c'8 c'8 ] c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] c'8 [ c'8 ] } >> .. container:: example Makes pitched staff: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.beam(selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... pitched_staff=True, ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> abjad.f(lilypond_file[abjad.Score]) \new Score << \new GlobalContext { \time 3/4 s1 * 3/4 \time 4/8 s1 * 1/2 \time 1/4 s1 * 1/4 } \new Staff { c'8 [ c'8 c'8 c'8 c'8 c'8 ] c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] c'8 [ c'8 ] } >> .. container:: example Makes simultaneous voices: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.beam(selection[:]) ... >>> for note in abjad.iterate(selections).components(abjad.Note): ... note.written_pitch = abjad.NamedPitch("e'") ... >>> selection_1 = selections[0] + selections[1] + selections[2] >>> selections = [ ... maker(12 * [0], [(1, 16)]), ... maker(16 * [0], [(1, 32)]), ... maker(4 * [0], [(1, 16)]), ... ] >>> for selection in selections: ... abjad.beam(selection[:]) ... >>> selection_2 = selections[0] + selections[1] + selections[2] >>> selections = { ... 'Voice_1': selection_1, ... 'Voice_2': selection_2, ... } >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... ) >>> voice_1 = lilypond_file['Voice_1'] >>> literal = abjad.LilyPondLiteral(r'\voiceOne', "opening") >>> abjad.attach(literal, voice_1) >>> voice_2 = lilypond_file['Voice_2'] >>> literal = abjad.LilyPondLiteral(r'\voiceTwo', "opening") >>> abjad.attach(literal, voice_2) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> abjad.f(lilypond_file[abjad.Score]) \new Score << \new GlobalContext { s1 * 3/4 s1 * 1/2 s1 * 1/4 } \new Staff << \context Voice = "Voice_1" { \voiceOne e'8 [ e'8 e'8 e'8 e'8 e'8 ] e'16 [ e'16 e'16 e'16 e'16 e'16 e'16 e'16 ] e'8 [ e'8 ] } \context Voice = "Voice_2" { \voiceTwo c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] c'32 [ c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 ] c'16 [ c'16 c'16 c'16 ] } >> >> Returns LilyPond file. """ if isinstance(selections, Selection): pass elif isinstance(selections, list): for selection in selections: if not isinstance(selection, Selection): raise TypeError(f"must be selection: {selection!r}.") elif isinstance(selections, dict): for selection in selections.values(): if not isinstance(selection, Selection): raise TypeError(f"must be selection: {selection!r}.") else: raise TypeError(f"must be list or dictionary: {selections!r}.") score = Score() lilypond_file = LilyPondFile.new( score, includes=["default.ily", "rhythm-maker-docs.ily"] ) if pitched_staff is None: if isinstance(selections, (list, Selection)): selections_ = selections elif isinstance(selections, dict): selections_ = selections.values() else: raise TypeError(selections) for note in select(selections_).notes(): if note.written_pitch != NamedPitch("c'"): pitched_staff = True break chords = select(selections_).chords() if chords: pitched_staff = True if isinstance(selections, (list, Selection)): if divisions is None: duration = abjad_inspect(selections).duration() divisions = [duration] time_signatures = time_signatures or divisions time_signatures = [TimeSignature(_) for _ in time_signatures] if pitched_staff: staff = Staff() else: staff = Staff(lilypond_type="RhythmicStaff") staff.extend(selections) elif isinstance(selections, dict): voices = [] for voice_name in sorted(selections): selections_ = selections[voice_name] selections_ = sequence(selections_).flatten(depth=-1) selections_ = copy.deepcopy(selections_) voice = Voice(selections_, name=voice_name) if attach_lilypond_voice_commands: voice_name_to_command_string = { "Voice_1": "voiceOne", "Voice_2": "voiceTwo", "Voice_3": "voiceThree", "Voice_4": "voiceFour", } command_string = voice_name_to_command_string.get(voice_name) if command_string: command = LilyPondLiteral("\\" + command_string) attach(command, voice) voices.append(voice) staff = Staff(voices, simultaneous=True) if divisions is None: duration = abjad_inspect(staff).duration() divisions = [duration] else: message = "must be list or dictionary of selections:" message += f" {selections!r}." raise TypeError(message) score.append(staff) assert isinstance(divisions, collections.abc.Sequence), repr(divisions) time_signatures = time_signatures or divisions context = Context(lilypond_type="GlobalContext") skips = [] for time_signature in time_signatures: skip = Skip(1) skip.multiplier = time_signature attach(time_signature, skip, context="Score") skips.append(skip) context.extend(skips) score.insert(0, context) return lilypond_file
def rhythm( class_, selections, divisions=None, attach_lilypond_voice_commands=None, implicit_scaling=None, pitched_staff=None, simultaneous_selections=None, time_signatures=None, ): r""" Makes rhythm-styled LilyPond file. .. container:: example Makes rhythmic staff: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file[abjad.Score] >>> abjad.f(score) \new Score << \new GlobalContext { { % measure \time 3/4 s1 * 3/4 } % measure { % measure \time 4/8 s1 * 1/2 } % measure { % measure \time 1/4 s1 * 1/4 } % measure } \new RhythmicStaff { { % measure \time 3/4 c'8 [ c'8 c'8 c'8 c'8 c'8 ] } % measure { % measure \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } % measure { % measure \time 1/4 c'8 [ c'8 ] } % measure } >> .. container:: example Set time signatures explicitly: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... [(6, 8), (4, 8), (2, 8)], ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file[abjad.Score] >>> abjad.f(score) \new Score << \new GlobalContext { { % measure \time 6/8 s1 * 3/4 } % measure { % measure \time 4/8 s1 * 1/2 } % measure { % measure \time 2/8 s1 * 1/4 } % measure } \new RhythmicStaff { { % measure \time 6/8 c'8 [ c'8 c'8 c'8 c'8 c'8 ] } % measure { % measure \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } % measure { % measure \time 2/8 c'8 [ c'8 ] } % measure } >> .. container:: example Makes pitched staff: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... pitched_staff=True, ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> abjad.f(lilypond_file[abjad.Score]) \new Score << \new GlobalContext { { % measure \time 3/4 s1 * 3/4 } % measure { % measure \time 4/8 s1 * 1/2 } % measure { % measure \time 1/4 s1 * 1/4 } % measure } \new Staff { { % measure \time 3/4 c'8 [ c'8 c'8 c'8 c'8 c'8 ] } % measure { % measure \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } % measure { % measure \time 1/4 c'8 [ c'8 ] } % measure } >> .. container:: example Makes simultaneous voices: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> for note in abjad.iterate(selections).components(abjad.Note): ... note.written_pitch = abjad.NamedPitch("e'") ... >>> selection_1 = selections[0] + selections[1] + selections[2] >>> selections = [ ... maker(12 * [0], [(1, 16)]), ... maker(16 * [0], [(1, 32)]), ... maker(4 * [0], [(1, 16)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> selection_2 = selections[0] + selections[1] + selections[2] >>> selections = { ... 'Voice 1': selection_1, ... 'Voice 2': selection_2, ... } >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... ) >>> voice_1 = lilypond_file['Voice 1'] >>> abjad.attach(abjad.LilyPondLiteral(r'\voiceOne'), voice_1) >>> voice_2 = lilypond_file['Voice 2'] >>> abjad.attach(abjad.LilyPondLiteral(r'\voiceTwo'), voice_2) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> abjad.f(lilypond_file[abjad.Score]) \new Score << \new GlobalContext { { % measure \time 3/4 s1 * 3/4 } % measure { % measure \time 4/8 s1 * 1/2 } % measure { % measure \time 1/4 s1 * 1/4 } % measure } \new Staff << \context Voice = "Voice 1" { \voiceOne e'8 [ e'8 e'8 e'8 e'8 e'8 ] e'16 [ e'16 e'16 e'16 e'16 e'16 e'16 e'16 ] e'8 [ e'8 ] } \context Voice = "Voice 2" { \voiceTwo c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] c'32 [ c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 ] c'16 [ c'16 c'16 c'16 ] } >> >> Returns LilyPond file. """ if isinstance(selections, list): for selection in selections: if not isinstance(selection, Selection): message = f'must be selection: {selection!r}.' raise TypeError(message) elif isinstance(selections, dict): for selection in selections.values(): if not isinstance(selection, Selection): message = f'must be selection: {selection!r}.' raise TypeError(message) else: message = f'must be list or dictionary: {selections!r}.' raise TypeError(message) score = Score() lilypond_file = LilyPondFile.new( score, includes=['default.ily', 'rhythm-maker-docs.ily'], ) if pitched_staff is None: if isinstance(selections, list): selections_ = selections elif isinstance(selections, dict): selections_ = selections.values() else: raise TypeError(selections) for note in iterate(selections_).leaves(Note): if note.written_pitch != NamedPitch("c'"): pitched_staff = True break if isinstance(selections, list): if divisions is None: duration = abjad_inspect(selections).duration() divisions = [duration] time_signatures = time_signatures or divisions maker = MeasureMaker(implicit_scaling=implicit_scaling) measures = maker(time_signatures) if pitched_staff: staff = Staff(measures) else: staff = Staff(measures, lilypond_type='RhythmicStaff') selections = sequence(selections).flatten(depth=-1) selections_ = copy.deepcopy(selections) try: agent = mutate(staff) measures = agent.replace_measure_contents(selections) except StopIteration: if pitched_staff: staff = Staff(selections_) else: staff = Staff( selections_, lilypond_type='RhythmicStaff', ) elif isinstance(selections, dict): voices = [] for voice_name in sorted(selections): selections_ = selections[voice_name] selections_ = sequence(selections_).flatten(depth=-1) selections_ = copy.deepcopy(selections_) voice = Voice(selections_, name=voice_name) if attach_lilypond_voice_commands: voice_name_to_command_string = { 'Voice 1': 'voiceOne', 'Voice 2': 'voiceTwo', 'Voice 3': 'voiceThree', 'Voice 4': 'voiceFour', } command_string = voice_name_to_command_string.get( voice_name, ) if command_string: command = LilyPondLiteral('\\' + command_string) attach(command, voice) voices.append(voice) staff = Staff(voices, is_simultaneous=True) if divisions is None: duration = abjad_inspect(staff).duration() divisions = [duration] else: message = 'must be list or dictionary of selections:' message += f' {selections!r}.' raise TypeError(message) score.append(staff) assert isinstance(divisions, collections.Sequence), repr(divisions) time_signatures = time_signatures or divisions context = Context(lilypond_type='GlobalContext') maker = MeasureMaker(implicit_scaling=implicit_scaling) measures = maker(time_signatures) context.extend(measures) score.insert(0, context) return lilypond_file
def rhythm( class_, selections, divisions=None, attach_lilypond_voice_commands=None, implicit_scaling=None, pitched_staff=None, simultaneous_selections=None, time_signatures=None, ): r""" Makes rhythm-styled LilyPond file. .. container:: example Makes rhythmic staff: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.beam(selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file[abjad.Score] >>> abjad.f(score) \new Score << \new GlobalContext { \time 3/4 s1 * 3/4 \time 4/8 s1 * 1/2 \time 1/4 s1 * 1/4 } \new RhythmicStaff { c'8 [ c'8 c'8 c'8 c'8 c'8 ] c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] c'8 [ c'8 ] } >> .. container:: example Set time signatures explicitly: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.beam(selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... [(6, 8), (4, 8), (2, 8)], ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file[abjad.Score] >>> abjad.f(score) \new Score << \new GlobalContext { \time 6/8 s1 * 3/4 \time 4/8 s1 * 1/2 \time 2/8 s1 * 1/4 } \new RhythmicStaff { c'8 [ c'8 c'8 c'8 c'8 c'8 ] c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] c'8 [ c'8 ] } >> .. container:: example Makes pitched staff: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.beam(selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... pitched_staff=True, ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> abjad.f(lilypond_file[abjad.Score]) \new Score << \new GlobalContext { \time 3/4 s1 * 3/4 \time 4/8 s1 * 1/2 \time 1/4 s1 * 1/4 } \new Staff { c'8 [ c'8 c'8 c'8 c'8 c'8 ] c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] c'8 [ c'8 ] } >> .. container:: example Makes simultaneous voices: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.beam(selection[:]) ... >>> for note in abjad.iterate(selections).components(abjad.Note): ... note.written_pitch = abjad.NamedPitch("e'") ... >>> selection_1 = selections[0] + selections[1] + selections[2] >>> selections = [ ... maker(12 * [0], [(1, 16)]), ... maker(16 * [0], [(1, 32)]), ... maker(4 * [0], [(1, 16)]), ... ] >>> for selection in selections: ... abjad.beam(selection[:]) ... >>> selection_2 = selections[0] + selections[1] + selections[2] >>> selections = { ... 'Voice_1': selection_1, ... 'Voice_2': selection_2, ... } >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... ) >>> voice_1 = lilypond_file['Voice_1'] >>> abjad.attach(abjad.LilyPondLiteral(r'\voiceOne'), voice_1) >>> voice_2 = lilypond_file['Voice_2'] >>> abjad.attach(abjad.LilyPondLiteral(r'\voiceTwo'), voice_2) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> abjad.f(lilypond_file[abjad.Score]) \new Score << \new GlobalContext { s1 * 3/4 s1 * 1/2 s1 * 1/4 } \new Staff << \context Voice = "Voice_1" { \voiceOne e'8 [ e'8 e'8 e'8 e'8 e'8 ] e'16 [ e'16 e'16 e'16 e'16 e'16 e'16 e'16 ] e'8 [ e'8 ] } \context Voice = "Voice_2" { \voiceTwo c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] c'32 [ c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 ] c'16 [ c'16 c'16 c'16 ] } >> >> Returns LilyPond file. """ if isinstance(selections, list): for selection in selections: if not isinstance(selection, Selection): raise TypeError(f"must be selection: {selection!r}.") elif isinstance(selections, dict): for selection in selections.values(): if not isinstance(selection, Selection): raise TypeError(f"must be selection: {selection!r}.") else: raise TypeError(f"must be list or dictionary: {selections!r}.") score = Score() lilypond_file = LilyPondFile.new( score, includes=["default.ily", "rhythm-maker-docs.ily"] ) if pitched_staff is None: if isinstance(selections, list): selections_ = selections elif isinstance(selections, dict): selections_ = selections.values() else: raise TypeError(selections) for note in iterate(selections_).leaves(Note): if note.written_pitch != NamedPitch("c'"): pitched_staff = True break if isinstance(selections, list): if divisions is None: duration = abjad_inspect(selections).duration() divisions = [duration] time_signatures = time_signatures or divisions time_signatures = [TimeSignature(_) for _ in time_signatures] if pitched_staff: staff = Staff() else: staff = Staff(lilypond_type="RhythmicStaff") staff.extend(selections) elif isinstance(selections, dict): voices = [] for voice_name in sorted(selections): selections_ = selections[voice_name] selections_ = sequence(selections_).flatten(depth=-1) selections_ = copy.deepcopy(selections_) voice = Voice(selections_, name=voice_name) if attach_lilypond_voice_commands: voice_name_to_command_string = { "Voice_1": "voiceOne", "Voice_2": "voiceTwo", "Voice_3": "voiceThree", "Voice_4": "voiceFour", } command_string = voice_name_to_command_string.get( voice_name ) if command_string: command = LilyPondLiteral("\\" + command_string) attach(command, voice) voices.append(voice) staff = Staff(voices, is_simultaneous=True) if divisions is None: duration = abjad_inspect(staff).duration() divisions = [duration] else: message = "must be list or dictionary of selections:" message += f" {selections!r}." raise TypeError(message) score.append(staff) assert isinstance(divisions, collections.abc.Sequence), repr(divisions) time_signatures = time_signatures or divisions context = Context(lilypond_type="GlobalContext") skips = [] for time_signature in time_signatures: skip = Skip(1) skip.multiplier = time_signature attach(time_signature, skip, context="Score") skips.append(skip) context.extend(skips) score.insert(0, context) return lilypond_file