import collections
import abjad
from .HashCachingObject import HashCachingObject
from .MusicSpecifierSequence import MusicSpecifierSequence
[docs]class CompositeMusicSpecifier(HashCachingObject):
r"""A composite music specifier.
.. container:: example
>>> music_specifier = tsmakers.CompositeMusicSpecifier(
... primary_music_specifier='one',
... primary_voice_name='A',
... rotation_indices=(0, 1, -1),
... secondary_voice_name='B',
... secondary_music_specifier=tsmakers.MusicSpecifierSequence(
... application_rate='phrase',
... music_specifiers=('two', 'three', 'four'),
... ),
... )
>>> durations = [1, 2]
>>> timespans = music_specifier(
... durations=durations,
... layer=1,
... )
>>> ts_list = abjad.TimespanList(
... [
... abjad.AnnotatedTimespan(
... start_offset=_.start_offset,
... stop_offset=_.stop_offset,
... annotation=_.voice_name,
... )
... for _ in timespans
... ]
... )
>>> abjad.show(ts_list, scale=0.5, key="annotation") # doctest: +SKIP
.. docs::
>>> print(abjad.storage(timespans))
abjad.TimespanList(
[
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((0, 1)),
stop_offset=abjad.Offset((1, 1)),
layer=1,
music_specifier='one',
voice_name='A',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((0, 1)),
stop_offset=abjad.Offset((1, 1)),
layer=1,
music_specifier='two',
voice_name='B',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((1, 1)),
stop_offset=abjad.Offset((3, 1)),
layer=1,
music_specifier='one',
voice_name='A',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((1, 1)),
stop_offset=abjad.Offset((3, 1)),
layer=1,
music_specifier='two',
voice_name='B',
),
]
)
.. container:: example
>>> durations = [1, 2]
>>> timespans = music_specifier(
... durations=durations,
... layer=2,
... seed=1,
... )
>>> ts_list = abjad.TimespanList(
... [
... abjad.AnnotatedTimespan(
... start_offset=_.start_offset,
... stop_offset=_.stop_offset,
... annotation=_.voice_name,
... )
... for _ in timespans
... ]
... )
>>> abjad.show(ts_list, scale=0.5, key="annotation") # doctest: +SKIP
.. docs::
>>> print(abjad.storage(timespans))
abjad.TimespanList(
[
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((0, 1)),
stop_offset=abjad.Offset((1, 1)),
layer=2,
music_specifier='one',
voice_name='A',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((0, 1)),
stop_offset=abjad.Offset((2, 1)),
layer=2,
music_specifier='three',
voice_name='B',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((1, 1)),
stop_offset=abjad.Offset((3, 1)),
layer=2,
music_specifier='one',
voice_name='A',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((2, 1)),
stop_offset=abjad.Offset((3, 1)),
layer=2,
music_specifier='three',
voice_name='B',
),
]
)
.. container:: example
>>> durations = [1, 2]
>>> timespans = music_specifier(
... durations=durations,
... layer=3,
... padding=1,
... seed=2,
... )
>>> ts_list = abjad.TimespanList(
... [
... abjad.AnnotatedTimespan(
... start_offset=_.start_offset,
... stop_offset=_.stop_offset,
... annotation=_.voice_name,
... )
... for _ in timespans
... ]
... )
>>> abjad.show(ts_list, scale=0.5, key="annotation") # doctest: +SKIP
.. docs::
>>> print(abjad.storage(timespans))
abjad.TimespanList(
[
tsmakers.SilentTimespan(
start_offset=abjad.Offset((-1, 1)),
stop_offset=abjad.Offset((0, 1)),
layer=3,
voice_name='A',
),
tsmakers.SilentTimespan(
start_offset=abjad.Offset((-1, 1)),
stop_offset=abjad.Offset((0, 1)),
layer=3,
voice_name='B',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((0, 1)),
stop_offset=abjad.Offset((1, 1)),
layer=3,
music_specifier='one',
voice_name='A',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((0, 1)),
stop_offset=abjad.Offset((2, 1)),
layer=3,
music_specifier='four',
voice_name='B',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((1, 1)),
stop_offset=abjad.Offset((3, 1)),
layer=3,
music_specifier='one',
voice_name='A',
),
tsmakers.PerformedTimespan(
start_offset=abjad.Offset((2, 1)),
stop_offset=abjad.Offset((3, 1)),
layer=3,
music_specifier='four',
voice_name='B',
),
tsmakers.SilentTimespan(
start_offset=abjad.Offset((3, 1)),
stop_offset=abjad.Offset((4, 1)),
layer=3,
voice_name='A',
),
tsmakers.SilentTimespan(
start_offset=abjad.Offset((3, 1)),
stop_offset=abjad.Offset((4, 1)),
layer=3,
voice_name='B',
),
]
)
"""
### CLASS VARIABLES ###
__slots__ = (
"_discard_inner_offsets",
"_primary_music_specifier",
"_primary_voice_name",
"_rotation_indices",
"_secondary_music_specifier",
"_secondary_voice_name",
)
### INITIALIZER ###
def __init__(
self,
discard_inner_offsets=None,
primary_music_specifier=None,
primary_voice_name=None,
rotation_indices=None,
secondary_music_specifier=None,
secondary_voice_name=None,
):
HashCachingObject.__init__(self)
prototype = MusicSpecifierSequence
if discard_inner_offsets is not None:
discard_inner_offsets = bool(discard_inner_offsets)
self._discard_inner_offsets = discard_inner_offsets
if not isinstance(primary_music_specifier, prototype):
primary_music_specifier = MusicSpecifierSequence(
music_specifiers=primary_music_specifier,
)
self._primary_music_specifier = primary_music_specifier
if primary_voice_name is not None:
primary_voice_name = str(primary_voice_name)
self._primary_voice_name = primary_voice_name
if rotation_indices is not None:
if not isinstance(rotation_indices, collections.Sequence):
rotation_indices = int(rotation_indices)
rotation_indices = (rotation_indices,)
rotation_indices = tuple(rotation_indices)
self._rotation_indices = rotation_indices
if not isinstance(secondary_music_specifier, prototype):
secondary_music_specifier = MusicSpecifierSequence(
music_specifiers=secondary_music_specifier,
)
self._secondary_music_specifier = secondary_music_specifier
if secondary_voice_name is not None:
secondary_voice_name = str(secondary_voice_name)
self._secondary_voice_name = secondary_voice_name
### PUBLIC METHODS ###
[docs] def __call__(
self,
durations=None,
layer=None,
division_masks=None,
division_mask_seed=None,
padding=None,
seed=None,
start_offset=None,
timespan_specifier=None,
voice_name=None,
):
seed = seed or 0
rotation_indices = self.rotation_indices or (0,)
rotation_indices = abjad.CyclicTuple(rotation_indices)
primary_durations = abjad.Sequence(durations)
start_offset = start_offset or 0
if self.discard_inner_offsets:
secondary_durations = [sum(primary_durations)]
else:
# secondary_durations = rotate(
# primary_durations,
# rotation_indices[seed],
# )
secondary_durations = primary_durations.rotate(rotation_indices[seed])
primary_timespans = self.primary_music_specifier(
durations=primary_durations,
layer=layer,
division_masks=division_masks,
division_mask_seed=division_mask_seed,
padding=padding,
seed=seed,
start_offset=start_offset,
timespan_specifier=timespan_specifier,
voice_name=self.primary_voice_name,
)
secondary_timespans = self.secondary_music_specifier(
durations=secondary_durations,
layer=layer,
division_masks=division_masks,
division_mask_seed=division_mask_seed,
padding=padding,
seed=seed,
start_offset=start_offset,
timespan_specifier=timespan_specifier,
voice_name=self.secondary_voice_name,
)
timespans = primary_timespans[:] + secondary_timespans[:]
timespans = abjad.TimespanList(timespans)
timespans.sort()
return timespans
### PUBLIC PROPERTIES ###
@property
def discard_inner_offsets(self):
return self._discard_inner_offsets
@property
def primary_music_specifier(self):
return self._primary_music_specifier
@property
def primary_voice_name(self):
return self._primary_voice_name
@property
def rotation_indices(self):
return self._rotation_indices
@property
def secondary_music_specifier(self):
return self._secondary_music_specifier
@property
def secondary_voice_name(self):
return self._secondary_voice_name