import collections
import abjad
import tsmakers
from abjadext import rmakers
[docs]class MusicSpecifierSequence(object):
r"""
A music specifier sequence.
.. container:: example
>>> sequence_a = tsmakers.MusicSpecifierSequence(
... music_specifiers='music',
... )
>>> print(abjad.storage(sequence_a))
tsmakers.MusicSpecifierSequence(
music_specifiers=('music',),
)
.. container:: example
>>> sequence_b = tsmakers.MusicSpecifierSequence(
... application_rate='phrase',
... music_specifiers=['one', 'two', 'three'],
... )
>>> print(abjad.storage(sequence_b))
tsmakers.MusicSpecifierSequence(
application_rate='phrase',
music_specifiers=('one', 'two', 'three'),
)
"""
### CLASS VARIABLES ###
__slots__ = (
"_application_rate",
"_music_specifiers",
)
### INITIALIZER ###
def __init__(
self,
application_rate=None,
music_specifiers=None,
):
if application_rate is not None:
application_rate = application_rate or "phrase"
assert application_rate in ("division", "phrase")
if music_specifiers is None:
music_specifiers = [None]
if not isinstance(music_specifiers, collections.Sequence) or isinstance(
music_specifiers, str
):
music_specifiers = [music_specifiers]
music_specifiers = tuple(music_specifiers)
# music_specifiers = abjad.CyclicTuple(music_specifiers)
assert len(music_specifiers)
self._application_rate = application_rate
self._music_specifiers = music_specifiers
[docs] def __str__(self):
return abjad.storage(self)
[docs] def __repr__(self):
return abjad.storage(self)
### SPECIAL METHODS ###
[docs] def __call__(
self,
durations=None,
layer=None,
division_mask_seed=0,
division_masks=None,
padding=None,
seed=None,
start_offset=None,
timespan_specifier=None,
voice_name=None,
):
timespans = abjad.TimespanList()
timespan_specifier = timespan_specifier or tsmakers.TimespanSpecifier()
seed = seed or 0
division_mask_seed = division_mask_seed or 0
durations = [_ for _ in durations if _]
offsets = abjad.math.cumulative_sums(durations, start_offset)
if not offsets:
return timespans
offset_pair_count = len(offsets) - 1
if offset_pair_count == 1:
offset_pair_count = 2 # make patterns happy
iterator = abjad.Sequence(offsets).nwise()
for i, offset_pair in enumerate(iterator):
start_offset, stop_offset = offset_pair
music_specifier = self[seed % len(self)]
timespan = tsmakers.PerformedTimespan(
forbid_fusing=timespan_specifier.forbid_fusing,
forbid_splitting=timespan_specifier.forbid_splitting,
layer=layer,
minimum_duration=timespan_specifier.minimum_duration,
music_specifier=music_specifier,
start_offset=start_offset,
stop_offset=stop_offset,
voice_name=voice_name,
)
if not division_masks:
timespans.append(timespan)
else:
output_mask = division_masks.get_matching_pattern(
i, offset_pair_count + 1, rotation=division_mask_seed
)
if output_mask is None:
timespans.append(timespan)
elif isinstance(output_mask, rmakers.SustainMask):
timespans.append(timespan)
elif isinstance(output_mask, rmakers.SilenceMask):
pass
division_mask_seed += 1
if self.application_rate == "division":
seed += 1
if padding:
silent_timespans = abjad.TimespanList()
for shard in timespans.partition(True):
silent_timespan_one = tsmakers.SilentTimespan(
layer=layer,
start_offset=shard.start_offset - padding,
stop_offset=shard.start_offset,
voice_name=voice_name,
)
silent_timespans.append(silent_timespan_one)
silent_timespan_two = tsmakers.SilentTimespan(
layer=layer,
start_offset=shard.stop_offset,
stop_offset=shard.stop_offset + padding,
voice_name=voice_name,
)
silent_timespans.append(silent_timespan_two)
silent_timespans.compute_logical_or()
for timespan in timespans:
silent_timespans - timespan
timespans.extend(silent_timespans)
timespans.sort()
return timespans
[docs] def __getitem__(self, item):
return self._music_specifiers[item]
[docs] def __len__(self):
return len(self._music_specifiers)
### PUBLIC METHODS ###
[docs] def transpose(self, expr):
music_specifiers = [_.transpose(expr) for _ in self.music_specifiers]
return abjad.new(
self,
music_specifiers=music_specifiers,
)
### PUBLIC PROPERTIES ###
@property
def application_rate(self):
return self._application_rate
@property
def music_specifiers(self):
return self._music_specifiers