def prettify_rewrite_meter( selection: abjad.Selection, meter: Union[abjad.Meter, abjad.TimeSignature], *, fuse_across_groups_of_beats: bool = True, fuse_quadruple_meter: bool = True, fuse_triple_meter: bool = True, extract_trivial_tuplets: bool = True, split_quadruple_meter: bool = True, ) -> None: r"""Mutates an input |abjad.Selection| in place and has no return value; this function fuses pitched leaves according to the rules shown below, improving the default output of |abjad.mutate().rewrite_meter()|. Basic usage: Meters whose denominators are a crotchet or longer get tied notes within a beat after |abjad.mutate().rewrite_meter()| when they are at an offset ``denominator / 4``, so a rhythm such as ``denominator / 4`` ``denominator / 2`` ``denominator / 4`` becomes ``denominator / 4`` ``denominator / 4`` ``~`` ``denominator / 4`` ``denominator / 4``. This function looks for those specific cases and fuses them, generating an output which is often more readable. >>> staff = abjad.Staff( ... r"\time 3/4 c'16 d'8 e'16 f'16 g'16 a'8 b'8 c''16 d''16" ... ) >>> meter = abjad.Meter((3, 4)) >>> abjad.mutate(staff[:]).rewrite_meter(meter) >>> abjad.f(staff) \new Staff { \time 3/4 c'16 d'16 ~ d'16 e'16 f'16 g'16 a'8 b'8 c''16 d''16 } .. figure:: ../_images/prettify_rewrite_meter-vlnd7l5fb7s.png >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter) >>> abjad.f(staff) \new Staff { \time 3/4 c'16 d'8 e'16 f'16 g'16 a'8 b'8 c''16 d''16 } .. figure:: ../_images/prettify_rewrite_meter-e7vfnese0ut.png .. note:: Auxjad automatically adds this function as an extension method to |abjad.mutate()|. It can thus be used from either :func:`auxjad.mutate()` or |abjad.mutate()|. Therefore, the two lines below are equivalent: >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter) >>> abjad.mutate(staff[:]).prettify_rewrite_meter(meter) Other examples: The rhythm of the leaves just before and after the two leaves to be fused can be different than ``denominator / 4``, as the function searches for logical ties of specific length and offset, and its surroundings do not matter. >>> staff = abjad.Staff(r"\time 3/4 c'32 d'32 e'8 f'16 " ... r"\times 2/3 {g'32 a'32 b'32} c''8 " ... r"r16 r32. d''64 e''8 f''32 g''32" ... ) >>> meter = abjad.Meter((3, 4)) >>> abjad.mutate(staff[:]).rewrite_meter(meter) >>> abjad.f(staff) \new Staff { \time 3/4 c'32 d'32 e'16 ~ e'16 f'16 \times 2/3 { g'32 a'32 b'32 } c''16 ~ c''16 r16 r32. d''64 e''16 ~ e''16 f''32 g''32 } .. figure:: ../_images/prettify_rewrite_meter-kw09gse2zxj.png >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter) >>> abjad.f(staff) \new Staff { \time 3/4 c'32 d'32 e'8 f'16 \times 2/3 { g'32 a'32 b'32 } c''8 r16 r32. d''64 e''8 f''32 g''32 } .. figure:: ../_images/prettify_rewrite_meter-u5gmtdippsa.png ``fuse_across_groups_of_beats``: By default, this function also fuses rhythms of type ``denominator / 2`` ``denominator / 2`` ``~`` ``denominator / 2`` ``denominator / 2``, becoming ``denominator / 2`` ``denominator`` ``denominator / 2``. This is only applied when the meter's structure has a depth of 2, which is the case for meters with numerators equal to or larger than ``5``. >>> staff = abjad.Staff(r"\time 6/4 c'8 d'4 e'4 f'4 g'4 a'4 b'8") >>> meter = abjad.Meter((6, 4)) >>> abjad.mutate(staff[:]).rewrite_meter(meter) >>> abjad.f(staff) \new Staff { \time 6/4 c'8 d'8 ~ d'8 e'8 ~ e'8 f'8 ~ f'8 g'8 ~ g'8 a'8 ~ a'8 b'8 } .. figure:: ../_images/prettify_rewrite_meter-tqi4p0u8qog.png >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter) >>> abjad.f(staff) \new Staff { \time 6/4 c'8 d'4 e'4 f'8 ~ f'8 g'4 a'4 b'8 } .. figure:: ../_images/prettify_rewrite_meter-riif1glyqpo.png to disable this behaviour, set the optional keyword argument ``fuse_across_groups_of_beats`` to ``False``. >>> staff = abjad.Staff(r"\time 6/4 c'8 d'4 e'4 f'4 g'4 a'4 b'8") >>> meter = abjad.Meter((6, 4)) >>> abjad.mutate(staff[:]).rewrite_meter(meter) >>> auxjad.mutate(staff[:]).prettify_rewrite_meter( ... meter, ... fuse_across_groups_of_beats=False, ... ) >>> abjad.f(staff) \new Staff { \time 6/4 c'8 d'8 ~ d'8 e'8 ~ e'8 f'8 ~ f'8 g'8 ~ g'8 a'8 ~ a'8 b'8 } .. figure:: ../_images/prettify_rewrite_meter-ki5xbiteij.png |abjad.Meter| with ``increase_monotonic=True``: The fused notes will respect the beat structures of such meters, even when ``increase_monotonic`` is set to the non-default value ``True``. Compare the outputs below. >>> staff = abjad.Staff(r"\time 7/4 c'8 d'4 e'4 f'4 g'4 a'4 b'4 c''8") >>> meter = abjad.Meter((7, 4)) >>> abjad.mutate(staff[:]).rewrite_meter(meter) >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter) >>> abjad.f(staff) \new Staff { \time 7/4 c'8 d'4 e'4 f'8 ~ f'8 g'4 a'8 ~ a'8 b'4 c''8 } .. figure:: ../_images/prettify_rewrite_meter-bud0jhkvvl.png >>> staff = abjad.Staff(r"\time 7/4 c'8 d'4 e'4 f'4 g'4 a'4 b'4 c''8") >>> meter = abjad.Meter((7, 4), increase_monotonic=True) >>> abjad.mutate(staff[:]).rewrite_meter(meter) >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter) >>> abjad.f(staff) \new Staff { \time 7/4 c'8 d'4 e'8 ~ e'8 f'4 g'8 ~ g'8 a'4 b'4 c''8 } .. figure:: ../_images/prettify_rewrite_meter-47y86pbwwv5.png Multiple measures at once: This function can take handle multiple measures at once, as long as they share the same meter. >>> staff = abjad.Staff(r"\time 5/8 c'16 d'8 e'8 f'8 g'8 a'16 ~ " ... r"a'16 b'8 c''8 d''8 e''8 f''16" ... ) >>> meter = abjad.Meter((5, 8)) >>> for measure in abjad.select(staff[:]).group_by_measure(): ... abjad.mutate(staff[:]).rewrite_meter(meter) >>> abjad.f(staff) \new Staff { \time 5/8 c'16 d'16 ~ d'16 e'16 ~ e'16 f'16 ~ f'16 g'16 ~ g'16 a'16 ~ a'16 b'16 ~ b'16 c''16 ~ c''16 d''16 ~ d''16 e''16 ~ e''16 f''16 } .. figure:: ../_images/prettify_rewrite_meter-8jdzmvf9yl.png >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter) >>> abjad.f(staff) \new Staff { \time 5/8 c'16 d'8 e'8 f'16 ~ f'16 g'8 a'16 ~ a'16 b'8 c''8 d''16 ~ d''16 e''8 f''16 } .. figure:: ../_images/prettify_rewrite_meter-pcn8x9hr6bb.png Multiple measures: Similarly to |abjad.mutate().rewrite_meter()|, this function accepts selections of multiple measures: >>> staff = abjad.Staff(r"\time 4/4 c'8 d'4 e'4 f'4 g'8 | " ... r"a'8 b'4 c''8 d''16 e''4 f''8.") >>> meter = abjad.Meter((4, 4)) >>> for measure in abjad.select(staff[:]).group_by_measure(): ... abjad.mutate(measure).rewrite_meter(meter) >>> abjad.f(staff) \new Staff { \time 4/4 c'8 d'8 ~ d'8 e'8 ~ e'8 f'8 ~ f'8 g'8 a'8 b'8 ~ b'8 c''8 d''16 e''8. ~ e''16 f''8. } .. figure:: ../_images/prettify_rewrite_meter-s8fg7a2k0tr.png >>> for measure in abjad.select(staff[:]).group_by_measure(): ... auxjad.mutate(measure).prettify_rewrite_meter(meter) >>> abjad.f(staff) \new Staff { \time 4/4 c'8 d'4 e'8 ~ e'8 f'4 g'8 a'8 b'4 c''8 d''16 e''8. ~ e''16 f''8. } .. figure:: ../_images/prettify_rewrite_meter-rgd7ok7fkq.png Multiple measures with different meters: If the measures have different meters, they can be passed on individually using :func:`zip()` as shown below. >>> staff = abjad.Staff(r"\time 3/4 c'8 d'4 e'4 f'16 g'16 | " ... r"\time 4/4 a'8 b'4 c''8 d''16 e''4 f''8.") >>> meters = [abjad.Meter((3, 4)), abjad.Meter((4, 4))] >>> for meter, measure in zip( ... meters, ... abjad.select(staff[:]).group_by_measure(), ... ): ... abjad.mutate(measure).rewrite_meter(meter) >>> abjad.f(staff) \new Staff { \time 3/4 c'8 d'8 ~ d'8 e'8 ~ e'8 f'16 g'16 \time 4/4 a'8 b'8 ~ b'8 c''8 d''16 e''8. ~ e''16 f''8. } .. figure:: ../_images/prettify_rewrite_meter-o2izz0m7s9k.png >>> for meter, measure in zip( ... meters, ... abjad.select(staff[:]).group_by_measure(), ... ): ... auxjad.mutate(measure).prettify_rewrite_meter(meter) >>> abjad.f(staff) \new Staff { \time 3/4 c'8 d'4 e'4 f'16 g'16 \time 4/4 a'8 b'4 c''8 d''16 e''8. ~ e''16 f''8. } .. figure:: ../_images/prettify_rewrite_meter-zh89kk66zon.png ``fuse_quadruple_meter``: This function also takes care of two special cases, namely quadruple and triple meters. By default, it will fuse leaves in quadruple meters across beats 1 and 2, and across beats 3 and 4 (as long as they fulfil the other requirements of duration and offset). >>> staff = abjad.Staff(r"\time 4/4 c'8 d'4 e'4 f'4 g'8") >>> meter = abjad.Meter((4, 4)) >>> abjad.mutate(staff[:]).rewrite_meter(meter) >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter) >>> abjad.f(staff) \new Staff { \time 4/4 c'8 d'4 e'8 ~ e'8 f'4 g'8 } .. figure:: ../_images/prettify_rewrite_meter-nap4bbf7mxe.png Set ``fuse_quadruple_meter`` to ``False`` to disable this behaviour. >>> staff = abjad.Staff(r"\time 4/4 c'8 d'4 e'4 f'4 g'8") >>> meter = abjad.Meter((4, 4)) >>> abjad.mutate(staff[:]).rewrite_meter(meter) >>> auxjad.mutate(staff[:]).prettify_rewrite_meter( ... meter, ... fuse_quadruple_meter=False, ... ) >>> abjad.f(staff) \new Staff { \time 4/4 c'8 d'8 ~ d'8 e'8 ~ e'8 f'8 ~ f'8 g'8 } .. figure:: ../_images/prettify_rewrite_meter-juipg9nzna.png ``fuse_triple_meter``: In the case of triple meters, it will fuse leaves across any beat as long as the previously mentioned conditions of offset and duration are met. >>> staff = abjad.Staff(r"\time 3/4 c'8 d'4 e'4 f'8") >>> meter = abjad.Meter((3, 4)) >>> abjad.mutate(staff[:]).rewrite_meter(meter) >>> auxjad.mutate(staff[:]).prettify_rewrite_meter(meter) >>> abjad.f(staff) \new Staff { \time 3/4 c'8 d'4 e'4 f'8 } .. figure:: ../_images/prettify_rewrite_meter-4wg3grpb94p.png Similarly to the example before, set ``fuse_triple_meter`` to ``False`` to disable this behaviour. >>> staff = abjad.Staff(r"\time 3/4 c'8 d'4 e'4 f'8") >>> meter = abjad.Meter((3, 4)) >>> abjad.mutate(staff[:]).rewrite_meter(meter) >>> auxjad.mutate(staff[:]).prettify_rewrite_meter( ... meter, ... fuse_triple_meter=False, ... ) >>> abjad.f(staff) \new Staff { \time 3/4 c'8 d'8 ~ d'8 e'8 ~ e'8 f'8 } .. figure:: ../_images/prettify_rewrite_meter-l16ostzscta.png ``extract_trivial_tuplets``: By default, this function extracts the contents of tuples that consist solely of rests, or solely of tied notes and chords. >>> staff = abjad.Staff( ... r"\times 2/3 {c'4 ~ c'8} \times 2/3 {d'8 r4} " ... r"\times 2/3 {r8 r8 r8} \times 2/3 {<e' g'>8 ~ <e' g'>4}" ... ) >>> meter = abjad.Meter((4, 4)) >>> abjad.mutate(staff[:]).rewrite_meter(meter) >>> abjad.mutate(staff[:]).prettify_rewrite_meter(meter) >>> abjad.f(staff) \new Staff { c'4 \times 2/3 { d'8 r4 } r4 <e' g'>4 } .. figure:: ../_images/prettify_rewrite_meter-a72jx4fc1xd.png Set ``extract_trivial_tuplets`` to ``False`` to disable this behaviour. >>> staff = abjad.Staff( ... r"\times 2/3 {c'4 ~ c'8} \times 2/3 {d'8 r4} " ... r"\times 2/3 {r8 r8 r8} \times 2/3 {<e' g'>8 ~ <e' g'>4}" ... ) >>> meter = abjad.Meter((4, 4)) >>> abjad.mutate(staff[:]).rewrite_meter(meter) >>> abjad.mutate(staff[:]).prettify_rewrite_meter( ... meter, ... extract_trivial_tuplets=False, ... ) >>> abjad.f(staff) \new Staff { \times 2/3 { c'4. } \times 2/3 { d'8 r4 } \times 2/3 { r4. } \times 2/3 { <e' g'>4. } } .. figure:: ../_images/prettify_rewrite_meter-v9q0ka94qcd.png ``split_quadruple_meter`` When applying |abjad.mutate().rewrite_meter()| to a selection with quadruple meter and without using a deeper ``boundary_depth`` than the default, the resulting notation will often have leaves crossing the third beat of the measure, as shown below. >>> staff = abjad.Staff( ... r"c'4 d'2 r4" ... r"e'4. f'2 g'8" ... r"a'4. b'4. c''4" ... r"d''16 e''8. f''4. g''4 a''8" ... ) >>> meter = abjad.Meter((4, 4)) >>> for measure in abjad.select(staff[:]).group_by_measure(): ... abjad.mutate(measure).rewrite_meter(meter) >>> abjad.f(staff) \new Staff { c'4 d'2 r4 e'4. f'8 ~ f'4. g'8 a'4. b'4. c''4 d''16 e''8. f''4. g''8 ~ g''8 a''8 } .. figure:: ../_images/prettify_rewrite_meter-1wvhrjife1i.png This function tests those leaves against a series of rules, splitting them when the tests fails. In the case shown above, the first two bars are very easy to read rhythmically, but the third and fourth are less so. This is due to the dotted crotchet, which starts off a beat, crossing the third beat of the measure. This function will split these sort of leaves as shown below. >>> abjad.mutate(staff[:]).prettify_rewrite_meter(meter) >>> abjad.f(staff) \new Staff { c'4 d'2 r4 e'4. f'8 ~ f'4. g'8 a'4. b'8 ~ b'4 c''4 d''16 e''8. f''4 ~ f''8 g''4 a''8 } .. figure:: ../_images/prettify_rewrite_meter-56dy04wjzg.png Set ``split_quadruple_meter`` to ``False`` to disable this behaviour. >>> staff = abjad.Staff( ... r"c'4 d'2 r4" ... r"e'4. f'2 g'8" ... r"a'4. b'4. c''4" ... r"d''16 e''8. f''4. g''4 a''8" ... ) >>> meter = abjad.Meter((4, 4)) >>> for measure in abjad.select(staff[:]).group_by_measure(): ... abjad.mutate(measure).rewrite_meter(meter) >>> abjad.mutate(staff[:]).prettify_rewrite_meter( ... meter, ... split_quadruple_meter=False, ... ) >>> abjad.f(staff) \new Staff { c'4 d'2 r4 e'4. f'8 ~ f'4. g'8 a'4. b'4. c''4 d''16 e''8. f''4. g''4 a''8 } .. figure:: ../_images/prettify_rewrite_meter-ww1x0zsxlnd.png .. tip:: Use :func:`auxjad.auto_rewrite_meter()` to automatically apply |abjad.mutate().rewrite_meter()| and |auxjad.mutate().prettify_rewrite_meter()| to a container with multiple time signatures. .. warning:: The input selection must be a contiguous logical voice. When dealing with a container with multiple subcontainers (e.g. a score containing multiple staves), the best approach is to cycle through these subcontainers, applying this function to them individually. """ if not isinstance(selection, abjad.Selection): raise TypeError("first argument must be 'abjad.Selection'") if not selection.leaves().are_contiguous_logical_voice(): raise ValueError("first argument must be contiguous logical voice") if not isinstance(meter, (abjad.Meter, abjad.TimeSignature)): raise TypeError("argument must be 'abjad.Meter' or " "'abjad.TimeSignature'") if not isinstance(fuse_across_groups_of_beats, bool): raise TypeError("'fuse_across_groups_of_beats' must be 'bool'") if not isinstance(fuse_quadruple_meter, bool): raise TypeError("'fuse_quadruple_meter' must be 'bool'") if not isinstance(fuse_triple_meter, bool): raise TypeError("'fuse_triple_meter' must be 'bool'") if not isinstance(extract_trivial_tuplets, bool): raise TypeError("'extract_trivial_tuplets' must be 'bool'") if not isinstance(split_quadruple_meter, bool): raise TypeError("'split_quadruple_meter' must be 'bool'") if isinstance(meter, abjad.TimeSignature): meter = abjad.Meter(meter.pair) logical_ties = selection.logical_ties(pitched=True) if len(logical_ties) == 0: return first_leaf = selection.leaf(0) initial_offset = abjad.inspect(first_leaf).timespan().start_offset base = 1 / meter.denominator def _merge_indicators_then_fuse(logical_tie): last_indicators = abjad.inspect(logical_tie[-1]).indicators() initial_indicators = abjad.inspect(logical_tie[0]).indicators() initial_indicators_types = tuple( type(indicator) for indicator in initial_indicators) abjad.mutate(logical_tie).fuse() for indicator in last_indicators: if isinstance(indicator, ( abjad.Dynamic, abjad.StopSlur, abjad.StopGroup, abjad.StopHairpin, abjad.StopTextSpan, abjad.StopTrillSpan, abjad.StopPianoPedal, abjad.StopPhrasingSlur, )): if not isinstance(indicator, initial_indicators_types): abjad.attach(indicator, logical_tie[0]) for logical_tie in logical_ties.filter_duration("==", base / 2): offset = abjad.inspect(logical_tie).timespan().start_offset offset -= initial_offset offset %= base if offset == base / 4: _merge_indicators_then_fuse(logical_tie) if fuse_across_groups_of_beats: for logical_tie in logical_ties.filter_duration("==", base): offset = abjad.inspect(logical_tie).timespan().start_offset offset -= initial_offset offset %= meter.duration offset_mod = offset % base if offset_mod == base / 2: if (not offset + base / 2 in meter.depthwise_offset_inventory[1]): _merge_indicators_then_fuse(logical_tie) if fuse_quadruple_meter and meter.numerator == 4: for logical_tie in logical_ties.filter_duration("==", base): offset = abjad.inspect(logical_tie).timespan().start_offset offset -= initial_offset offset %= meter.duration offset_mod = offset % base if offset_mod == base / 2: if not offset + base / 2 in ( abjad.Offset(0, 1), abjad.Offset(2 * base), abjad.Offset(4 * base), ): _merge_indicators_then_fuse(logical_tie) if fuse_triple_meter and meter.numerator == 3: for logical_tie in logical_ties.filter_duration("==", base): offset = abjad.inspect(logical_tie).timespan().start_offset offset -= initial_offset offset %= meter.duration offset_mod = offset % base if offset_mod == base / 2: if not offset + base / 2 in ( abjad.Offset(0, 1), abjad.Offset(3 * base), ): _merge_indicators_then_fuse(logical_tie) logical_ties = selection.logical_ties() # splitting not only pitched if split_quadruple_meter and meter.numerator == 4: half_point_offset = abjad.Offset(2 * base) for logical_tie in logical_ties: offset0 = abjad.inspect(logical_tie).timespan().start_offset offset0 -= initial_offset offset0 %= meter.duration if offset0 == abjad.Offset(0, 1): # do not split things like c'1, c'2.. r8, c'2. r4, etc. continue offset1 = abjad.inspect(logical_tie).timespan().stop_offset offset1 -= initial_offset offset1 %= meter.duration if offset1 == abjad.Offset(0, 1): offset1 = abjad.Offset(meter.duration) if (offset0 % abjad.Offset(base) == abjad.Offset(0, 1) and offset1 % abjad.Offset(base) == abjad.Offset(0, 1)): # do not split things like r4 c'2. continue if offset0 < half_point_offset < offset1: if (offset1 == abjad.Offset(meter.duration) and len(logical_tie) == 1): # do not split r8 c'2.., r16 c'2..., etc. break if any( abjad.inspect(leaf).duration() == abjad.Duration(2 * base) for leaf in logical_tie): # do not split r8 c'8~c'2 r4, r16 c'8.~c'2~c'8 r8, etc. break # do not split tuplets getter = abjad.select().logical_ties() result = selection.tuplets().map(getter).flatten() if logical_tie in result: break duration = abjad.Duration(half_point_offset - offset0) abjad.mutate(logical_tie).split([duration]) if extract_trivial_tuplets: extract_trivial_tuplets_function(selection)
def reposition_slurs( selection: abjad.Selection, *, allow_slurs_under_rests: bool = False, close_unterminated_final_slur: bool = True, ) -> None: r"""Mutates an input |abjad.Selection| in place and has no return value; this function repositions all slurs that starts or ends on rests. Basic usage: This function will shift slurs that ends on rests to the previous pitched leaf. >>> staff = abjad.Staff(r"c'1( d'2 r2) r1 e'1") >>> abjad.f(staff) \new Staff { c'1 ( d'2 r2 ) r1 e'1 } .. figure:: ../_images/reposition_slurs-uxji4xx6ftk.png >>> staff = abjad.Staff(r"c'1( d'2 r2) r1 e'1") >>> auxjad.mutate(staff[:]).reposition_slurs() >>> abjad.f(staff) \new Staff { c'1 ( d'2 ) r2 r1 e'1 } .. figure:: ../_images/reposition_slurs-7nnp5cttm4y.png .. note:: Auxjad automatically adds this function as an extension method to |abjad.mutate()|. It can thus be used from either :func:`auxjad.mutate()` or |abjad.mutate()|. Therefore, the two lines below are equivalent: >>> auxjad.mutate(staff[:]).reposition_slurs() >>> abjad.mutate(staff[:]).reposition_slurs() Rests: Slurs starting on rests are shifted to the next pitched leaf. >>> staff = abjad.Staff(r"c'1 r2( d'2 e'1)") >>> abjad.f(staff) \new Staff { c'1 r2 ( d'2 e'1 ) } .. figure:: ../_images/reposition_slurs-2j7hgqd7bt1.png >>> staff = abjad.Staff(r"c'1 r2( d'2 e'1)") >>> auxjad.mutate(staff[:]).reposition_slurs() >>> abjad.f(staff) \new Staff { c'1 r2 d'2 ( e'1 ) } .. figure:: ../_images/reposition_slurs-i957u1wt30m.png Multiple rests: This function also works when multiple rests are present. >>> staff = abjad.Staff(r"c'1( d'2 r2 r1) e'1") >>> abjad.f(staff) \new Staff { c'1 ( d'2 r2 r1 ) e'1 } .. figure:: ../_images/reposition_slurs-v76u42x7idk.png >>> staff = abjad.Staff(r"c'1( d'2 r2 r1) e'1") >>> auxjad.mutate(staff[:]).reposition_slurs() >>> abjad.f(staff) \new Staff { c'1 ( d'2 ) r2 r1 e'1 } .. figure:: ../_images/reposition_slurs-burs1t0daid.png ``allow_slurs_under_rests``: By default, a slur crossing a rest is broken into two. >>> staff = abjad.Staff(r"c'1( d'2 r2 e'1 f'1)") >>> auxjad.mutate(staff[:]).reposition_slurs() >>> abjad.f(staff) \new Staff { c'1 ( d'2 ) r2 e'1 ( f'1 ) } .. figure:: ../_images/reposition_slurs-8wb7orpt285.png Set the optional keyword argument ``allow_slurs_under_rests`` to ``True`` to allow slurs under rests. >>> staff = abjad.Staff(r"c'1( d'2 r2 e'1 f'1)") >>> auxjad.mutate(staff[:]).reposition_slurs( ... allow_slurs_under_rests=True, ... ) >>> abjad.f(staff) \new Staff { c'1 ( d'2 r2 e'1 f'1 ) } .. figure:: ../_images/reposition_slurs-ftb59kz6u8j.png ``close_unterminated_final_slur``: By default, unterminated slurs at the end of the selection are closed when possible or removed when not. >>> staff = abjad.Staff(r"c'1( d'2 r2 e'2 f'2) g'1( a'1") >>> auxjad.mutate(staff[:]).reposition_slurs() >>> abjad.f(staff) \new Staff { c'1 ( d'2 ) r2 e'2 ( f'2 ) g'1 ( a'1 ) } .. figure:: ../_images/reposition_slurs-70dli8e0kqr.png Set the optional keyword argument ``close_unterminated_final_slur`` to ``False`` to disable this behaviour. >>> staff = abjad.Staff(r"c'1( d'2 r2 e'2 f'2) g'1( a'1") >>> auxjad.mutate(staff[:]).reposition_slurs( ... close_unterminated_final_slur=False, ... ) >>> abjad.f(staff) \new Staff { c'1 ( d'2 ) r2 e'2 ( f'2 ) g'1 ( a'1 } .. figure:: ../_images/reposition_slurs-1usa2dezl45.png When there are no pitched leaves left after an unterminated open slur, it is removed. >>> staff = abjad.Staff(r"c'1( d'2 r2 e'2 f'2) g'1( r1") >>> auxjad.mutate(staff[:]).reposition_slurs() >>> abjad.f(staff) \new Staff { c'1 ( d'2 ) r2 e'2 ( f'2 ) g'1 r1 } .. figure:: ../_images/reposition_slurs-a0uakfcltuf.png .. note:: Duplicate slur starts or stops are removed. Note that the score output will not change, as LilyPond also ignores duplicate slurs, but the output of |abjad.f()| will be cleaner. >>> staff = abjad.Staff(r"c'1( d'2) e'2) f'2( g'2( a'1)") >>> auxjad.mutate(staff[:]).reposition_slurs() >>> abjad.f(staff) \new Staff { c'1 ( d'2 ) e'2 f'2 ( g'2 a'1 ) } .. figure:: ../_images/reposition_slurs-0ugn322x3tr.png .. warning:: The input selection must be a contiguous logical voice. When dealing with a container with multiple subcontainers (e.g. a score containing multiple staves), the best approach is to cycle through these subcontainers, applying this function to them individually. """ if not isinstance(selection, abjad.Selection): raise TypeError("argument must be 'abjad.Container' or child class") if not selection.leaves().are_contiguous_logical_voice(): raise ValueError("argument must be contiguous logical voice") if not isinstance(allow_slurs_under_rests, bool): raise TypeError("'allow_slurs_under_rests' must be 'bool'") if not isinstance(close_unterminated_final_slur, bool): raise TypeError("'close_unterminated_final_slur' must be 'bool'") leaves = selection.leaves() # checking for final unfinished slurs if close_unterminated_final_slur: for leaf in leaves[::-1]: inspector = abjad.inspect(leaf) if inspector.indicator(abjad.StartSlur) is not None: if leaf is leaves[-1]: abjad.detach(abjad.StartSlur(), leaf) elif (abjad.inspect(leaves[-1]).indicator(abjad.StopSlur) is None): abjad.attach(abjad.StopSlur(), leaves[-1]) if inspector.indicator(abjad.StopSlur) is not None: break # checking for duplicate open or close slurs start_slur_count = 0 stop_slur_count = 0 for leaf in leaves: inspector = abjad.inspect(leaf) if inspector.indicator(abjad.StartSlur) is not None: start_slur_count += 1 stop_slur_count = 0 if start_slur_count > 1: abjad.detach(abjad.StartSlur(), leaf) elif inspector.indicator(abjad.StopSlur) is not None: stop_slur_count += 1 start_slur_count = 0 if stop_slur_count > 1: abjad.detach(abjad.StopSlur(), leaf) # shifting slurs from rests to notes shifted_startslur = None for leaf in leaves: inspector = abjad.inspect(leaf) if isinstance(leaf, (abjad.Rest, abjad.MultimeasureRest)): if inspector.indicator(abjad.StartSlur) is not None: shifted_startslur = inspector.indicator(abjad.StartSlur) abjad.detach(abjad.StartSlur, leaf) else: if inspector.indicator(abjad.StartSlur) is None: if shifted_startslur is not None: abjad.attach(shifted_startslur, leaf) shifted_startslur = None shifted_stopslur = None for leaf in leaves[::-1]: inspector = abjad.inspect(leaf) if isinstance(leaf, (abjad.Rest, abjad.MultimeasureRest)): if inspector.indicator(abjad.StopSlur) is not None: shifted_stopslur = inspector.indicator(abjad.StopSlur) abjad.detach(abjad.StopSlur, leaf) else: if inspector.indicator(abjad.StopSlur) is None: if shifted_stopslur is not None: abjad.attach(shifted_stopslur, leaf) shifted_stopslur = None # splitting slurs under rests if not allow_slurs_under_rests: active_slur = False for index, leaf in enumerate(leaves): inspector = abjad.inspect(leaf) if inspector.indicator(abjad.StartSlur) is not None: active_slur = True elif inspector.indicator(abjad.StopSlur) is not None: if not active_slur: abjad.detach(abjad.StopSlur, leaf) active_slur = False if (isinstance(leaf, (abjad.Rest, abjad.MultimeasureRest)) and active_slur): previous_leaf = abjad.select(leaf).with_previous_leaf()[0] if (abjad.inspect(previous_leaf).indicator(abjad.StopSlur) is None): abjad.attach(abjad.StopSlur(), previous_leaf) for next_leaf in leaves[index + 1:]: if not isinstance(next_leaf, (abjad.Rest, abjad.MultimeasureRest)): if (abjad.inspect(next_leaf).indicator(abjad.StartSlur) is None): abjad.attach(abjad.StartSlur(), next_leaf) break for leaf in leaves: inspector = abjad.inspect(leaf) if (inspector.indicator(abjad.StartSlur) is not None and inspector.indicator(abjad.StopSlur) is not None): abjad.detach(abjad.StartSlur, leaf) abjad.detach(abjad.StopSlur, leaf) # removing slurs spanning a single logical tie for logical_tie in selection.logical_ties(): inspector_head = abjad.inspect(logical_tie[0]) inspector_tail = abjad.inspect(logical_tie[-1]) if (inspector_head.indicator(abjad.StartSlur) is not None and inspector_tail.indicator(abjad.StopSlur) is not None): abjad.detach(abjad.StartSlur, logical_tie[0]) abjad.detach(abjad.StopSlur, logical_tie[-1])