Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor tuplet simplification #655

Merged
merged 4 commits into from
Jul 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 78 additions & 1 deletion abjad/tools/agenttools/IterationAgent.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ def by_leaf(

.. container:: example

**Example 1.** Iterates leaves:
**Example 1.** Iterates leaves:

::

Expand Down Expand Up @@ -550,6 +550,7 @@ def by_logical_tie(
nontrivial=False,
pitched=False,
reverse=False,
parentage_mask=None,
):
r'''Iterates client by logical tie.

Expand Down Expand Up @@ -626,26 +627,102 @@ def by_logical_tie(
LogicalTie(Note("c'4"), Note("c'16"))
LogicalTie(Note("f'4"), Note("f'16"))

.. container:: example

**Example 5.** Iterates logical ties masked by parentage.

.. note::

When iterating logical ties in a container, the yielded logical
ties may contain leaves outside that container's parentage. By
specifying a parentage mask, composers can constrain the
contents of the yielded logical ties to only those leaves
actually within the parentage of the container under iteration.

::

>>> staff = Staff("{ c'1 ~ } { c'2 d'2 ~ } { d'1 }")
>>> for logical_tie in iterate(staff[1]).by_logical_tie():
... logical_tie
...
LogicalTie(Note("c'1"), Note("c'2"))
LogicalTie(Note("d'2"), Note("d'1"))

::

>>> for logical_tie in iterate(staff[1]).by_logical_tie(
... parentage_mask=staff[1]):
... logical_tie
...
LogicalTie(Note("c'2"),)
LogicalTie(Note("d'2"),)

Returns generator.
'''
from abjad.tools import selectiontools
nontrivial = bool(nontrivial)
prototype = scoretools.Leaf
if pitched:
prototype = (scoretools.Chord, scoretools.Note)
leaf, yielded = None, False
if not reverse:
for leaf in self.by_class(prototype):
yielded = False
tie_spanners = leaf._get_spanners(spannertools.Tie)
if not tie_spanners or \
tuple(tie_spanners)[0]._is_my_last_leaf(leaf):
logical_tie = leaf._get_logical_tie()
if parentage_mask:
logical_tie = selectiontools.LogicalTie(
x for x in logical_tie
if parentage_mask in x._get_parentage()
)
if not logical_tie:
continue
if not nontrivial or not logical_tie.is_trivial:
yielded = True
yield logical_tie
if leaf is not None and not yielded:
if tie_spanners and \
tuple(tie_spanners)[0]._is_my_first_leaf(leaf):
logical_tie = leaf._get_logical_tie()
if parentage_mask:
logical_tie = selectiontools.LogicalTie(
x for x in logical_tie
if parentage_mask in x._get_parentage()
)
if not logical_tie:
return
if not nontrivial or not logical_tie.is_trivial:
yield logical_tie
else:
for leaf in self.by_class(prototype, reverse=True):
yielded = False
tie_spanners = leaf._get_spanners(spannertools.Tie)
if not(tie_spanners) or \
tuple(tie_spanners)[0]._is_my_first_leaf(leaf):
logical_tie = leaf._get_logical_tie()
if parentage_mask:
logical_tie = selectiontools.LogicalTie(
x for x in logical_tie
if parentage_mask in x._get_parentage()
)
if not logical_tie:
continue
if not nontrivial or not logical_tie.is_trivial:
yielded = True
yield logical_tie
if leaf is not None and not yielded:
if tie_spanners and \
tuple(tie_spanners)[0]._is_my_last_leaf(leaf):
logical_tie = leaf._get_logical_tie()
if parentage_mask:
logical_tie = selectiontools.LogicalTie(
x for x in logical_tie
if parentage_mask in x._get_parentage()
)
if not logical_tie:
return
if not nontrivial or not logical_tie.is_trivial:
yield logical_tie

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,40 @@ def test_agenttools_IterationAgent_by_logical_tie_08():

assert logical_ties[0] == selectiontools.LogicalTie(staff[:2])
assert logical_ties[1] == selectiontools.LogicalTie(staff[3:5])


def test_agenttools_IterationAgent_by_logical_tie_09():

staff = Staff("{ c'4 d'4 ~ } { d'4 e'4 ~ } { e'4 f'4 }")

logical_ties = list(iterate(staff[1]).by_logical_tie())

assert len(logical_ties) == 2
assert len(logical_ties[0]) == 2
assert len(logical_ties[1]) == 2
assert logical_ties[0][0] is staff[0][1]
assert logical_ties[0][1] is staff[1][0]
assert logical_ties[1][0] is staff[1][1]
assert logical_ties[1][1] is staff[2][0]


def test_agenttools_IterationAgent_by_logical_tie_10():

staff = Staff("{ c'4 d'4 ~ } { d'4 e'4 ~ } { e'4 f'4 }")

logical_ties = list(iterate(staff[1])
.by_logical_tie(parentage_mask=staff[1])
)

assert len(logical_ties) == 2
assert len(logical_ties[0]) == 1
assert len(logical_ties[1]) == 1
assert logical_ties[0][0] is staff[1][0]
assert logical_ties[1][0] is staff[1][1]


def test_agenttools_IterationAgent_by_logical_tie_11():
r'''No logical ties, but no errors either.'''
staff = Staff()
logical_ties = list(iterate(staff).by_logical_tie())
assert len(logical_ties) == 0
31 changes: 21 additions & 10 deletions abjad/tools/scoretools/Tuplet.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from abjad.tools import mathtools
from abjad.tools.scoretools.Container import Container
from abjad.tools.topleveltools import inspect_
from abjad.tools.topleveltools import iterate
from abjad.tools.topleveltools import mutate
from abjad.tools.topleveltools import override

Expand Down Expand Up @@ -354,11 +355,24 @@ def _simplify_redundant_tuplet(self):
from abjad.tools import scoretools
if not self.is_redundant:
return
leaves = self[:]
leaf_durations = [inspect_(_).get_duration() for _ in leaves]
tuplet_duration = sum(leaf_durations)
for leaf_duration, leaf in zip(leaf_durations, leaves):
leaf.written_duration = leaf_duration
leaves = []
logical_ties = list(iterate(self).by_logical_tie(parentage_mask=self))
durations = [_.get_duration() for _ in logical_ties]
tuplet_duration = sum(durations)
for i, logical_tie in enumerate(logical_ties):
duration = durations[i]
if i == len(logical_ties) - 1:
leaf = logical_tie[-1]
else:
leaf = logical_tie[0]
leaf.written_duration = duration
leaves.append(leaf)
self[:] = leaves
#leaves = self[:]
#leaf_durations = [inspect_(_).get_duration() for _ in leaves]
#tuplet_duration = sum(leaf_durations)
#for leaf_duration, leaf in zip(leaf_durations, leaves):
# leaf.written_duration = leaf_duration
if isinstance(self, scoretools.FixedDurationTuplet):
self.target_duration = tuplet_duration
else:
Expand Down Expand Up @@ -914,11 +928,8 @@ def is_redundant(self):

Returns true or false.
'''
from abjad.tools import scoretools
if not all(isinstance(_, scoretools.Leaf) for _ in self):
return False
leaf_durations = [inspect_(_).get_duration() for _ in self]
return all(_.is_assignable for _ in leaf_durations)
logical_ties = iterate(self).by_logical_tie(parentage_mask=self)
return all(_.get_duration().is_assignable for _ in logical_ties)

@property
def is_trivial(self):
Expand Down