def __getitem__(self, i): r'''Gets container `i`. Traverses top-level items only. Returns component. ''' if isinstance(i, int): return self._music[i] elif isinstance(i, slice) and not self.is_simultaneous: return selectiontools.SliceSelection(self._music[i]) elif isinstance(i, slice) and self.is_simultaneous: return selectiontools.SimultaneousSelection(self._music[i]) elif isinstance(i, str): if i not in self._named_children: message = 'can not find component named {!r}.' message = message.format(i) raise ValueError(message) elif 1 < len(self._named_children[i]): message = 'multiple components named {!r}.' message = message.format(i) raise ValueError(message) return self._named_children[i][0] message = 'can not get container item {!r}.' message = message.format(i) raise ValueError(message)
def _initialize_music(self, music): from abjad.tools import scoretools Selection = selectiontools.Selection if music is None: music = [] if self._all_are_orphan_components(music): self._music = list(music) self[:]._set_parents(self) elif Selection._all_are_contiguous_components_in_same_logical_voice( music): music = selectiontools.SliceSelection(music) parent, start, stop = music._get_parent_and_start_stop_indices() self._music = list(music) self[:]._set_parents(self) assert parent is not None parent._music.insert(start, self) self._set_parent(parent) elif isinstance(music, str): parsed = self._parse_string(music) self._music = [] self.is_simultaneous = parsed.is_simultaneous if parsed.is_simultaneous or \ not Selection._all_are_contiguous_components_in_same_logical_voice( parsed[:]): while len(parsed): self.append(parsed.pop(0)) else: self[:] = parsed[:] else: message = 'can not initialize container from {!r}.' message = message.format((music)) raise TypeError(message)
def _get_contents(self, include_self=True): result = [] if include_self: result.append(self) result.extend(getattr(self, '_music', [])) result = selectiontools.SliceSelection(result) return result
def _extract(self, scale_contents=None): from abjad.tools import selectiontools selection = selectiontools.SliceSelection([self]) parent, start, stop = selection._get_parent_and_start_stop_indices() music_list = list(getattr(self, '_music', ())) parent.__setitem__(slice(start, stop + 1), music_list) return self
def get_counttime_components(self, counttime_components): r'''Get `counttime_components` that satisfy `time_relation`: :: >>> voice = Voice( ... [Note(i % 36, Duration(1, 4)) for i in range(200)]) >>> timespan_1 = timespantools.Timespan(20, 22) >>> time_relation = \ ... timespantools.timespan_2_starts_during_timespan_1( ... timespan_1=timespan_1) :: >>> result = time_relation.get_counttime_components(voice[:]) :: >>> for counttime_component in result: ... counttime_component Note("af'4") Note("a'4") Note("bf'4") Note("b'4") Note("c''4") Note("cs''4") Note("d''4") Note("ef''4") :: >>> result.get_timespan() Timespan(start_offset=Offset(20, 1), stop_offset=Offset(22, 1)) `counttime_components` must belong to a single voice. `counttime_components` must be time-contiguous. The call shown here takes 78355 function calls under r9686. Returns selection. ''' from abjad.tools import selectiontools from abjad.tools import timespantools # check input assert isinstance( counttime_components, (list, selectiontools.SliceSelection)), repr(counttime_components) assert self.timespan_1 is not None # iterate counttime components result = [] for counttime_component in counttime_components: if self(timespan_2=counttime_component._get_timespan()): result.append(counttime_component) # return result return selectiontools.SliceSelection(result)
def __delitem__(self, i): r'''Deletes container `i`. Detaches component(s) from parentage. Withdraws component(s) from crossing spanners. Preserves spanners that component(s) cover(s). Returns none. ''' components = self[i] #if not isinstance(components, selectiontools.SliceSelection): if not isinstance(components, selectiontools.Selection): components = selectiontools.SliceSelection([components]) if not self.is_simultaneous: components._withdraw_from_crossing_spanners() components._set_parents(None)
def _fuse_measures(self): from abjad.tools import scoretools from abjad.tools import selectiontools # check input prototype=(scoretools.Measure,) assert self._all_are_contiguous_components_in_same_parent( self, prototype) # return none on empty measures if len(self) == 0: return None # TODO: instantiate a new measure # instead of returning a reference to existing measure if len(self) == 1: return self[0] implicit_scaling = self[0].implicit_scaling assert all( x.implicit_scaling == implicit_scaling for x in self) selection = selectiontools.SliceSelection(self) parent, start, stop = selection._get_parent_and_start_stop_indices() old_denominators = [] new_duration = durationtools.Duration(0) for measure in self: effective_time_signature = measure.time_signature old_denominators.append(effective_time_signature.denominator) new_duration += effective_time_signature.duration new_time_signature = \ measure._duration_and_possible_denominators_to_time_signature( new_duration, old_denominators, ) music = [] for measure in self: # scale before reassignment to prevent logical tie scale drama signature = measure.time_signature prolation = signature.implied_prolation multiplier = prolation / new_time_signature.implied_prolation measure._scale_contents(multiplier) measure_music = measure[:] measure_music._set_parents(None) music += measure_music new_measure = scoretools.Measure(new_time_signature, music) new_measure.implicit_scaling = self[0].implicit_scaling if parent is not None: self._give_dominant_spanners([new_measure]) self._set_parents(None) if parent is not None: parent.insert(start, new_measure) return new_measure
def _next_in_parent(component): from abjad.tools import selectiontools if not isinstance(component, scoretools.Component): raise TypeError selection = selectiontools.SliceSelection(component) parent, start, stop = \ selection._get_parent_and_start_stop_indices() assert start == stop if parent is None: raise StopIteration # can not advance within simultaneous parent if parent.is_simultaneous: raise StopIteration try: return parent[start + 1] except IndexError: raise StopIteration
def _split( self, durations, cyclic=False, fracture_spanners=False, tie_split_notes=True, use_messiaen_style_ties=False, ): from abjad.tools import pitchtools from abjad.tools import selectiontools from abjad.tools import scoretools from abjad.tools import spannertools durations = [durationtools.Duration(x) for x in durations] if cyclic: durations = sequencetools.repeat_sequence_to_weight( durations, self._get_duration()) durations = [durationtools.Duration(x) for x in durations] if sum(durations) < self._get_duration(): last_duration = self._get_duration() - sum(durations) durations.append(last_duration) sequencetools.truncate_sequence( durations, weight=self._get_duration(), ) result = [] leaf_prolation = self._get_parentage(include_self=False).prolation timespan = self._get_timespan() start_offset = timespan.start_offset for duration in durations: new_leaf = copy.copy(self) preprolated_duration = duration / leaf_prolation shard = new_leaf._set_duration( preprolated_duration, use_messiaen_style_ties=use_messiaen_style_ties, ) for x in shard: if isinstance(x, scoretools.Leaf): x_duration = x.written_duration * leaf_prolation else: x_duration = x.multiplied_duration * leaf_prolation stop_offset = x_duration + start_offset x._start_offset = start_offset x._stop_offset = stop_offset x._timespan = timespantools.Timespan( start_offset=start_offset, stop_offset=stop_offset, ) start_offset = stop_offset shard = [x._get_parentage().root for x in shard] result.append(shard) flattened_result = sequencetools.flatten_sequence(result) flattened_result = selectiontools.SliceSelection(flattened_result) prototype = (spannertools.Tie,) parentage = self._get_parentage() if parentage._get_spanners(prototype=prototype): selection = select(flattened_result) for component in selection: # TODO: make top-level detach() work here for spanner in component._get_spanners(prototype): spanner._sever_all_components() #detach(prototype, component) # replace leaf with flattened result selection = selectiontools.SliceSelection(self) parent, start, stop = selection._get_parent_and_start_stop_indices() if parent: parent.__setitem__(slice(start, stop + 1), flattened_result) else: selection._give_dominant_spanners(flattened_result) selection._withdraw_from_crossing_spanners() # fracture spanners if fracture_spanners: first_shard = result[0] for spanner in first_shard[-1]._get_spanners(): index = spanner._index(first_shard[-1]) spanner._fracture(index, direction=Right) last_shard = result[-1] for spanner in last_shard[0]._get_spanners(): index = spanner._index(last_shard[0]) spanner._fracture(index, direction=Left) for middle_shard in result[1:-1]: for spanner in middle_shard[0]._get_spanners(): index = spanner._index(middle_shard[0]) spanner._fracture(index, direction=Left) for spanner in middle_shard[-1]._get_spanners(): index = spanner._index(middle_shard[-1]) spanner._fracture(index, direction=Right) # adjust first leaf first_leaf = flattened_result[0] self._detach_grace_containers(kind='after') # adjust any middle leaves for middle_leaf in flattened_result[1:-1]: middle_leaf._detach_grace_containers(kind='grace') self._detach_grace_containers(kind='after') detach(object, middle_leaf) # adjust last leaf last_leaf = flattened_result[-1] last_leaf._detach_grace_containers(kind='grace') detach(object, last_leaf) # tie split notes, rests and chords as specified if pitchtools.Pitch.is_pitch_carrier(self) and tie_split_notes: flattened_result_leaves = iterate(flattened_result).by_class( scoretools.Leaf) # TODO: implement SliceSelection._attach_tie_spanner_to_leaves() for leaf_pair in sequencetools.iterate_sequence_nwise( flattened_result_leaves): selection = selectiontools.ContiguousSelection(leaf_pair) selection._attach_tie_spanner_to_leaf_pair( use_messiaen_style_ties=use_messiaen_style_ties, ) # return result return result
def by_run(self, classes): r'''Iterate runs in expression. .. container:: example **Example 1.** Iterate runs of notes and chords at only the top level of score: :: >>> staff = Staff(r"\times 2/3 { c'8 d'8 r8 }") >>> staff.append(r"\times 2/3 { r8 <e' g'>8 <f' a'>8 }") >>> staff.extend("g'8 a'8 r8 r8 <b' d''>8 <c'' e''>8") .. doctest:: >>> print(format(staff)) \new Staff { \times 2/3 { c'8 d'8 r8 } \times 2/3 { r8 <e' g'>8 <f' a'>8 } g'8 a'8 r8 r8 <b' d''>8 <c'' e''>8 } :: >>> for group in iterate(staff[:]).by_run((Note, Chord)): ... group ... (Note("g'8"), Note("a'8")) (Chord("<b' d''>8"), Chord("<c'' e''>8")) .. container:: example **Example 2.** Iterate runs of notes and chords at all levels of score: :: >>> leaves = iterate(staff).by_class(scoretools.Leaf) :: >>> for group in iterate(leaves).by_run((Note, Chord)): ... group ... (Note("c'8"), Note("d'8")) (Chord("<e' g'>8"), Chord("<f' a'>8"), Note("g'8"), Note("a'8")) (Chord("<b' d''>8"), Chord("<c'' e''>8")) Returns generator. ''' from abjad.tools import selectiontools sequence = selectiontools.SliceSelection(self._client) current_group = () for group in sequence.group_by(type): if type(group[0]) in classes: current_group = current_group + group elif current_group: yield current_group current_group = () if current_group: yield current_group
def _split_at_index( self, i, fracture_spanners=False, ): r'''Splits container to the left of index `i`. Preserves tuplet multiplier when container is a tuplet. Preserves time signature denominator when container is a measure. Resizes resizable containers. Returns split parts. ''' from abjad.tools import indicatortools from abjad.tools import scoretools from abjad.tools import selectiontools from abjad.tools import spannertools # partition my music left_music = self[:i] right_music = self[i:] # instantiate new left and right containers if isinstance(self, scoretools.Measure): time_signature = self._get_effective(indicatortools.TimeSignature) denominator = time_signature.denominator left_duration = sum([x._get_duration() for x in left_music]) left_pair = mathtools.NonreducedFraction(left_duration) left_pair = left_pair.with_multiple_of_denominator(denominator) left_time_signature = indicatortools.TimeSignature(left_pair) left = type(self)(left_time_signature, left_music) left.implicit_scaling = self.implicit_scaling right_duration = sum([x._get_duration() for x in right_music]) right_pair = mathtools.NonreducedFraction(right_duration) right_pair = right_pair.with_multiple_of_denominator(denominator) right_time_signature = indicatortools.TimeSignature(right_pair) right = type(self)(right_time_signature, right_music) right.implicit_scaling = self.implicit_scaling elif isinstance(self, scoretools.FixedDurationTuplet): multiplier = self.multiplier left = type(self)(1, left_music) right = type(self)(1, right_music) target_duration = multiplier * left._contents_duration left.target_duration = target_duration target_duration = multiplier * right._contents_duration right.target_duration = target_duration elif isinstance(self, scoretools.Tuplet): multiplier = self.multiplier left = type(self)(multiplier, left_music) right = type(self)(multiplier, right_music) else: left = type(self)(left_music) right = type(self)(right_music) # save left and right containers together for iteration halves = (left, right) nonempty_halves = [half for half in halves if len(half)] # give my attached spanners to my children self._move_spanners_to_children() # incorporate left and right parents in score if possible selection = selectiontools.SliceSelection(self) parent, start, stop = selection._get_parent_and_start_stop_indices() if parent is not None: parent._music.__setitem__(slice(start, stop + 1), nonempty_halves) for part in nonempty_halves: part._set_parent(parent) else: left._set_parent(None) right._set_parent(None) # fracture spanners if requested if fracture_spanners: for spanner in left._get_spanners(): index = spanner._index(left) spanner._fracture(index, direction=Right) # return new left and right containers return halves
def _set_item( self, i, expr, withdraw_components_in_expr_from_crossing_spanners=True, ): r'''This method exists because __setitem__ can not accept keywords. Note that setting withdraw_components_in_expr_from_crossing_spanners=False constitutes a composer-unsafe use of this method. Only private methods should set this keyword. ''' from abjad.tools import scoretools from abjad.tools import selectiontools # cache indicators attached to components in expr expr_indicators = [] for component in iterate(expr).by_class(): indicators = component._get_indicators(unwrap=False) expr_indicators.extend(indicators) # item assignment if isinstance(i, int): if isinstance(expr, str): expr = self._parse_string(expr)[:] assert len(expr) == 1, repr(expr) expr = expr[0] else: expr = [expr] if i < 0: i = len(self) + i i = slice(i, i + 1) else: if isinstance(expr, str): expr = self._parse_string(expr)[:] elif (isinstance(expr, list) and len(expr) == 1 and isinstance(expr[0], str)): expr = self._parse_string(expr[0])[:] prototype = (scoretools.Component, selectiontools.Selection) assert all(isinstance(x, prototype) for x in expr) new_expr = [] for item in expr: if isinstance(item, selectiontools.Selection): new_expr.extend(item) else: new_expr.append(item) expr = new_expr assert all(isinstance(x, scoretools.Component) for x in expr) if any(isinstance(x, scoretools.GraceContainer) for x in expr): message = 'must attach grace container to note or chord.' raise Exception(message) if self._check_for_cycles(expr): raise ParentageError('Attempted to induce cycles.') if (i.start == i.stop and i.start is not None and i.stop is not None and i.start <= -len(self)): start, stop = 0, 0 else: start, stop, stride = i.indices(len(self)) old = self[start:stop] spanners_receipt = self._get_spanners_that_dominate_slice(start, stop) #print('RECEIPT', spanners_receipt, self, expr) for component in old: for child in iterate([component]).by_class(): for spanner in child._get_spanners(): spanner._remove(child) del (self[start:stop]) # must withdraw before setting in self! # otherwise circular withdraw ensues! if withdraw_components_in_expr_from_crossing_spanners: selection = selectiontools.SliceSelection(expr) if selection._all_are_contiguous_components_in_same_logical_voice( selection): selection._withdraw_from_crossing_spanners() self._music.__setitem__(slice(start, start), expr) for component in expr: component._set_parent(self) for spanner, index in spanners_receipt: for component in reversed(expr): spanner._insert(index, component) component._spanners.add(spanner) for indicator in expr_indicators: if hasattr(indicator, '_update_effective_context'): indicator._update_effective_context()
def _splice( self, components, direction=Right, grow_spanners=True, ): from abjad.tools import scoretools from abjad.tools import selectiontools assert all(isinstance(x, scoretools.Component) for x in components) selection = selectiontools.ContiguousSelection(self) if direction == Right: if grow_spanners: insert_offset = self._get_timespan().stop_offset receipt = selection._get_dominant_spanners() for spanner, index in receipt: insert_component = None for component in spanner: start_offset = component._get_timespan().start_offset if start_offset == insert_offset: insert_component = component break if insert_component is not None: insert_index = spanner._index(insert_component) else: insert_index = len(spanner) for component in reversed(components): spanner._insert(insert_index, component) component._spanners.add(spanner) selection = selectiontools.SliceSelection(self) parent, start, stop = \ selection._get_parent_and_start_stop_indices() if parent is not None: if grow_spanners: for component in reversed(components): component._set_parent(parent) parent._music.insert(start + 1, component) else: after = stop + 1 parent.__setitem__(slice(after, after), components) return [self] + components else: if grow_spanners: offset = self._get_timespan().start_offset receipt = selection._get_dominant_spanners() for spanner, x in receipt: for component in spanner: if component._get_timespan().start_offset == offset: index = spanner._index(component) break else: message = 'no component in spanner at offset.' raise ValueError(message) for component in reversed(components): spanner._insert(index, component) component._spanners.add(spanner) selection = selectiontools.SliceSelection(self) parent, start, stop = \ selection._get_parent_and_start_stop_indices() if parent is not None: if grow_spanners: for component in reversed(components): component._set_parent(parent) parent._music.insert(start, component) else: parent.__setitem__(slice(start, start), components) return components + [self]