import collections
import abjad
from abjadext import rmakers
from .Cursor import Cursor
from .SilentTimespan import SilentTimespan
from .TimespanMaker import TimespanMaker
[docs]class CascadingTimespanMaker(TimespanMaker):
r"""
A cascading timespan maker.
.. container:: example
>>> timespan_maker = tsmakers.CascadingTimespanMaker()
>>> print(abjad.storage(timespan_maker))
tsmakers.CascadingTimespanMaker(
cascade_pattern=(1,),
playing_talea=rmakers.Talea(
[4],
16
),
playing_groupings=(1,),
repeat=True,
silence_talea=rmakers.Talea(
[4],
16
),
)
.. container:: example
>>> import collections
>>> music_specifiers = collections.OrderedDict([
... ('A', None),
... ('B', None),
... ('C', None),
... ('D', None),
... ])
>>> target_timespan = abjad.Timespan(0, 2)
>>> timespan_list = timespan_maker(
... music_specifiers=music_specifiers,
... target_timespan=target_timespan,
... )
>>> ts_list = abjad.TimespanList(
... [
... abjad.AnnotatedTimespan(
... start_offset=_.start_offset,
... stop_offset=_.stop_offset,
... annotation=_.voice_name,
... )
... for _ in timespan_list
... ]
... )
>>> abjad.show(ts_list, scale=0.5, key="annotation") # doctest: +SKIP
.. docs::
>>> print(abjad.storage(timespan_list))
abjad.TimespanList(
[
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((0, 1)),
stop_offset=abjad.Offset((1, 4)),
voice_name='A',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((1, 4)),
stop_offset=abjad.Offset((1, 2)),
voice_name='B',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((1, 2)),
stop_offset=abjad.Offset((3, 4)),
voice_name='C',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((3, 4)),
stop_offset=abjad.Offset((1, 1)),
voice_name='D',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((1, 1)),
stop_offset=abjad.Offset((5, 4)),
voice_name='A',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((5, 4)),
stop_offset=abjad.Offset((3, 2)),
voice_name='B',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((3, 2)),
stop_offset=abjad.Offset((7, 4)),
voice_name='C',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((7, 4)),
stop_offset=abjad.Offset((2, 1)),
voice_name='D',
),
]
)
.. container:: example
>>> timespan_maker = abjad.new(
... timespan_maker,
... playing_groupings=(1, 2),
... cascade_pattern=(2, -1),
... )
>>> timespan_list = timespan_maker(
... music_specifiers=music_specifiers,
... target_timespan=target_timespan,
... )
>>> ts_list = abjad.TimespanList(
... [
... abjad.AnnotatedTimespan(
... start_offset=_.start_offset,
... stop_offset=_.stop_offset,
... annotation=_.voice_name,
... )
... for _ in timespan_list
... ]
... )
>>> abjad.show(ts_list, scale=0.5, key="annotation") # doctest: +SKIP
.. docs::
>>> print(abjad.storage(timespan_list))
abjad.TimespanList(
[
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((0, 1)),
stop_offset=abjad.Offset((1, 4)),
voice_name='A',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((1, 4)),
stop_offset=abjad.Offset((3, 4)),
original_stop_offset=abjad.Offset((1, 2)),
voice_name='C',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((1, 2)),
stop_offset=abjad.Offset((3, 4)),
voice_name='B',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((3, 4)),
stop_offset=abjad.Offset((5, 4)),
original_stop_offset=abjad.Offset((1, 1)),
voice_name='D',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((1, 1)),
stop_offset=abjad.Offset((5, 4)),
voice_name='C',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((5, 4)),
stop_offset=abjad.Offset((7, 4)),
original_stop_offset=abjad.Offset((3, 2)),
voice_name='A',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((3, 2)),
stop_offset=abjad.Offset((7, 4)),
voice_name='D',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((7, 4)),
stop_offset=abjad.Offset((2, 1)),
voice_name='B',
),
]
)
"""
### CLASS VARIABLES ###
__slots__ = (
"_cascade_pattern",
"_fuse_groups",
"_playing_talea",
"_playing_groupings",
"_repeat",
"_silence_talea",
)
### INITIALIZER ###
def __init__(
self,
cascade_pattern=(1,),
division_masks=None,
fuse_groups=None,
padding=None,
playing_talea=rmakers.Talea(
counts=[4],
denominator=16,
),
playing_groupings=(1,),
seed=None,
repeat=True,
silence_talea=rmakers.Talea(
counts=[4],
denominator=16,
),
timespan_specifier=None,
):
TimespanMaker.__init__(
self,
division_masks=division_masks,
padding=padding,
seed=seed,
timespan_specifier=timespan_specifier,
)
self._initialize_cascade_pattern(cascade_pattern)
self._initialize_fuse_groups(fuse_groups)
self._initialize_playing_talea(playing_talea)
self._initialize_playing_groupings(playing_groupings)
self._initialize_repeat(repeat)
self._initialize_silence_talea(silence_talea)
### PRIVATE METHODS ###
def _initialize_cascade_pattern(self, cascade_pattern):
if not isinstance(cascade_pattern, collections.Sequence):
cascade_pattern = (cascade_pattern,)
cascade_pattern = tuple(int(_) for _ in cascade_pattern)
assert all(_ != 0 for _ in cascade_pattern)
self._cascade_pattern = cascade_pattern
def _initialize_fuse_groups(self, fuse_groups):
if fuse_groups is not None:
fuse_groups = bool(fuse_groups)
self._fuse_groups = fuse_groups
def _initialize_playing_talea(self, playing_talea):
assert isinstance(playing_talea, rmakers.Talea)
assert playing_talea.counts
assert all(0 < x for x in playing_talea.counts)
self._playing_talea = playing_talea
def _initialize_repeat(self, repeat):
if repeat is not None:
repeat = bool(repeat)
self._repeat = repeat
def _initialize_silence_talea(self, silence_talea):
assert isinstance(silence_talea, rmakers.Talea)
assert silence_talea.counts
assert all(0 <= x for x in silence_talea.counts)
self._silence_talea = silence_talea
def _initialize_playing_groupings(self, playing_groupings):
if not isinstance(playing_groupings, collections.Sequence):
playing_groupings = (playing_groupings,)
playing_groupings = tuple(int(x) for x in playing_groupings)
assert len(playing_groupings)
assert all(0 < x for x in playing_groupings)
self._playing_groupings = playing_groupings
def _make_timespans(
self,
layer=None,
music_specifiers=None,
target_timespan=None,
timespan_list=None,
):
# setup state
context_names = abjad.CyclicTuple(music_specifiers)
context_index = self.seed or 0
cascade_pattern = self.cascade_pattern
playing_talea = Cursor(self.playing_talea)
playing_groupings = Cursor(self.playing_groupings)
silence_talea = Cursor(self.silence_talea)
if self.seed is not None and 0 < self.seed:
for _ in range(self.seed):
next(playing_talea)
next(playing_groupings)
next(silence_talea)
context_seeds = collections.Counter()
timespan_list = abjad.TimespanList()
start_offset = target_timespan.start_offset
stop_offset = target_timespan.stop_offset
can_continue = True
division_mask_seed = 0
# start the engine
new_timespan_mapping = {}
while start_offset < stop_offset and can_continue:
for cascade_step in cascade_pattern:
context_name = context_names[context_index]
music_specifier = music_specifiers[context_name]
grouping = next(playing_groupings)
valid_durations = []
for duration in (next(playing_talea) for _ in range(grouping)):
offset = start_offset + duration + sum(valid_durations)
if stop_offset < offset:
playing_talea.backtrack()
break
valid_durations.append(duration)
if self.fuse_groups:
valid_durations = [sum(valid_durations)]
new_timespans = music_specifier(
durations=valid_durations,
layer=layer,
division_masks=self.division_masks,
padding=self.padding,
seed=context_seeds[context_name],
division_mask_seed=division_mask_seed,
start_offset=start_offset,
timespan_specifier=self.timespan_specifier,
voice_name=context_name,
)
if all(isinstance(_, SilentTimespan) for _ in new_timespans):
new_timespans[:] = []
if context_name not in new_timespan_mapping:
new_timespan_mapping[context_name] = abjad.TimespanList()
new_timespan_mapping[context_name].extend(new_timespans)
context_index += cascade_step
context_seeds[context_name] += 1
division_mask_seed += 1
start_offset += next(silence_talea)
if not can_continue:
break
if not self.repeat:
if len(music_specifiers) == len(new_timespan_mapping):
# dangerous...
break
for context_name, timespans in new_timespan_mapping.items():
timespans.compute_logical_or()
timespan_list.extend(timespans)
return timespan_list
### PUBLIC PROPERTIES ###
@property
def cascade_pattern(self):
return self._cascade_pattern
@property
def fuse_groups(self):
return self._fuse_groups
@property
def playing_groupings(self):
return self._playing_groupings
@property
def playing_talea(self):
return self._playing_talea
@property
def repeat(self):
return self._repeat
@property
def silence_talea(self):
return self._silence_talea