def duration_to_milliseconds(self, duration): r'''Gets millisecond value of `duration` under a given tempo. .. container:: example :: >>> duration = (1, 4) >>> tempo = Tempo((1, 4), 60) >>> tempo.duration_to_milliseconds(duration) Duration(1000, 1) Returns duration. ''' duration = durationtools.Duration(duration) # TODO: rewrite formula without line breaks; # use two or three temporary variables instead. whole_note_duration = 1000 \ * durationtools.Multiplier( self.duration.denominator, self.duration.numerator, ) \ * durationtools.Multiplier( 60, self.units_per_minute, ) return durationtools.Duration(duration * whole_note_duration)
def __init__( self, compound_meter_multiplier=durationtools.Multiplier(1), cyclic=True, durations=(), pattern_rotation_index=0, remainder=Right, remainder_fuse_threshold=None, ): compound_meter_multiplier = durationtools.Multiplier( compound_meter_multiplier) self._compound_meter_multiplier = compound_meter_multiplier assert isinstance(cyclic, bool), repr(cyclic) self._cyclic = cyclic durations = durations or () pattern_ = [] for division in durations: division = mathtools.NonreducedFraction(division) pattern_.append(division) durations = tuple(pattern_) self._pattern = durations assert remainder in (Left, Right), repr(remainder) self._remainder = remainder assert isinstance(pattern_rotation_index, int) self._pattern_rotation_index = pattern_rotation_index if remainder_fuse_threshold is not None: remainder_fuse_threshold = durationtools.Duration( remainder_fuse_threshold, ) self._remainder_fuse_threshold = remainder_fuse_threshold self._callbacks = ()
def _scale(self, multiplier=None): from abjad.tools import indicatortools if multiplier is None: return multiplier = durationtools.Multiplier(multiplier) old_time_signature = self.time_signature if mathtools.is_nonnegative_integer_power_of_two(multiplier) and \ 1 <= multiplier: old_numerator = old_time_signature.numerator old_denominator = old_time_signature.denominator new_denominator = old_denominator // multiplier.numerator pair = (old_numerator, new_denominator) new_time_signature = indicatortools.TimeSignature(pair) else: old_denominator = old_time_signature.denominator old_duration = old_time_signature.duration new_duration = multiplier * old_duration new_time_signature = \ self._duration_and_possible_denominators_to_time_signature( new_duration, [old_denominator], multiplier.denominator, ) detach(indicatortools.TimeSignature, self) attach(new_time_signature, self) contents_multiplier_denominator = \ mathtools.greatest_power_of_two_less_equal(multiplier.denominator) pair = (multiplier.numerator, contents_multiplier_denominator) contents_multiplier = durationtools.Multiplier(*pair) self._scale_contents(contents_multiplier)
def prolations(self): r'''Prolations of rhythm tree node. Returns tuple. ''' prolations = [durationtools.Multiplier(1)] improper_parentage = self.improper_parentage for child, parent in \ sequencetools.iterate_sequence_nwise(improper_parentage): prolations.append(durationtools.Multiplier( parent.preprolated_duration, parent._contents_duration)) return tuple(prolations)
def __illustrate__(self): r'''Illustrates pitch segment. :: >>> named_pitch_segment = pitchtools.PitchSegment( ... ['bf,', 'aqs', "fs'", "g'", 'bqf', "g'"], ... item_class=NamedPitch, ... ) >>> show(named_pitch_segment) # doctest: +SKIP Returns LilyPond file. ''' from abjad.tools import durationtools from abjad.tools import lilypondfiletools from abjad.tools import markuptools from abjad.tools import pitchtools from abjad.tools import scoretools from abjad.tools.topleveltools import attach from abjad.tools.topleveltools import iterate from abjad.tools.topleveltools import override named_pitches = [pitchtools.NamedPitch(x) for x in self] notes = scoretools.make_notes(named_pitches, [1]) score, treble_staff, bass_staff = \ scoretools.make_piano_sketch_score_from_leaves(notes) for leaf in iterate(score).by_class(scoretools.Leaf): attach(durationtools.Multiplier(1, 8), leaf) override(score).rest.transparent = True lilypond_file = lilypondfiletools.make_basic_lilypond_file(score) lilypond_file.header_block.tagline = markuptools.Markup('""') return lilypond_file
def scale(self, multiplier): r'''Scale offset expression by `multiplier`. :: >>> result = offset.scale(Multiplier(4, 5)) :: >>> print(format(result)) musicexpressiontools.OffsetExpression( anchor=musicexpressiontools.TimespanExpression( anchor='red', callbacks=musicexpressiontools.CallbackInventory( [] ), ), edge=Right, callbacks=musicexpressiontools.CallbackInventory( ['self._scale(offset, Multiplier(4, 5))'] ), ) Returns offset expression copy with callback. ''' multiplier = durationtools.Multiplier(multiplier) callback = 'self._scale(offset, {!r})' callback = callback.format(multiplier) return self._copy_and_append_callback(callback)
def implied_prolation(self): r'''Implied prolation of duration. :: >>> for denominator in range(1, 16 + 1): ... duration = Duration(1, denominator) ... result = duration.implied_prolation ... print('{!s}\t{!s}'.format(duration, result)) ... 1 1 1/2 1 1/3 2/3 1/4 1 1/5 4/5 1/6 2/3 1/7 4/7 1/8 1 1/9 8/9 1/10 4/5 1/11 8/11 1/12 2/3 1/13 8/13 1/14 4/7 1/15 8/15 1/16 1 Returns new multipler. ''' from abjad.tools import durationtools numerator = \ mathtools.greatest_power_of_two_less_equal(self.denominator) return durationtools.Multiplier(numerator, self.denominator)
def __call__(self, expr): r'''Calls metrical accent kernal on `expr`. :: >>> upper_staff = Staff("c'8 d'4. e'8 f'4.") >>> lower_staff = Staff(r'\clef bass c4 b,4 a,2') >>> score = Score([upper_staff, lower_staff]) :: >>> kernel = metertools.MetricAccentKernel.from_meter((4, 4)) >>> kernel(score) Multiplier(10, 33) Returns float. ''' offset_count = self.count_offsets_in_expr(expr) response = durationtools.Multiplier(0, 1) for offset, count in offset_count.items(): if offset in self._kernel: weight = self._kernel[offset] weighted_count = weight * count response += weighted_count return response
def _prolations(self): prolations = [] default = durationtools.Multiplier(1) for parent in self: prolation = getattr(parent, 'implied_prolation', default) prolations.append(prolation) return prolations
def multipliers(self): r'''Gets multipliers of ratio. .. container:: example **Example 1.** Ratio of two numbers: :: >>> ratio = mathtools.Ratio((2, 4)) >>> ratio.multipliers (Multiplier(1, 3), Multiplier(2, 3)) .. container:: example **Example 2.** Ratio of three numbers: :: >>> ratio = mathtools.Ratio((2, 4, 2)) >>> ratio.multipliers (Multiplier(1, 4), Multiplier(1, 2), Multiplier(1, 4)) Returns tuple of multipliers. ''' from abjad.tools import durationtools weight = sum(self.numbers) multipliers = [ durationtools.Multiplier((_, weight)) for _ in self.numbers ] multipliers = tuple(multipliers) return multipliers
def scale(self, multiplier): r'''Scale timespan expression duration by `multiplier`. :: >>> timespan = red_segment.timespan.scale(Multiplier(4, 5)) :: >>> print(format(timespan)) musicexpressiontools.TimespanExpression( anchor='red', callbacks=musicexpressiontools.CallbackInventory( [ 'self._scale(original_start_offset, original_stop_offset, Multiplier(4, 5))', ] ), ) Returns copy of timespan expression with callback. ''' multiplier = durationtools.Multiplier(multiplier) callback = \ 'self._scale(original_start_offset, original_stop_offset, {!r})' callback = callback.format(multiplier) return self._copy_and_append_callback(callback)
def __init__( self, contact_point=None, ): if contact_point is not None: contact_point = durationtools.Multiplier(contact_point) assert 0 <= contact_point <= 1 self._contact_point = contact_point
def prolation(self): r'''Gets prolation. Returns multiplier. ''' prolations = [durationtools.Multiplier(1)] + self._prolations products = mathtools.cumulative_products(prolations) return products[-1]
def prolation(self): r'''Prolation governing component. Returns multiplier. ''' prolations = [durationtools.Multiplier(1)] + self._prolations products = mathtools.cumulative_products(prolations) return products[-1]
def _all_contents_are_scalable_by_multiplier(self, multiplier): from abjad.tools import scoretools multiplier = durationtools.Multiplier(multiplier) for component in self: if isinstance(component, scoretools.Leaf): candidate_duration = multiplier * component.written_duration if not candidate_duration.is_assignable: return False return True
def __init__( self, duration=durationtools.Duration(1, 4), music="c'8 c'8 c'8", ): dummy_multiplier = durationtools.Multiplier(1) Tuplet.__init__(self, dummy_multiplier, music) self._signifier = '@' self.target_duration = duration
def __illustrate__(self): r'''Illustrates pitch range. :: >>> show(pitch_range) # doctest: +SKIP Returns LilyPond file. ''' from abjad.tools import durationtools from abjad.tools import lilypondfiletools from abjad.tools import indicatortools from abjad.tools import markuptools from abjad.tools import pitchtools from abjad.tools import scoretools from abjad.tools import spannertools from abjad.tools.topleveltools import attach from abjad.tools.topleveltools import iterate from abjad.tools.topleveltools import override start_pitch_clef = pitchtools.suggest_clef_for_named_pitches( self.start_pitch) stop_pitch_clef = pitchtools.suggest_clef_for_named_pitches( self.stop_pitch) start_note = scoretools.Note(self.start_pitch, 1) stop_note = scoretools.Note(self.stop_pitch, 1) glissando = spannertools.Glissando() if start_pitch_clef == stop_pitch_clef: if start_pitch_clef == indicatortools.Clef('bass'): bass_staff = scoretools.Staff() attach(indicatortools.Clef('bass'), bass_staff) bass_staff.extend([start_note, stop_note]) attach(glissando, bass_staff.select_leaves()) score = scoretools.Score([bass_staff]) else: treble_staff = scoretools.Staff() attach(indicatortools.Clef('treble'), treble_staff) treble_staff.extend([start_note, stop_note]) attach(glissando, treble_staff.select_leaves()) score = scoretools.Score([treble_staff]) else: result = scoretools.make_empty_piano_score() score, treble_staff, bass_staff = result bass_staff.extend([start_note, stop_note]) treble_staff.extend(scoretools.Skip(1) * 2) attach(glissando, bass_staff.select_leaves()) attach(indicatortools.StaffChange(treble_staff), bass_staff[1]) for leaf in iterate(score).by_class(scoretools.Leaf): attach(durationtools.Multiplier(1, 4), leaf) override(score).bar_line.stencil = False override(score).span_bar.stencil = False override(score).glissando.thickness = 2 override(score).time_signature.stencil = False lilypond_file = lilypondfiletools.make_basic_lilypond_file(score) lilypond_file.header_block.tagline = markuptools.Markup('""') return lilypond_file
def with_power_of_two_denominator( self, contents_multiplier=durationtools.Multiplier(1), ): r'''Makes new time signature equivalent to current time signature with power-of-two denominator. .. container:: example **Example 1.** Non-power-of-two denominator with power-of-two denominator: >>> time_signature = TimeSignature((3, 12)) >>> time_signature.with_power_of_two_denominator() TimeSignature((2, 8)) Returns new time signature. ''' # check input contents_multiplier = durationtools.Multiplier(contents_multiplier) # save non_power_of_two time_signature and denominator non_power_of_two_denominator = self.denominator # find power_of_two denominator if contents_multiplier == durationtools.Multiplier(1): power_of_two_denominator = \ mathtools.greatest_power_of_two_less_equal( non_power_of_two_denominator) else: power_of_two_denominator = \ mathtools.greatest_power_of_two_less_equal( non_power_of_two_denominator, 1) # find power_of_two pair non_power_of_two_pair = mathtools.NonreducedFraction(self.pair) power_of_two_fraction = non_power_of_two_pair.with_denominator( power_of_two_denominator) power_of_two_pair = power_of_two_fraction.pair # return new power_of_two time signature return type(self)(power_of_two_pair)
def _make_leaf_on_pitch( pitch, duration, decrease_durations_monotonically=True, forbidden_written_duration=None, use_multimeasure_rests=False, use_messiaen_style_ties=False, ): from abjad.tools import scoretools note_prototype = ( numbers.Number, str, pitchtools.NamedPitch, pitchtools.PitchClass, ) chord_prototype = (tuple, list) rest_prototype = (type(None), ) if isinstance(pitch, note_prototype): leaves = scoretools.make_tied_leaf( scoretools.Note, duration, decrease_durations_monotonically=decrease_durations_monotonically, forbidden_written_duration=forbidden_written_duration, pitches=pitch, use_messiaen_style_ties=use_messiaen_style_ties, ) elif isinstance(pitch, chord_prototype): leaves = scoretools.make_tied_leaf( scoretools.Chord, duration, decrease_durations_monotonically=decrease_durations_monotonically, forbidden_written_duration=forbidden_written_duration, pitches=pitch, use_messiaen_style_ties=use_messiaen_style_ties, ) elif isinstance(pitch, rest_prototype) and not use_multimeasure_rests: leaves = scoretools.make_tied_leaf( scoretools.Rest, duration, decrease_durations_monotonically=decrease_durations_monotonically, forbidden_written_duration=forbidden_written_duration, pitches=None, use_messiaen_style_ties=use_messiaen_style_ties, ) elif isinstance(pitch, rest_prototype) and use_multimeasure_rests: multimeasure_rest = scoretools.MultimeasureRest((1)) multiplier = durationtools.Multiplier(duration) attach(multiplier, multimeasure_rest) leaves = (multimeasure_rest, ) else: message = 'unknown pitch {!r}.' message = message.format(pitch) raise ValueError(message) return leaves
def make_multiplied_quarter_notes( pitches, multiplied_durations, ): r'''Make quarter notes with `pitches` and `multiplied_durations`: :: >>> args = [[0, 2, 4, 5], [(1, 4), (1, 5), (1, 6), (1, 7)]] >>> scoretools.make_multiplied_quarter_notes(*args) Selection(Note("c'4 * 1"), Note("d'4 * 4/5"), Note("e'4 * 2/3"), Note("f'4 * 4/7")) Read `pitches` cyclically where the length of `pitches` is less than the length of `multiplied_durations`: :: >>> args = [[0], [(1, 4), (1, 5), (1, 6), (1, 7)]] >>> scoretools.make_multiplied_quarter_notes(*args) Selection(Note("c'4 * 1"), Note("c'4 * 4/5"), Note("c'4 * 2/3"), Note("c'4 * 4/7")) Read `multiplied_durations` cyclically where the length of `multiplied_durations` is less than the length of `pitches`: :: >>> args = [[0, 2, 4, 5], [(1, 5)]] >>> scoretools.make_multiplied_quarter_notes(*args) Selection(Note("c'4 * 4/5"), Note("d'4 * 4/5"), Note("e'4 * 4/5"), Note("f'4 * 4/5")) Returns list of zero or more newly constructed notes. ''' from abjad.tools import scoretools multiplied_durations = [ durationtools.Duration(x) for x in multiplied_durations ] quarter_notes = [] sequences = [pitches, multiplied_durations] for pitch, duration in sequencetools.zip_sequences(sequences, cyclic=True): quarter_note = scoretools.Note(pitch, durationtools.Duration(1, 4)) duration = durationtools.Duration(duration) multiplier = durationtools.Multiplier(duration / durationtools.Duration(1, 4)) attach(multiplier, quarter_note) quarter_notes.append(quarter_note) quarter_notes = selectiontools.Selection(quarter_notes) return quarter_notes
def duration_to_milliseconds(self, duration): r'''Millisecond value of `duration` under a given tempo. :: >>> duration = (1, 4) >>> tempo = Tempo((1, 4), 60) >>> tempo.duration_to_milliseconds(duration) Duration(1000, 1) Returns duration. ''' duration = durationtools.Duration(duration) whole_note_duration = 1000 \ * durationtools.Multiplier( self.duration.denominator, self.duration.numerator, ) \ * durationtools.Multiplier( 60, self.units_per_minute, ) return durationtools.Duration(duration * whole_note_duration)
def implied_prolation(self): r'''Implied prolation of measure. .. container:: example Measures with implicit scaling scale the duration of their contents: :: >>> measure = Measure((5, 12), "c'8 d'8 e'8 f'8 g'8") >>> measure.implicit_scaling = True >>> show(measure) # doctest: +SKIP :: >>> measure.implied_prolation Multiplier(2, 3) :: >>> for note in measure: ... note, inspect_(note).get_duration() (Note("c'8"), Duration(1, 12)) (Note("d'8"), Duration(1, 12)) (Note("e'8"), Duration(1, 12)) (Note("f'8"), Duration(1, 12)) (Note("g'8"), Duration(1, 12)) .. container:: example Measures without implicit scaling turned on do not scale the duration of their contents: :: >>> measure = Measure((5, 12), []) >>> measure.implicit_scaling = False :: >>> measure.implied_prolation Multiplier(1, 1) Returns positive multiplier. ''' if self.implicit_scaling: time_signature = self.time_signature return time_signature.implied_prolation return durationtools.Multiplier(1)
def __div__(self, *args): r'''Divides duration by `args`. Returns multiplier. ''' from abjad.tools import durationtools if len(args) == 1 and isinstance(args[0], type(self)): fraction = fractions.Fraction.__truediv__(self, *args) result = durationtools.Multiplier(fraction) elif len(args) == 1 and isinstance(args[0], mathtools.NonreducedFraction): result = args[0].__rdiv__(self) else: result = type(self)(fractions.Fraction.__truediv__(self, *args)) return result
def multiply_with_numerator_preservation(self, multiplier): r'''Multiplies nonreduced fraction by `multiplier` with numerator preservation where possible. :: >>> fraction = mathtools.NonreducedFraction(9, 16) :: >>> fraction.multiply_with_numerator_preservation((2, 3)) NonreducedFraction(9, 24) :: >>> fraction.multiply_with_numerator_preservation((1, 2)) NonreducedFraction(9, 32) :: >>> fraction.multiply_with_numerator_preservation((5, 6)) NonreducedFraction(45, 96) :: >>> fraction = mathtools.NonreducedFraction(3, 8) :: >>> fraction.multiply_with_numerator_preservation((2, 3)) NonreducedFraction(3, 12) Returns nonreduced fraction. ''' from abjad.tools import durationtools multiplier = durationtools.Multiplier(multiplier) self_denominator = self.denominator candidate_result_denominator = self_denominator / multiplier if candidate_result_denominator.denominator == 1: return NonreducedFraction(self.numerator, candidate_result_denominator.numerator) else: result_numerator = \ self.numerator * candidate_result_denominator.denominator result_denominator = candidate_result_denominator.numerator return NonreducedFraction(result_numerator, result_denominator)
def _scale(self, multiplier): from abjad.tools import scoretools multiplier = durationtools.Multiplier(multiplier) # find new target duration old_target_duration = self.target_duration new_target_duration = multiplier * old_target_duration # change tuplet target duration self.target_duration = new_target_duration # if multiplier is note head assignable, # scale contents graphically if multiplier.is_assignable: for component in self[:]: if isinstance(component, scoretools.Leaf): new_duration = multiplier * component.written_duration component._set_duration(new_duration) self._fix()
def multiplier(self): r'''Gets and sets multiplier of fixed-duration tuplet. :: >>> tuplet = scoretools.FixedDurationTuplet( ... (1, 4), "c'8 d'8 e'8") >>> tuplet.multiplier Multiplier(2, 3) Returns multiplier. ''' if 0 < len(self): return durationtools.Multiplier(self.target_duration / self._contents_duration) else: return None
def multipliers(self): r'''Gets multipliers implicit in ratio. .. container:: example **Example 1.** Gets mutlipliers: :: >>> mathtools.NonreducedRatio((2, 4, 2)).multipliers (Multiplier(1, 4), Multiplier(1, 2), Multiplier(1, 4)) Returns tuple of multipliers. ''' from abjad.tools import durationtools weight = sum(self) multipliers = [durationtools.Multiplier((_, weight)) for _ in self] multipliers = tuple(multipliers) return multipliers
def _get_likely_multiplier_of_components(components): pass from abjad.tools import scoretools from abjad.tools import selectiontools from abjad.tools import sequencetools assert all(isinstance(x, scoretools.Component) for x in components) logical_tie_duration_numerators = [] for expr in \ iterate(components).by_topmost_logical_ties_and_components(): if isinstance(expr, selectiontools.LogicalTie): logical_tie_duration = expr._preprolated_duration logical_tie_duration_numerators.append( logical_tie_duration.numerator) if len(sequencetools.remove_repeated_elements( logical_tie_duration_numerators)) == 1: numerator = logical_tie_duration_numerators[0] denominator = mathtools.greatest_power_of_two_less_equal(numerator) likely_multiplier = durationtools.Multiplier( numerator, denominator) return likely_multiplier
def _apply_logical_tie_masks(self, selections): from abjad.tools import rhythmmakertools if self.logical_tie_masks is None: return selections # wrap every selection in a temporary container; # this allows the call to mutate().replace() to work containers = [] for selection in selections: container = scoretools.Container(selection) attach('temporary container', container) containers.append(container) logical_ties = iterate(selections).by_logical_tie() logical_ties = list(logical_ties) total_logical_ties = len(logical_ties) for index, logical_tie in enumerate(logical_ties[:]): matching_mask = self.logical_tie_masks.get_matching_pattern( index, total_logical_ties, ) if not isinstance(matching_mask, rhythmmakertools.SilenceMask): continue if isinstance(logical_tie.head, scoretools.Rest): continue for leaf in logical_tie: rest = scoretools.Rest(leaf.written_duration) inspector = inspect_(leaf) if inspector.has_indicator(durationtools.Multiplier): multiplier = inspector.get_indicator( durationtools.Multiplier, ) multiplier = durationtools.Multiplier(multiplier) attach(multiplier, rest) mutate(leaf).replace([rest]) detach(spannertools.Tie, rest) # remove every temporary container and recreate selections new_selections = [] for container in containers: inspector = inspect_(container) assert inspector.get_indicator(str) == 'temporary container' new_selection = mutate(container).eject_contents() new_selections.append(new_selection) return new_selections
def with_denominator(self, denominator): r'''Returns new nonreduced fraction with integer `denominator`. :: >>> mathtools.NonreducedFraction(3, 6).with_denominator(12) NonreducedFraction(6, 12) Returns nonreduced fraction. ''' from abjad.tools import durationtools current_numerator, current_denominator = self.pair multiplier = durationtools.Multiplier(denominator, current_denominator) new_numerator = multiplier * current_numerator new_denominator = multiplier * current_denominator if (new_numerator.denominator == 1 and new_denominator.denominator == 1): pair = (new_numerator.numerator, new_denominator.numerator) else: pair = (current_numerator, current_denominator) return self._from_pair(pair)