def _add_container_identifiers(self): if (self.environment == 'docs' and not getattr(self, 'test_container_identifiers', False)): return segment_name = self.segment_name or '' segment_name = String(segment_name).to_segment_lilypond_identifier() contexts = [] try: context = self.score['GlobalSkips'] contexts.append(context) except ValueError: pass try: context = self.score['GlobalRests'] contexts.append(context) except ValueError: pass for voice in iterate(self.score).components(Voice): contexts.append(voice) container_to_part_assignment = OrderedDict() for context in contexts: if segment_name: context_identifier = f'{segment_name}_{context.name}' else: context_identifier = context.name context.identifier = f'%*% {context_identifier}' part_container_count = 0 for container in iterate(context).components(Container): if not container.identifier: continue if container.identifier.startswith('%*% Part'): part_container_count += 1 globals_ = globals() part = container.identifier.strip('%*% ') part = eval(part, globals_) suffix = String().base_26(part_container_count).lower() container_identifier = f'{context_identifier}_{suffix}' container_identifier = String(container_identifier) assert container_identifier.is_lilypond_identifier() assert container_identifier not in \ container_to_part_assignment timespan = inspect(container).get_timespan() pair = (part, timespan) container_to_part_assignment[container_identifier] = pair container.identifier = f'%*% {container_identifier}' for staff in iterate(self.score).components(Staff): if segment_name: context_identifier = f'{segment_name}_{staff.name}' else: context_identifier = staff.name staff.identifier = f'%*% {context_identifier}' self._container_to_part_assignment = container_to_part_assignment
def __call__(self, expr): r'''Calls handler on `expr`. Returns none. ''' leaves = iterate(expr).by_class(scoretools.Leaf) statement = 'override(leaf).{}.{} = {}' statement = statement.format( self._grob_name, self._attribute_name, self._attribute_value, ) if self.maximum_written_duration is not None: maximum_statement = 'override(leaf).{}.{} = {}' maximum_statement = maximum_statement.format( self.maximum_settings['grob_name'], self.maximum_settings['attribute_name'], self.maximum_settings['attribute_value'], ) for leaf in leaves: if self.maximum_written_duration is not None: if self.maximum_written_duration <= leaf.written_duration: if maximum_statement is not None: exec(maximum_statement, globals(), locals()) continue exec(statement, globals(), locals())
def __call__(self, expr, timespan=None): r'''Calls handler on `expr`. Returns none. ''' leaves = iterate(expr).by_class(scoretools.Leaf) statement = 'override(leaf).{}.{} = {}' statement = statement.format( self._grob_name, self._attribute_name, self._attribute_value, ) if self.maximum_written_duration is not None: maximum_statement = 'override(leaf).{}.{} = {}' maximum_statement = maximum_statement.format( self.maximum_settings['grob_name'], self.maximum_settings['attribute_name'], self.maximum_settings['attribute_value'], ) for leaf in leaves: if self.maximum_written_duration is not None: if self.maximum_written_duration <= leaf.written_duration: if maximum_statement is not None: exec(maximum_statement, globals(), locals()) continue exec(statement, globals(), locals())
def __call__(self, expr, timespan=None): r'''Calls handler on `expr`. Returns none. ''' prototype = (scoretools.Note, scoretools.Chord) hash_mark_counts = datastructuretools.CyclicTuple( self.hash_mark_counts) leaves = iterate(expr).by_class(prototype) for i, leaf in enumerate(leaves): hash_mark_count = hash_mark_counts[i] stem_tremolo = indicatortools.StemTremolo(hash_mark_count) attach(stem_tremolo, leaf)
def __call__(self, expr): r'''Calls handler on `expr`. Returns none. ''' prototype = (scoretools.Note, scoretools.Chord) hash_mark_counts = datastructuretools.CyclicTuple( self.hash_mark_counts) leaves = list(iterate(expr).by_class(prototype)) total_length = len(leaves) for i, leaf in enumerate(leaves): if self.pattern is not None: if not self.pattern.matches_index(i, total_length): continue hash_mark_count = hash_mark_counts[i] stem_tremolo = indicatortools.StemTremolo(hash_mark_count) attach(stem_tremolo, leaf)
def __illustrate__( self, default_paper_size: str = None, global_staff_size: int = None, includes: typing.List[str] = None, ) -> LilyPondFile: r'''Illustrates score template. ''' score = self() for voice in iterate(score).components(Voice): voice.append(Skip(1)) self.attach_defaults(score) lilypond_file = score.__illustrate__() lilypond_file = new( lilypond_file, default_paper_size=default_paper_size, global_staff_size=global_staff_size, includes=includes, ) return lilypond_file
def from_selection(selection) -> 'Clef': """ Makes clef from ``selection``. .. container:: example >>> maker = abjad.NoteMaker() >>> notes = maker(range(-12, -6), [(1, 4)]) >>> staff = abjad.Staff(notes) >>> abjad.Clef.from_selection(staff) Clef('bass') Choses between treble and bass based on minimal number of ledger lines. """ pitches = iterate(selection).pitches() diatonic_pitch_numbers = [ pitch._get_diatonic_pitch_number() for pitch in pitches ] max_diatonic_pitch_number = max(diatonic_pitch_numbers) min_diatonic_pitch_number = min(diatonic_pitch_numbers) lowest_treble_line_pitch = NamedPitch('E4') lowest_treble_line_diatonic_pitch_number = \ lowest_treble_line_pitch._get_diatonic_pitch_number() candidate_steps_below_treble = \ lowest_treble_line_diatonic_pitch_number - \ min_diatonic_pitch_number highest_bass_line_pitch = NamedPitch('A3') highest_bass_line_diatonic_pitch_number = \ highest_bass_line_pitch._get_diatonic_pitch_number() candidate_steps_above_bass = \ max_diatonic_pitch_number - highest_bass_line_diatonic_pitch_number if candidate_steps_above_bass < candidate_steps_below_treble: return Clef('bass') else: return Clef('treble')
def get_leaf(self, n=0): r'''Gets leaf `n`. .. container:: example Example score: :: >>> staff = Staff() >>> staff.append(Voice("c'8 d'8 e'8 f'8")) >>> staff.append(Voice("g'8 a'8 b'8 c''8")) >>> show(staff) # doctest: +SKIP .. doctest:: >>> print(format(staff)) \new Staff { \new Voice { c'8 d'8 e'8 f'8 } \new Voice { g'8 a'8 b'8 c''8 } } .. container:: example **Example 1.** Gets leaf `n` **from** client of inspection agent when client of inspection agent is a leaf. With positive indices: :: >>> first_leaf = staff[0][0] >>> first_leaf Note("c'8") :: >>> for n in range(8): ... print(n, inspect_(first_leaf).get_leaf(n)) ... 0 c'8 1 d'8 2 e'8 3 f'8 4 None 5 None 6 None 7 None With negative indices: :: >>> last_leaf = staff[0][-1] >>> last_leaf Note("f'8") :: >>> for n in range(0, -8, -1): ... print(n, inspect_(last_leaf).get_leaf(n)) ... 0 f'8 -1 e'8 -2 d'8 -3 c'8 -4 None -5 None -6 None -7 None .. container:: example **Example 2.** Gets leaf `n` **in** client of inspection agent when client of inspection agent is a container. With positive indices: :: >>> first_voice = staff[0] >>> first_voice Voice("c'8 d'8 e'8 f'8") :: >>> for n in range(8): ... print(n, inspect_(first_voice).get_leaf(n)) ... 0 c'8 1 d'8 2 e'8 3 f'8 4 None 5 None 6 None 7 None With negative indices: :: >>> first_voice = staff[0] >>> first_voice Voice("c'8 d'8 e'8 f'8") :: >>> for n in range(-1, -9, -1): ... print(n, inspect_(first_voice).get_leaf(n)) ... -1 f'8 -2 e'8 -3 d'8 -4 c'8 -5 None -6 None -7 None -8 None Returns leaf or none. ''' from abjad.tools import scoretools if isinstance(self._client, scoretools.Leaf): return self._client._get_leaf(n=n) if 0 <= n: leaves = iterate(self._client).by_class( scoretools.Leaf, start=0, stop=n+1, ) leaves = list(leaves) if len(leaves) < n + 1: return leaf = leaves[n] return leaf else: leaves = iterate(self._client).by_class( scoretools.Leaf, start=0, stop=abs(n), reverse=True, ) leaves = list(leaves) if len(leaves) < abs(n): return leaf = leaves[abs(n)-1] return leaf
def grade_composition(self, composition: CompositionEnvironment) -> int: penalties = 0 working_staff = StaffGroup() working_staff.append(composition.voices[0]) working_staff.append(composition.voices[1]) interval_tally = {} pitch_tally = {} melodic_interval_tally = {} vertical_moments = list(iterate(working_staff).by_vertical_moment()) intervals = [] degrees = [[], []] for moment in vertical_moments: pitches = moment.leaves harmonic = NamedInterval.from_pitch_carriers( pitches[1], pitches[0]) intervals.append(harmonic) degrees[0].append( composition.composition_parameters.scale. named_pitch_class_to_scale_degree(pitches[0])) degrees[1].append( composition.composition_parameters.scale. named_pitch_class_to_scale_degree(pitches[1])) count = pitch_tally.setdefault(pitches[0], 0) + 1 pitch_tally[pitches[0]] = count count = pitch_tally.setdefault(pitches[1], 0) + 1 pitch_tally[pitches[1]] = count count = interval_tally.setdefault(harmonic, 0) + 1 interval_tally[harmonic] = count for i in range(len(vertical_moments)): vertical_moment = vertical_moments[i] harmonic = intervals[i] # No voice crossing if harmonic.direction_string == "descending": penalties -= 1 if abs(harmonic.semitones) in constants.dissonant_intervals: penalties -= 5 # No harmonic intervals greater than a 12th if abs(harmonic.semitones) > NamedInterval("P12").semitones: penalties -= 5 # Tenth is pushing it elif abs(harmonic.semitones) > NamedInterval("M10").semitones: penalties -= 1 maximum_extent = vertical_moment.offset + vertical_moment.leaves[ 0].written_duration if maximum_extent == composition.composition_parameters.duration: last_top = degrees[0][-1] last_bottom = degrees[1][-1] prev_top = degrees[0][-2] prev_bottom = degrees[1][-2] # Use an authentic cadence if last_top != ScaleDegree(1): penalties -= 10 if last_bottom != ScaleDegree(1): penalties -= 10 if not ((prev_top == ScaleDegree(7) and prev_bottom == ScaleDegree(2)) or (prev_top == ScaleDegree(2) and prev_bottom == ScaleDegree(7))): penalties -= 10 elif i is 0: # First interval should be a tonic unison if degrees[0][0] != ScaleDegree(1): penalties -= 5 if degrees[1][0] != ScaleDegree(1): penalties -= 5 if i > 0: prev_harmonic = intervals[i - 1] prev_slice = vertical_moments[i - 1] lower_melodic, upper_melodic = slices_to_melodic_intervals( prev_slice, vertical_moment) count = melodic_interval_tally.get(lower_melodic, 0) + 1 melodic_interval_tally[lower_melodic] = count count = melodic_interval_tally.get(upper_melodic, 0) + 1 melodic_interval_tally[upper_melodic] = count motion = characterize_relative_motion(upper_melodic, lower_melodic) # Lines should always be moving if motion is RelativeMotion.none: penalties -= 5 # Contrary motion is preferred if motion is RelativeMotion.similar or motion is RelativeMotion.oblique: penalties -= 1 # Never have two perfect consonances in a row if prev_harmonic.interval_class == harmonic.interval_class and harmonic.quality_string == "perfect": penalties -= 5 # Steps are preferred to leaps if is_leap(lower_melodic): penalties -= 1 if is_leap(upper_melodic): penalties -= 1 if i > 2: prev_prev_harmonic = intervals[i - 2] prev_prev_prev_harmonic = intervals[i - 3] all_same = same_harmonic_quality(harmonic, prev_harmonic, prev_prev_harmonic, prev_prev_prev_harmonic) # Don't have the same interval more than three times in a row if all_same: penalties -= 5 prev_lower_melodic, prev_upper_harmonic = slices_to_melodic_intervals( vertical_moments[i - 2], prev_slice) # Encourage counterstepwise motion. # If the prev motion was a leap.. if is_leap(prev_lower_melodic): # It needs to be resolved by a step, and the step needs to be in the opposite direction if not is_step(lower_melodic) or ( prev_lower_melodic.semitones > 0 ^ lower_melodic.semitones > 0): penalties -= 5 else: () # print("we did it") if is_leap(prev_upper_harmonic): if not is_step(upper_melodic) or ( prev_upper_harmonic.semitones > 0 ^ upper_melodic.semitones > 0): penalties -= 5 else: () # print("we did it") """ for pitch, num in pitch_tally.items(): if num > 2: penalties -= 5 * num for interval, num in interval_tally.items(): if num > 5: penalties -= 5 * num for interval, num in melodic_interval_tally.items(): if num > 5: penalties -= 5 * num """ return penalties
def rhythm( class_, selections, divisions=None, attach_lilypond_voice_commands=None, implicit_scaling=None, pitched_staff=None, simultaneous_selections=None, time_signatures=None, ): r'''Makes rhythm-styled LilyPond file. .. container:: example Makes rhythmic staff: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file[abjad.Score] >>> abjad.f(score) \new Score << \new GlobalContext { { % measure \time 3/4 s1 * 3/4 } % measure { % measure \time 4/8 s1 * 1/2 } % measure { % measure \time 1/4 s1 * 1/4 } % measure } \new RhythmicStaff { { % measure \time 3/4 c'8 [ c'8 c'8 c'8 c'8 c'8 ] } % measure { % measure \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } % measure { % measure \time 1/4 c'8 [ c'8 ] } % measure } >> .. container:: example Set time signatures explicitly: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... [(6, 8), (4, 8), (2, 8)], ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file[abjad.Score] >>> abjad.f(score) \new Score << \new GlobalContext { { % measure \time 6/8 s1 * 3/4 } % measure { % measure \time 4/8 s1 * 1/2 } % measure { % measure \time 2/8 s1 * 1/4 } % measure } \new RhythmicStaff { { % measure \time 6/8 c'8 [ c'8 c'8 c'8 c'8 c'8 ] } % measure { % measure \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } % measure { % measure \time 2/8 c'8 [ c'8 ] } % measure } >> .. container:: example Makes pitched staff: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... pitched_staff=True, ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> abjad.f(lilypond_file[abjad.Score]) \new Score << \new GlobalContext { { % measure \time 3/4 s1 * 3/4 } % measure { % measure \time 4/8 s1 * 1/2 } % measure { % measure \time 1/4 s1 * 1/4 } % measure } \new Staff { { % measure \time 3/4 c'8 [ c'8 c'8 c'8 c'8 c'8 ] } % measure { % measure \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } % measure { % measure \time 1/4 c'8 [ c'8 ] } % measure } >> .. container:: example Makes simultaneous voices: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> for note in abjad.iterate(selections).components(abjad.Note): ... note.written_pitch = abjad.NamedPitch("e'") ... >>> selection_1 = selections[0] + selections[1] + selections[2] >>> selections = [ ... maker(12 * [0], [(1, 16)]), ... maker(16 * [0], [(1, 32)]), ... maker(4 * [0], [(1, 16)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> selection_2 = selections[0] + selections[1] + selections[2] >>> selections = { ... 'Voice 1': selection_1, ... 'Voice 2': selection_2, ... } >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... ) >>> voice_1 = lilypond_file['Voice 1'] >>> abjad.attach(abjad.LilyPondLiteral(r'\voiceOne'), voice_1) >>> voice_2 = lilypond_file['Voice 2'] >>> abjad.attach(abjad.LilyPondLiteral(r'\voiceTwo'), voice_2) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> abjad.f(lilypond_file[abjad.Score]) \new Score << \new GlobalContext { { % measure \time 3/4 s1 * 3/4 } % measure { % measure \time 4/8 s1 * 1/2 } % measure { % measure \time 1/4 s1 * 1/4 } % measure } \new Staff << \context Voice = "Voice 1" { \voiceOne e'8 [ e'8 e'8 e'8 e'8 e'8 ] e'16 [ e'16 e'16 e'16 e'16 e'16 e'16 e'16 ] e'8 [ e'8 ] } \context Voice = "Voice 2" { \voiceTwo c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] c'32 [ c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 ] c'16 [ c'16 c'16 c'16 ] } >> >> Returns LilyPond file. ''' if isinstance(selections, list): for selection in selections: if not isinstance(selection, Selection): message = f'must be selection: {selection!r}.' raise TypeError(message) elif isinstance(selections, dict): for selection in selections.values(): if not isinstance(selection, Selection): message = f'must be selection: {selection!r}.' raise TypeError(message) else: message = f'must be list or dictionary: {selections!r}.' raise TypeError(message) score = Score() lilypond_file = LilyPondFile.new( score, includes=['default.ily', 'rhythm-maker-docs.ily'], ) if pitched_staff is None: if isinstance(selections, list): selections_ = selections elif isinstance(selections, dict): selections_ = selections.values() else: raise TypeError(selections) for note in iterate(selections_).leaves(Note): if note.written_pitch != NamedPitch("c'"): pitched_staff = True break if isinstance(selections, list): if divisions is None: duration = abjad_inspect(selections).get_duration() divisions = [duration] time_signatures = time_signatures or divisions maker = MeasureMaker(implicit_scaling=implicit_scaling) measures = maker(time_signatures) if pitched_staff: staff = Staff(measures) else: staff = Staff(measures, lilypond_type='RhythmicStaff') selections = sequence(selections).flatten(depth=-1) selections_ = copy.deepcopy(selections) try: agent = mutate(staff) measures = agent.replace_measure_contents(selections) except StopIteration: if pitched_staff: staff = Staff(selections_) else: staff = Staff( selections_, lilypond_type='RhythmicStaff', ) elif isinstance(selections, dict): voices = [] for voice_name in sorted(selections): selections_ = selections[voice_name] selections_ = sequence(selections_).flatten(depth=-1) selections_ = copy.deepcopy(selections_) voice = Voice(selections_, name=voice_name) if attach_lilypond_voice_commands: voice_name_to_command_string = { 'Voice 1': 'voiceOne', 'Voice 2': 'voiceTwo', 'Voice 3': 'voiceThree', 'Voice 4': 'voiceFour', } command_string = voice_name_to_command_string.get( voice_name, ) if command_string: command = LilyPondLiteral('\\' + command_string) attach(command, voice) voices.append(voice) staff = Staff(voices, is_simultaneous=True) if divisions is None: duration = abjad_inspect(staff).get_duration() divisions = [duration] else: message = 'must be list or dictionary of selections:' message += f' {selections!r}.' raise TypeError(message) score.append(staff) assert isinstance(divisions, collections.Sequence), repr(divisions) time_signatures = time_signatures or divisions context = Context(lilypond_type='GlobalContext') maker = MeasureMaker(implicit_scaling=implicit_scaling) measures = maker(time_signatures) context.extend(measures) score.insert(0, context) return lilypond_file
def __getitem__(self, name): r'''Gets item with `name`. .. container:: example Gets header block: >>> lilypond_file = abjad.LilyPondFile.new() >>> lilypond_file['header'] <Block(name='header')> .. container:: example Searches score: >>> voice_1 = abjad.Voice("c''4 b' a' g'", name='Custom Voice 1') >>> abjad.attach(abjad.LilyPondLiteral(r'\voiceOne'), voice_1) >>> voice_2 = abjad.Voice("c'4 d' e' f'", name='Custom Voice 2') >>> abjad.attach(abjad.LilyPondLiteral(r'\voiceTwo'), voice_2) >>> staff = abjad.Staff( ... [voice_1, voice_2], ... is_simultaneous=True, ... name='Custom Staff', ... ) >>> score = abjad.Score([staff], name='Custom Score') >>> lilypond_file = abjad.LilyPondFile.new(score) >>> abjad.show(score) # doctest: +SKIP .. docs:: >>> abjad.f(score) \context Score = "Custom Score" << \context Staff = "Custom Staff" << \context Voice = "Custom Voice 1" { \voiceOne c''4 b'4 a'4 g'4 } \context Voice = "Custom Voice 2" { \voiceTwo c'4 d'4 e'4 f'4 } >> >> >>> lilypond_file['score'] <Block(name='score')> >>> lilypond_file['Custom Score'] <Score-"Custom Score"<<1>>> >>> lilypond_file[abjad.Score] <Score-"Custom Score"<<1>>> >>> lilypond_file['Custom Staff'] <Staff-"Custom Staff"<<2>>> >>> lilypond_file[abjad.Staff] <Staff-"Custom Staff"<<2>>> >>> lilypond_file['Custom Voice 1'] Voice("c''4 b'4 a'4 g'4", name='Custom Voice 1') >>> lilypond_file['Custom Voice 2'] Voice("c'4 d'4 e'4 f'4", name='Custom Voice 2') >>> lilypond_file[abjad.Voice] Voice("c''4 b'4 a'4 g'4", name='Custom Voice 1') .. container:: example REGRESSION. Works when score block contains parallel container: >>> include_container = abjad.Container() >>> string = r'\include "layout.ly"' >>> literal = abjad.LilyPondLiteral(string, 'opening') >>> abjad.attach(literal, include_container) >>> staff = abjad.Staff("c'4 d' e' f'", name='CustomStaff') >>> container = abjad.Container( ... [include_container, staff], ... is_simultaneous=True, ... ) >>> lilypond_file = abjad.LilyPondFile.new( ... container, ... lilypond_language_token=False, ... lilypond_version_token=False, ... ) >>> del(lilypond_file.items[:3]) >>> abjad.f(lilypond_file) \score { << { \include "layout.ly" } \context Staff = "CustomStaff" { c'4 d'4 e'4 f'4 } >> } >>> lilypond_file[abjad.Staff] Staff("c'4 d'4 e'4 f'4", name='CustomStaff') >>> lilypond_file['CustomStaff'] Staff("c'4 d'4 e'4 f'4", name='CustomStaff') Returns item. Raises key error when no item with `name` is found. ''' if not isinstance(name, str): if inspect.isclass(name): assert issubclass(name, Component), repr(name) else: assert isinstance(name, Component), repr(name) score = None if self.score_block and self.score_block.items: items = self.score_block.items for container in iterate(items).components(Container): if isinstance(container, Context): score = container break if isinstance(name, str): for item in self.items: if getattr(item, 'name', None) == name: return item if score is not None: if score.name == name: return score context = score[name] return context raise KeyError(f'can not find item with name {name!r}.') elif isinstance(name, Component): for item in self.items: if item is name: return item if score is not None: if score is name: return score prototype = Context for context in iterate(score).components(prototype): if context is name: return context raise KeyError(f'can not find {name}.') elif inspect.isclass(name) and issubclass(name, Component): for item in self.items: if isinstance(item, name): return item if score is not None: if isinstance(score, name): return score prototype = Context for context in iterate(score).components(prototype): if isinstance(context, name): return context raise KeyError(f'can not find item of class {name}.') else: raise TypeError(name)
def rhythm( class_, selections, divisions=None, attach_lilypond_voice_commands=None, implicit_scaling=None, pitched_staff=None, simultaneous_selections=None, time_signatures=None, ): r""" Makes rhythm-styled LilyPond file. .. container:: example Makes rhythmic staff: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file[abjad.Score] >>> abjad.f(score) \new Score << \new GlobalContext { { % measure \time 3/4 s1 * 3/4 } % measure { % measure \time 4/8 s1 * 1/2 } % measure { % measure \time 1/4 s1 * 1/4 } % measure } \new RhythmicStaff { { % measure \time 3/4 c'8 [ c'8 c'8 c'8 c'8 c'8 ] } % measure { % measure \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } % measure { % measure \time 1/4 c'8 [ c'8 ] } % measure } >> .. container:: example Set time signatures explicitly: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... [(6, 8), (4, 8), (2, 8)], ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> score = lilypond_file[abjad.Score] >>> abjad.f(score) \new Score << \new GlobalContext { { % measure \time 6/8 s1 * 3/4 } % measure { % measure \time 4/8 s1 * 1/2 } % measure { % measure \time 2/8 s1 * 1/4 } % measure } \new RhythmicStaff { { % measure \time 6/8 c'8 [ c'8 c'8 c'8 c'8 c'8 ] } % measure { % measure \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } % measure { % measure \time 2/8 c'8 [ c'8 ] } % measure } >> .. container:: example Makes pitched staff: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... pitched_staff=True, ... ) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> abjad.f(lilypond_file[abjad.Score]) \new Score << \new GlobalContext { { % measure \time 3/4 s1 * 3/4 } % measure { % measure \time 4/8 s1 * 1/2 } % measure { % measure \time 1/4 s1 * 1/4 } % measure } \new Staff { { % measure \time 3/4 c'8 [ c'8 c'8 c'8 c'8 c'8 ] } % measure { % measure \time 4/8 c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] } % measure { % measure \time 1/4 c'8 [ c'8 ] } % measure } >> .. container:: example Makes simultaneous voices: >>> divisions = [(3, 4), (4, 8), (1, 4)] >>> maker = abjad.NoteMaker() >>> selections = [ ... maker(6 * [0], [(1, 8)]), ... maker(8 * [0], [(1, 16)]), ... maker(2 * [0], [(1, 8)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> for note in abjad.iterate(selections).components(abjad.Note): ... note.written_pitch = abjad.NamedPitch("e'") ... >>> selection_1 = selections[0] + selections[1] + selections[2] >>> selections = [ ... maker(12 * [0], [(1, 16)]), ... maker(16 * [0], [(1, 32)]), ... maker(4 * [0], [(1, 16)]), ... ] >>> for selection in selections: ... abjad.attach(abjad.Beam(), selection[:]) ... >>> selection_2 = selections[0] + selections[1] + selections[2] >>> selections = { ... 'Voice 1': selection_1, ... 'Voice 2': selection_2, ... } >>> lilypond_file = abjad.LilyPondFile.rhythm( ... selections, ... divisions, ... ) >>> voice_1 = lilypond_file['Voice 1'] >>> abjad.attach(abjad.LilyPondLiteral(r'\voiceOne'), voice_1) >>> voice_2 = lilypond_file['Voice 2'] >>> abjad.attach(abjad.LilyPondLiteral(r'\voiceTwo'), voice_2) >>> abjad.show(lilypond_file) # doctest: +SKIP .. docs:: >>> abjad.f(lilypond_file[abjad.Score]) \new Score << \new GlobalContext { { % measure \time 3/4 s1 * 3/4 } % measure { % measure \time 4/8 s1 * 1/2 } % measure { % measure \time 1/4 s1 * 1/4 } % measure } \new Staff << \context Voice = "Voice 1" { \voiceOne e'8 [ e'8 e'8 e'8 e'8 e'8 ] e'16 [ e'16 e'16 e'16 e'16 e'16 e'16 e'16 ] e'8 [ e'8 ] } \context Voice = "Voice 2" { \voiceTwo c'16 [ c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 c'16 ] c'32 [ c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 c'32 ] c'16 [ c'16 c'16 c'16 ] } >> >> Returns LilyPond file. """ if isinstance(selections, list): for selection in selections: if not isinstance(selection, Selection): message = f'must be selection: {selection!r}.' raise TypeError(message) elif isinstance(selections, dict): for selection in selections.values(): if not isinstance(selection, Selection): message = f'must be selection: {selection!r}.' raise TypeError(message) else: message = f'must be list or dictionary: {selections!r}.' raise TypeError(message) score = Score() lilypond_file = LilyPondFile.new( score, includes=['default.ily', 'rhythm-maker-docs.ily'], ) if pitched_staff is None: if isinstance(selections, list): selections_ = selections elif isinstance(selections, dict): selections_ = selections.values() else: raise TypeError(selections) for note in iterate(selections_).leaves(Note): if note.written_pitch != NamedPitch("c'"): pitched_staff = True break if isinstance(selections, list): if divisions is None: duration = abjad_inspect(selections).get_duration() divisions = [duration] time_signatures = time_signatures or divisions maker = MeasureMaker(implicit_scaling=implicit_scaling) measures = maker(time_signatures) if pitched_staff: staff = Staff(measures) else: staff = Staff(measures, lilypond_type='RhythmicStaff') selections = sequence(selections).flatten(depth=-1) selections_ = copy.deepcopy(selections) try: agent = mutate(staff) measures = agent.replace_measure_contents(selections) except StopIteration: if pitched_staff: staff = Staff(selections_) else: staff = Staff( selections_, lilypond_type='RhythmicStaff', ) elif isinstance(selections, dict): voices = [] for voice_name in sorted(selections): selections_ = selections[voice_name] selections_ = sequence(selections_).flatten(depth=-1) selections_ = copy.deepcopy(selections_) voice = Voice(selections_, name=voice_name) if attach_lilypond_voice_commands: voice_name_to_command_string = { 'Voice 1': 'voiceOne', 'Voice 2': 'voiceTwo', 'Voice 3': 'voiceThree', 'Voice 4': 'voiceFour', } command_string = voice_name_to_command_string.get( voice_name, ) if command_string: command = LilyPondLiteral('\\' + command_string) attach(command, voice) voices.append(voice) staff = Staff(voices, is_simultaneous=True) if divisions is None: duration = abjad_inspect(staff).get_duration() divisions = [duration] else: message = 'must be list or dictionary of selections:' message += f' {selections!r}.' raise TypeError(message) score.append(staff) assert isinstance(divisions, collections.Sequence), repr(divisions) time_signatures = time_signatures or divisions context = Context(lilypond_type='GlobalContext') maker = MeasureMaker(implicit_scaling=implicit_scaling) measures = maker(time_signatures) context.extend(measures) score.insert(0, context) return lilypond_file
def __getitem__(self, name): r""" Gets item with ``name``. .. container:: example Gets header block: >>> lilypond_file = abjad.LilyPondFile.new() >>> lilypond_file['header'] <Block(name='header')> .. container:: example Searches score: >>> voice_1 = abjad.Voice("c''4 b' a' g'", name='Custom Voice 1') >>> abjad.attach(abjad.LilyPondLiteral(r'\voiceOne'), voice_1) >>> voice_2 = abjad.Voice("c'4 d' e' f'", name='Custom Voice 2') >>> abjad.attach(abjad.LilyPondLiteral(r'\voiceTwo'), voice_2) >>> staff = abjad.Staff( ... [voice_1, voice_2], ... is_simultaneous=True, ... name='Custom Staff', ... ) >>> score = abjad.Score([staff], name='Custom Score') >>> lilypond_file = abjad.LilyPondFile.new(score) >>> abjad.show(score) # doctest: +SKIP .. docs:: >>> abjad.f(score) \context Score = "Custom Score" << \context Staff = "Custom Staff" << \context Voice = "Custom Voice 1" { \voiceOne c''4 b'4 a'4 g'4 } \context Voice = "Custom Voice 2" { \voiceTwo c'4 d'4 e'4 f'4 } >> >> >>> lilypond_file['score'] <Block(name='score')> >>> lilypond_file['Custom Score'] <Score-"Custom Score"<<1>>> >>> lilypond_file[abjad.Score] <Score-"Custom Score"<<1>>> >>> lilypond_file['Custom Staff'] <Staff-"Custom Staff"<<2>>> >>> lilypond_file[abjad.Staff] <Staff-"Custom Staff"<<2>>> >>> lilypond_file['Custom Voice 1'] Voice("c''4 b'4 a'4 g'4", name='Custom Voice 1') >>> lilypond_file['Custom Voice 2'] Voice("c'4 d'4 e'4 f'4", name='Custom Voice 2') >>> lilypond_file[abjad.Voice] Voice("c''4 b'4 a'4 g'4", name='Custom Voice 1') .. container:: example REGRESSION. Works when score block contains parallel container: >>> include_container = abjad.Container() >>> string = r'\include "layout.ly"' >>> literal = abjad.LilyPondLiteral(string, 'opening') >>> abjad.attach(literal, include_container) >>> staff = abjad.Staff("c'4 d' e' f'", name='CustomStaff') >>> container = abjad.Container( ... [include_container, staff], ... is_simultaneous=True, ... ) >>> lilypond_file = abjad.LilyPondFile.new( ... container, ... lilypond_language_token=False, ... lilypond_version_token=False, ... ) >>> del(lilypond_file.items[:3]) >>> abjad.f(lilypond_file) \score { << { \include "layout.ly" } \context Staff = "CustomStaff" { c'4 d'4 e'4 f'4 } >> } >>> lilypond_file[abjad.Staff] Staff("c'4 d'4 e'4 f'4", name='CustomStaff') >>> lilypond_file['CustomStaff'] Staff("c'4 d'4 e'4 f'4", name='CustomStaff') Returns item. Raises key error when no item with ``name`` is found. """ if not isinstance(name, str): if inspect.isclass(name): assert issubclass(name, Component), repr(name) else: assert isinstance(name, Component), repr(name) score = None if self.score_block and self.score_block.items: items = self.score_block.items for container in iterate(items).components(Container): if isinstance(container, Context): score = container break if isinstance(name, str): for item in self.items: if getattr(item, 'name', None) == name: return item if score is not None: if score.name == name: return score context = score[name] return context raise KeyError(f'can not find item with name {name!r}.') elif isinstance(name, Component): for item in self.items: if item is name: return item if score is not None: if score is name: return score prototype = Context for context in iterate(score).components(prototype): if context is name: return context raise KeyError(f'can not find {name}.') elif inspect.isclass(name) and issubclass(name, Component): for item in self.items: if isinstance(item, name): return item if score is not None: if isinstance(score, name): return score prototype = Context for context in iterate(score).components(prototype): if isinstance(context, name): return context raise KeyError(f'can not find item of class {name}.') else: raise TypeError(name)