"""
Timespan classes and functions.
"""
import os
import re
import abjad
from abjadext import rmakers
from . import handlers
from .commands import RhythmCommand
env = os.path.expanduser("~")
assert isinstance(env, str)
abjad_stylesheet = os.path.join(env, "abjad/docs/source/_stylesheets/abjad.ily")
dir_path = os.path.split(__file__)[0]
rhythm_stylesheet = os.path.join(dir_path, "_rhythm_sketch_stylesheet.ily")
[docs]class SilentTimespan(abjad.Timespan):
r"""
Silent Timespan
.. container:: example
>>> span = evans.SilentTimespan(0, 1)
>>> abjad.show(span) # doctest: +SKIP
.. docs::
>>> print(abjad.storage(span))
evans.SilentTimespan(
abjad.Offset((0, 1)),
abjad.Offset((1, 1))
)
"""
def __init__(self, start_offset, stop_offset, annotation=None):
abjad.Timespan.__init__(self, start_offset, stop_offset)
self.annotation = annotation
[docs] def __str__(self):
return abjad.storage(self)
[docs] def __repr__(self):
return abjad.storage(self)
def _as_postscript(
self, postscript_x_offset, postscript_y_offset, postscript_scale
):
start = float(self._start_offset) * postscript_scale
start -= postscript_x_offset
stop = float(self._stop_offset) * postscript_scale
stop -= postscript_x_offset
ps = abjad.Postscript()
ps = ps.setdash([0.5])
ps = ps.moveto(start, postscript_y_offset)
ps = ps.lineto(stop, postscript_y_offset)
ps = ps.stroke()
ps = ps.moveto(start, postscript_y_offset + 0.75)
ps = ps.lineto(start, postscript_y_offset - 0.75)
ps = ps.setdash()
ps = ps.stroke()
ps = ps.moveto(stop, postscript_y_offset + 0.75)
ps = ps.lineto(stop, postscript_y_offset - 0.75)
ps = ps.stroke()
return ps
[docs]class TimespanMaker:
r"""
.. container:: example
>>> timespan_maker = evans.TimespanMaker(
... denominator=8,
... total_duration=abjad.Duration(15, 2),
... )
...
>>> counts = [3, 5, -3, 4, 7, -1]
>>> timespan_list = timespan_maker(counts, max_duration=6, voice_name="A")
>>> abjad.show(timespan_list, scale=0.5) # doctest: +SKIP
.. docs::
>>> print(abjad.storage(timespan_list))
abjad.TimespanList(
[
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((0, 1)),
stop_offset=abjad.Offset((3, 8)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((3, 8)),
stop_offset=abjad.Offset((1, 1)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((11, 8)),
stop_offset=abjad.Offset((15, 8)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((15, 8)),
stop_offset=abjad.Offset((21, 8)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((23, 8)),
stop_offset=abjad.Offset((13, 4)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((13, 4)),
stop_offset=abjad.Offset((31, 8)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((17, 4)),
stop_offset=abjad.Offset((19, 4)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((19, 4)),
stop_offset=abjad.Offset((11, 2)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((23, 4)),
stop_offset=abjad.Offset((49, 8)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((49, 8)),
stop_offset=abjad.Offset((27, 4)),
annotation='A',
),
]
)
.. container:: example
>>> timespan_maker = evans.TimespanMaker(
... denominator=8,
... total_duration=abjad.Duration(15, 2),
... )
...
>>> counts = [3, 1, -2, 2, 3, -1, 2, -2]
>>> timespan_list_1 = timespan_maker(counts, max_duration=6, voice_name="A")
>>> timespan_list_2 = timespan_maker(
... counts,
... max_duration=6,
... voice_name="B",
... rotation=2,
... translation=1
... )
...
>>> timespan_list_3 = timespan_maker(
... counts,
... max_duration=6,
... voice_name="C",
... rotation=5,
... translation=3
... )
...
>>> timespan_list_4 = timespan_maker(
... counts,
... max_duration=6,
... voice_name="D",
... rotation=3,
... translation=2
... )
...
>>> timespanlist = abjad.TimespanList()
>>> for span in timespan_list_1:
... timespanlist.append(span)
...
>>> for span in timespan_list_2:
... timespanlist.append(span)
...
>>> for span in timespan_list_3:
... timespanlist.append(span)
...
>>> for span in timespan_list_4:
... timespanlist.append(span)
...
>>> abjad.show(timespanlist, scale=0.5, key="annotation") # doctest: +SKIP
.. docs::
>>> print(abjad.storage(timespanlist))
abjad.TimespanList(
[
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((0, 1)),
stop_offset=abjad.Offset((3, 8)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((3, 8)),
stop_offset=abjad.Offset((1, 2)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((3, 4)),
stop_offset=abjad.Offset((1, 1)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((1, 1)),
stop_offset=abjad.Offset((11, 8)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((3, 2)),
stop_offset=abjad.Offset((7, 4)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((2, 1)),
stop_offset=abjad.Offset((19, 8)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((19, 8)),
stop_offset=abjad.Offset((5, 2)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((11, 4)),
stop_offset=abjad.Offset((3, 1)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((3, 1)),
stop_offset=abjad.Offset((27, 8)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((7, 2)),
stop_offset=abjad.Offset((15, 4)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((4, 1)),
stop_offset=abjad.Offset((35, 8)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((35, 8)),
stop_offset=abjad.Offset((9, 2)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((19, 4)),
stop_offset=abjad.Offset((5, 1)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((5, 1)),
stop_offset=abjad.Offset((43, 8)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((11, 2)),
stop_offset=abjad.Offset((23, 4)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((6, 1)),
stop_offset=abjad.Offset((51, 8)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((51, 8)),
stop_offset=abjad.Offset((13, 2)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((27, 4)),
stop_offset=abjad.Offset((7, 1)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((7, 1)),
stop_offset=abjad.Offset((59, 8)),
annotation='A',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((3, 8)),
stop_offset=abjad.Offset((5, 8)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((5, 8)),
stop_offset=abjad.Offset((1, 1)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((9, 8)),
stop_offset=abjad.Offset((11, 8)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((13, 8)),
stop_offset=abjad.Offset((2, 1)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((2, 1)),
stop_offset=abjad.Offset((17, 8)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((19, 8)),
stop_offset=abjad.Offset((21, 8)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((21, 8)),
stop_offset=abjad.Offset((3, 1)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((25, 8)),
stop_offset=abjad.Offset((27, 8)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((29, 8)),
stop_offset=abjad.Offset((4, 1)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((4, 1)),
stop_offset=abjad.Offset((33, 8)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((35, 8)),
stop_offset=abjad.Offset((37, 8)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((37, 8)),
stop_offset=abjad.Offset((5, 1)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((41, 8)),
stop_offset=abjad.Offset((43, 8)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((45, 8)),
stop_offset=abjad.Offset((6, 1)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((6, 1)),
stop_offset=abjad.Offset((49, 8)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((51, 8)),
stop_offset=abjad.Offset((53, 8)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((53, 8)),
stop_offset=abjad.Offset((7, 1)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((57, 8)),
stop_offset=abjad.Offset((59, 8)),
annotation='B',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((1, 2)),
stop_offset=abjad.Offset((3, 4)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((1, 1)),
stop_offset=abjad.Offset((11, 8)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((11, 8)),
stop_offset=abjad.Offset((3, 2)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((7, 4)),
stop_offset=abjad.Offset((2, 1)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((2, 1)),
stop_offset=abjad.Offset((19, 8)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((5, 2)),
stop_offset=abjad.Offset((11, 4)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((3, 1)),
stop_offset=abjad.Offset((27, 8)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((27, 8)),
stop_offset=abjad.Offset((7, 2)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((15, 4)),
stop_offset=abjad.Offset((4, 1)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((4, 1)),
stop_offset=abjad.Offset((35, 8)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((9, 2)),
stop_offset=abjad.Offset((19, 4)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((5, 1)),
stop_offset=abjad.Offset((43, 8)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((43, 8)),
stop_offset=abjad.Offset((11, 2)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((23, 4)),
stop_offset=abjad.Offset((6, 1)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((6, 1)),
stop_offset=abjad.Offset((51, 8)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((13, 2)),
stop_offset=abjad.Offset((27, 4)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((7, 1)),
stop_offset=abjad.Offset((59, 8)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((59, 8)),
stop_offset=abjad.Offset((15, 2)),
annotation='C',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((1, 4)),
stop_offset=abjad.Offset((1, 2)),
annotation='D',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((1, 2)),
stop_offset=abjad.Offset((7, 8)),
annotation='D',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((1, 1)),
stop_offset=abjad.Offset((5, 4)),
annotation='D',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((3, 2)),
stop_offset=abjad.Offset((15, 8)),
annotation='D',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((15, 8)),
stop_offset=abjad.Offset((2, 1)),
annotation='D',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((9, 4)),
stop_offset=abjad.Offset((5, 2)),
annotation='D',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((5, 2)),
stop_offset=abjad.Offset((23, 8)),
annotation='D',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((3, 1)),
stop_offset=abjad.Offset((13, 4)),
annotation='D',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((7, 2)),
stop_offset=abjad.Offset((31, 8)),
annotation='D',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((31, 8)),
stop_offset=abjad.Offset((4, 1)),
annotation='D',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((17, 4)),
stop_offset=abjad.Offset((9, 2)),
annotation='D',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((9, 2)),
stop_offset=abjad.Offset((39, 8)),
annotation='D',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((5, 1)),
stop_offset=abjad.Offset((21, 4)),
annotation='D',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((11, 2)),
stop_offset=abjad.Offset((47, 8)),
annotation='D',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((47, 8)),
stop_offset=abjad.Offset((6, 1)),
annotation='D',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((25, 4)),
stop_offset=abjad.Offset((13, 2)),
annotation='D',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((13, 2)),
stop_offset=abjad.Offset((55, 8)),
annotation='D',
),
abjad.AnnotatedTimespan(
start_offset=abjad.Offset((7, 1)),
stop_offset=abjad.Offset((29, 4)),
annotation='D',
),
]
)
"""
__slots__ = ["_denominator", "_total_duration"]
def __init__(self, denominator, total_duration):
self._denominator = denominator
self._total_duration = abjad.Duration(total_duration)
[docs] def __str__(self):
return abjad.storage(self)
[docs] def __repr__(self):
return abjad.storage(self)
[docs] def __call__(
self, counts, max_duration=None, translation=0, rotation=None, voice_name=None
):
if rotation:
counts = counts[rotation:] + counts[:rotation]
counts = self._ready_counts(counts, translation)
denominator = self.denominator
increment_total = 0 + translation
timespan_list = abjad.TimespanList([])
for count in counts:
if count < 0:
increment_total += abs(count)
continue
start = increment_total
stop = start + count
if max_duration is not None:
stop = (max_duration + start) if count > max_duration else stop
timespan_list.append(
abjad.AnnotatedTimespan(
start_offset=(start, denominator),
stop_offset=(stop, denominator),
annotation=voice_name,
)
)
increment_total += count
return timespan_list
def _ready_counts(self, counts, translation):
total_duration = self.total_duration
normalized_duration = total_duration.with_denominator(self.denominator)
total_numerator = normalized_duration.numerator - translation
counts = abjad.CyclicTuple(counts)
repeated_counts = []
increment = 0
previous_sum = 0
while previous_sum < total_numerator:
new_sum = sum(abs(_) for _ in repeated_counts)
count = counts[increment]
if new_sum + count <= total_numerator:
repeated_counts.append(count)
increment += 1
continue
break
return repeated_counts
@property
def denominator(self):
return self._denominator
@property
def total_duration(self):
return self._total_duration
[docs]class TimespanSpecifier:
def __init__(self, voice_name=None, handler=None):
self.voice_name = voice_name
self.handler = handler
[docs] def __str__(self):
return abjad.storage(self)
[docs] def __repr__(self):
return abjad.storage(self)
[docs]def make_split_list(timespan_list, offsets):
return abjad.TimespanList(
[
timespan
for timespanlist in timespan_list.split_at_offsets(offsets)
for timespan in timespanlist
]
)
[docs]def collect_offsets(timespan_list):
offsets = [timespan.start_offset for timespan in timespan_list]
for stop_offset in [timespan.stop_offset for timespan in timespan_list]:
if stop_offset not in offsets:
offsets.append(stop_offset)
offsets.sort()
return offsets
[docs]def make_showable_list(timespan_lists):
master_list = abjad.TimespanList([])
for i, timespan_list in enumerate(timespan_lists):
for timespan in timespan_list:
if isinstance(timespan, SilentTimespan):
new_span = SilentTimespan(
start_offset=timespan.start_offset,
stop_offset=timespan.stop_offset,
annotation=str(i + 1),
)
else:
new_span = abjad.AnnotatedTimespan(
start_offset=timespan.start_offset,
stop_offset=timespan.stop_offset,
annotation=str(i + 1),
)
master_list.extend([new_span])
master_list.sort()
return master_list
[docs]def add_silent_timespans(timespan_list, specifier=None):
silent_timespans = abjad.TimespanList(
[
abjad.Timespan(
start_offset=0, stop_offset=max(_.stop_offset for _ in timespan_list)
)
]
)
for timespan in timespan_list:
silent_timespans -= timespan
for silent_timespan in silent_timespans:
timespan_list.extend(
[
SilentTimespan(
start_offset=silent_timespan.start_offset,
stop_offset=silent_timespan.stop_offset,
annotation=specifier,
)
]
)
return timespan_list
[docs]def add_silences_to_timespan_lists(timespan_lists):
for timespan_list in timespan_lists:
timespan_list = add_silent_timespans(timespan_list)
timespan_list.sort()
[docs]def add_silences_to_timespan_dict(timespan_dict, specifier=None):
max_stop_offset = max(_.stop_offset for _ in timespan_dict.values())
for timespan_list in timespan_dict.values():
silences = SilentTimespan(0, max_stop_offset)
for timespan in timespan_list:
silences -= timespan
for silence in silences:
silence.annotation = specifier
timespan_list.extend([silence])
timespan_list.sort()
[docs]def talea_timespans(talea, advancement=0):
talea = abjad.new(talea)
talea = talea.advance(advancement)
timespans = abjad.TimespanList([])
total_duration = 0
for duration in talea:
start = total_duration
stop = total_duration + abs(duration)
if duration < 0:
timespan = SilentTimespan(
start_offset=start, stop_offset=stop, annotation=None
)
else:
timespan = abjad.AnnotatedTimespan(
start_offset=start, stop_offset=stop, annotation=None
)
timespans.append(timespan)
total_duration += abs(duration)
return timespans
[docs]def to_digit(string):
r"""
.. container:: example
>>> evans.to_digit("2")
2
"""
return int(string) if string.isdigit() else string
[docs]def sorted_keys(text):
"""
.. container:: example
>>> evans.sorted_keys("Voice 1")
['Voice ', 1, '']
"""
return [to_digit(_) for _ in re.split(r"(\d+)", text)]
[docs]def human_sorted_keys(pair):
key, timespan = pair
values = [to_digit(_) for _ in key.split()]
hashable_key = tuple(values)
return hashable_key
[docs]def intercalate_silences(rhythm_command_list, voice_names=None):
global_timespan = abjad.Timespan(
start_offset=0,
stop_offset=max(_.timespan.stop_offset for _ in rhythm_command_list),
)
silence_maker = handlers.RhythmHandler(
rmakers.stack(
rmakers.NoteRhythmMaker(),
rmakers.force_rest(abjad.select().leaves(pitched=True)),
),
name="silence_maker",
)
if voice_names is None:
voice_names = sorted(set(_.voice_name for _ in rhythm_command_list))
for voice_name in voice_names:
timespan_list = abjad.TimespanList(
[_.timespan for _ in rhythm_command_list if _.voice_name == voice_name]
)
silences = abjad.TimespanList([global_timespan])
for timespan in timespan_list:
silences -= timespan
for timespan in silences:
new_command = RhythmCommand(
voice_name,
timespan,
silence_maker,
)
rhythm_command_list.append(new_command)