Ejemplo n.º 1
0
    def repeat_to_duration(self, duration):
        r'''Repeat payload expression to duration.

        ::

            >>> result = \
            ...     payload_expression.repeat_to_duration(Duration(13, 16))

        ::

            >>> print(format(result))
            musicexpressiontools.IterablePayloadExpression(
                payload=(
                    durationtools.Division(4, 16),
                    durationtools.Division(2, 16),
                    durationtools.Division(4, 16),
                    durationtools.Division(2, 16),
                    durationtools.Division(1, 16),
                    ),
                )

        Returns newly constructed payload expression.
        '''
        if not mathtools.all_are_numbers(self.payload):
            payload = [durationtools.Division(_) for _ in self.payload]
        else:
            payload = self.payload
        payload = sequencetools.repeat_sequence_to_weight(payload, duration)
        payload = [durationtools.Division(_) for _ in payload]
        result = new(self, payload=payload)
        return result
Ejemplo n.º 2
0
 def _to_divisions(expr, start_offset=None):
     if isinstance(expr, durationtools.Division):
         result = durationtools.Division(expr)
         if start_offset is not None:
             result._start_offset = start_offset
             start_offset += result.duration
     elif isinstance(expr, mathtools.NonreducedFraction):
         result = durationtools.Division(expr.pair)
         if start_offset is not None:
             result._start_offset = start_offset
             start_offset += result.duration
     elif hasattr(expr, 'pair'):
         result = durationtools.Division(expr.pair)
         if start_offset is not None:
             result._start_offset = start_offset
             start_offset += result.duration
     elif isinstance(expr, tuple):
         result = durationtools.Division(expr)
         if start_offset is not None:
             result._start_offset = start_offset
             start_offset += result.duration
     elif isinstance(expr, (list, sequencetools.Sequence)):
         result = []
         for element in expr:
             new_element, start_offset = DivisionMaker._to_divisions(
                 element,
                 start_offset=start_offset,
             )
             result.append(new_element)
         result = type(expr)(result)
     else:
         raise TypeError(repr(expr))
     return result, start_offset
    def __call__(self, divisions=None):
        r'''Calls rounded ratio division maker on `division`.

        ..  container:: example

            **Example 1.** Calls maker on nonempty input:

            ::

                >>> maker = makertools.SplitByRoundedRatiosDivisionCallback(
                ...     ratios=[mathtools.Ratio([1, 1])],
                ...     )
                >>> lists = maker([(7, 4), (6, 4)])
                >>> for list_ in lists:
                ...     list_
                [Division(4, 4), Division(3, 4)]
                [Division(3, 4), Division(3, 4)]

            Returns list of division lists.

        ..  container:: example

            **Example 2.** Calls maker on empty input:

            ::

                >>> maker = makertools.SplitByRoundedRatiosDivisionCallback(
                ...     ratios=[mathtools.Ratio([1, 1])],
                ...     )
                >>> maker([])
                []

            Returns empty list.

        Returns possibly empty list of division lists.
        '''
        input_divisions = divisions or []
        if not input_divisions:
            return []
        output_division_lists = []
        ratios = self._get_ratios()
        for i, input_division in enumerate(input_divisions):
            input_division = durationtools.Division(input_division)
            ratio = ratios[i]
            numerators = mathtools.partition_integer_by_ratio(
                input_division.numerator,
                ratio,
            )
            output_division_list = [
                durationtools.Division(
                    numerator,
                    input_division.denominator,
                ) for numerator in numerators
            ]
            output_division_lists.append(output_division_list)
        return output_division_lists
Ejemplo n.º 4
0
 def _coerce_divisions(self, divisions):
     nonreduced_fractions = []
     for division in divisions:
         if hasattr(division, 'time_signature'):
             nonreduced_fraction = durationtools.Division(
                 division.time_signature.pair
                 )
         else:
             nonreduced_fraction = durationtools.Division(division)
         nonreduced_fractions.append(nonreduced_fraction)
     return nonreduced_fractions
Ejemplo n.º 5
0
    def __call__(self, divisions=None):
        r'''Calls beat division maker on `divisions`.

        ..  container:: example

            **Example 1.** Calls maker on nonempty input:

            ::

                >>> maker = makertools.BeatDivisionMaker(
                ...     depths=[1],
                ...     )
                >>> lists = maker([(7, 4), (6, 4)])
                >>> for list_ in lists:
                ...     list_
                [Division(3, 4), Division(2, 4), Division(2, 4)]
                [Division(3, 4), Division(3, 4)]

            Returns list of division lists.

        ..  container:: example

            **Example 2.** Calls maker on empty input:

            ::

                >>> maker = makertools.BeatDivisionMaker(
                ...     depths=[1],
                ...     )
                >>> lists = maker([])
                >>> lists
                []

            Returns empty list.

        Returns (possibly empty) list of division lists.
        '''
        input_divisions = divisions or []
        if not input_divisions:
            return []
        output_division_lists = []
        depths = self._get_depths()
        for i, input_division in enumerate(input_divisions):
            input_division = durationtools.Division(input_division)
            depth = depths[i]
            meter = metertools.Meter(input_division)
            durations = meter.get_durations_at_depth(depth)
            denominator = input_division.denominator
            output_division_list = [
                durationtools.Division(_.with_denominator(denominator))
                for _ in durations
            ]
            output_division_lists.append(output_division_list)
        return output_division_lists
Ejemplo n.º 6
0
 def _beat_list_to_grouped_beat_list(self, beat_list):
     assert isinstance(beat_list, (list, tuple)), repr(beat_list)
     beat_list_ = []
     for beat in beat_list:
         if hasattr(beat, 'duration'):
             beat = durationtools.Division(beat.duration)
         else:
             beat = durationtools.Division(beat)
         beat_list_.append(beat)
     beat_list = beat_list_
     total_duration = sum(beat_list)
     total_duration = durationtools.Duration(total_duration)
     if (total_duration.is_assignable
             and self.fuse_assignable_total_duration):
         return [[durationtools.Division(total_duration)]]
     if self.counts is None:
         beat_group = list(beat_list)
         grouped_beat_list = [beat_group]
         return grouped_beat_list
     grouped_beat_list = sequencetools.partition_sequence_by_counts(
         beat_list,
         counts=self.counts,
         cyclic=True,
         overhang=False,
     )
     beats_included = sum([len(_) for _ in grouped_beat_list])
     if beats_included == len(beat_list):
         return grouped_beat_list
     remainder_length = len(beat_list) - beats_included
     if self.remainder_direction == Left:
         grouped_beat_list = sequencetools.partition_sequence_by_counts(
             beat_list[remainder_length:],
             counts=self.counts,
             cyclic=True,
             overhang=False)
         remainder = beat_list[:remainder_length]
         if self.append_remainder:
             grouped_beat_list[0] = remainder + grouped_beat_list[0]
         else:
             grouped_beat_list.insert(0, remainder)
     else:
         grouped_beat_list = sequencetools.partition_sequence_by_counts(
             beat_list[:-remainder_length],
             counts=self.counts,
             cyclic=True,
             overhang=False)
         remainder = beat_list[-remainder_length:]
         if self.append_remainder:
             grouped_beat_list[-1] = grouped_beat_list[-1] + remainder
         else:
             grouped_beat_list.append(remainder)
     return grouped_beat_list
Ejemplo n.º 7
0
 def __init__(
     self,
     cyclic=True,
     pattern=(),
     pattern_rotation_index=0,
     remainder=Right,
     remainder_fuse_threshold=None,
 ):
     assert isinstance(cyclic, bool), repr(cyclic)
     self._cyclic = cyclic
     pattern = pattern or ()
     pattern_ = []
     for division in pattern:
         division = durationtools.Division(division)
         pattern_.append(division)
     pattern = tuple(pattern_)
     self._pattern = pattern
     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
Ejemplo n.º 8
0
 def _time_signatures_to_naive_beats(self, time_signatures):
     naive_beats = []
     for time_signature in time_signatures:
         numerator, denominator = time_signature.pair
         naive_beats.extend(
             numerator * [durationtools.Division(1, denominator)])
     return naive_beats
Ejemplo n.º 9
0
    def __call__(self, divisions, rotation=None):
        r'''Calls rhythm-maker.

        Makes music as a list of selections.

        Applies cross-division ties (when specified by tie specifier).
        Other types of ties specified by tie specifier must be
        applied by child classes.

        Validates output type.

        Returns list of selections.
        '''
        divisions = [durationtools.Division(x) for x in divisions]
        rotation = self._to_tuple(rotation)
        self._rotation = rotation
        selections = self._make_music(
            divisions,
            rotation,
        )
        self._simplify_tuplets(selections)
        selections = self._flatten_trivial_tuplets(selections)
        self._apply_tie_specifier(selections)
        self._validate_selections(selections)
        self._validate_tuplets(selections)
        return selections
Ejemplo n.º 10
0
 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 = durationtools.Division(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 = ()
Ejemplo n.º 11
0
 def __init__(self, divisions, start_offset=None, voice_name=None):
     from experimental.tools import musicexpressiontools
     assert isinstance(voice_name, (str, type(None))), repr(voice_name)
     start_offset = start_offset or durationtools.Offset(0)
     start_offset = durationtools.Offset(start_offset)
     self._start_offset = start_offset
     divisions = [durationtools.Division(_) for _ in divisions]
     self._divisions = divisions
     self._voice_name = voice_name
Ejemplo n.º 12
0
 def _coerce_divisions(self, divisions):
     divisions_ = []
     for division in divisions:
         if hasattr(division, 'time_signature'):
             argument = division.time_signature.pair
         elif hasattr(division, 'duration'):
             argument = division.duration
         else:
             argument = division
         division_ = durationtools.Division(argument)
         divisions_.append(division_)
     return divisions_
Ejemplo n.º 13
0
 def _make_music(self, divisions, seeds):
     #assert not seeds, repr(seeds)
     if seeds is None:
         seeds = 0
     selections = []
     divisions = [durationtools.Division(_) for _ in divisions]
     denominators = datastructuretools.CyclicTuple(self.denominators)
     extra_counts_per_division = self.extra_counts_per_division or (0,)
     extra_counts_per_division = datastructuretools.CyclicTuple(
         extra_counts_per_division
         )
     for i, division in enumerate(divisions, seeds):
         # not yet extended to work with non-power-of-two divisions
         assert mathtools.is_positive_integer_power_of_two(
             division.denominator), repr(division)
         denominator = denominators[i]
         extra_count = extra_counts_per_division[i]
         basic_duration = durationtools.Duration(1, denominator)
         unprolated_note_count = None
         if division < 2 * basic_duration:
             notes = scoretools.make_notes([0], [division])
         else:
             unprolated_note_count = division / basic_duration
             unprolated_note_count = int(unprolated_note_count)
             unprolated_note_count = unprolated_note_count or 1
             if 0 < extra_count:
                 modulus = unprolated_note_count
                 extra_count = extra_count % modulus
             elif extra_count < 0:
                 modulus = int(math.ceil(unprolated_note_count / 2.0))
                 extra_count = abs(extra_count) % modulus
                 extra_count *= -1
             note_count = unprolated_note_count + extra_count
             durations = note_count * [basic_duration]
             notes = scoretools.make_notes([0], durations)
             assert all(
                 _.written_duration.denominator == denominator
                 for _ in notes
                 )
         tuplet_duration = durationtools.Duration(division)
         tuplet = scoretools.FixedDurationTuplet(
             duration=tuplet_duration,
             music=notes,
             )
         if unprolated_note_count is not None:
             preferred_denominator = unprolated_note_count
             tuplet.preferred_denominator = preferred_denominator
         selection = selectiontools.Selection(tuplet)
         selections.append(selection)
     self._apply_beam_specifier(selections)
     return selections
Ejemplo n.º 14
0
    def __call__(self, expr=None):
        r'''Makes divisions from `expr`.

        Pass in `expr` as either a list of divisions or as a list of division
        lists.

        Returns either a list of divisions or a list of division lists.
        '''
        expr = expr or []
        expr = list(expr)
        assert isinstance(expr, list), repr(expr)
        if self._is_flat_list(expr):
            expr = [durationtools.Division(_) for _ in expr]
        for callback in self.callbacks:
            expr = callback(expr)
        return expr
Ejemplo n.º 15
0
    def evaluate(self):
        r'''Evaluate division region expression.

        Returns start-positioned division payload expression.
        '''
        from experimental.tools import musicexpressiontools
        divisions = self.source_expression[:]
        divisions = [durationtools.Division(x) for x in divisions]
        divisions = sequencetools.repeat_sequence_to_weight(
            divisions, self.total_duration)
        expression = musicexpressiontools.StartPositionedDivisionPayloadExpression(
            payload=divisions,
            start_offset=self.start_offset,
            voice_name=self.voice_name,
            )
        return expression
Ejemplo n.º 16
0
 def make_time_signatures(self):
     from experimental.tools import musicexpressiontools
     if hasattr(self.source_expression, 'evaluate_early'):
         expression = self.source_expression.evaluate_early()
         assert isinstance(
             expression,
             musicexpressiontools.IterablePayloadExpression)
         time_signatures = expression.payload
     else:
         expression = self.source_expression.evaluate()
         assert isinstance(
             expression,
             musicexpressiontools.IterablePayloadExpression)
         time_signatures = expression.payload[:]
     time_signatures = [durationtools.Division(x) for x in time_signatures]
     if time_signatures:
         self.root_specification._time_signatures = time_signatures[:]
         return time_signatures
Ejemplo n.º 17
0
    def evaluate_early(self):
        r'''Evaluate measure select expression early.

        Special definition because time signatures can be evaluated
        without knowing the timespan they occupy.

        Returns start-positioned division payload expression.
        '''
        from experimental.tools import musicexpressiontools
        time_signatures = self.root_specification.time_signatures[:]
        time_signatures = [durationtools.Division(x) for x in time_signatures]
        expression = \
            musicexpressiontools.IterablePayloadExpression(time_signatures)
        expression = self._apply_callbacks(expression)
        assert isinstance(
            expression,
            musicexpressiontools.IterablePayloadExpression)
        return expression
Ejemplo n.º 18
0
    def evaluate(self):
        r'''Evaluate literal division region expression.

        Returns start-positioned division payload expression.
        '''
        from experimental.tools import musicexpressiontools
        divisions = []
        for x in self.source_expression:
            if hasattr(x, 'duration'):
                x = x.duration
            division = durationtools.Division(x)
            divisions.append(division)
        divisions = sequencetools.repeat_sequence_to_weight(
            divisions, self.total_duration)
        expression = musicexpressiontools.StartPositionedDivisionPayloadExpression(
            payload=divisions,
            start_offset=self.start_offset,
            voice_name=self.voice_name,
            )
        return expression
Ejemplo n.º 19
0
    def evaluate(self):
        r'''Evaluate select expression division region expression.

        Returns none when nonevaluable.

        Returns start-positioned division payload expression when evaluable.
        '''
        from experimental.tools import musicexpressiontools
        expression = self.source_expression.evaluate()
        if expression is not None:
            divisions = expression.elements
            divisions = [durationtools.Division(x) for x in divisions]
            divisions = sequencetools.repeat_sequence_to_weight(
                divisions, self.total_duration)
            expression = \
                musicexpressiontools.StartPositionedDivisionPayloadExpression(
                payload=divisions,
                start_offset=self.start_offset,
                voice_name=self.voice_name,
                )
            return expression
Ejemplo n.º 20
0
    def __and__(self, timespan):
        r'''Logical AND of payload expression and `timespan`.

        ::

            >>> timespan = timespantools.Timespan((1, 16), (5, 16))
            >>> result = payload_expression & timespan

        ::

            >>> print(format(result))
            timespantools.TimespanInventory(
                [
                    musicexpressiontools.IterablePayloadExpression(
                        payload=(
                            durationtools.Division(3, 16),
                            durationtools.Division(1, 16),
                            ),
                        ),
                    ]
                )

        Returns newly constructed payload expression.
        '''
        from experimental.tools import musicexpressiontools
        if not mathtools.all_are_numbers(self.payload):
            payload = [durationtools.Division(x) for x in self.payload]
        else:
            payload = self.payload
        division_payload_expression = \
            musicexpressiontools.StartPositionedDivisionPayloadExpression(
            payload=payload, start_offset=0, voice_name='dummy voice name')
        result = division_payload_expression & timespan
        assert len(result) in (0, 1)
        if result:
            divisions = result[0].payload.divisions
            expression = new(self, payload=divisions)
            result[0] = expression
        return result
Ejemplo n.º 21
0
    def evaluate(self):
        r'''Evaluate measure select expression.

        Returns none when nonevaluable.

        Returns start-positioned division payload expression when evaluable.
        '''
        from experimental.tools import musicexpressiontools
        anchor_timespan = self._evaluate_anchor_timespan()
        time_relation = self._get_time_relation(anchor_timespan)
        time_signatures = self.root_specification.time_signatures[:]
        time_signatures = [durationtools.Division(x) for x in time_signatures]
        start_offset = self.root_specification.timespan.start_offset
        expression = \
            musicexpressiontools.StartPositionedDivisionPayloadExpression(
            payload=time_signatures,
            start_offset=start_offset,
            )
        callback_cache = self.score_specification.interpreter.callback_cache
        expression = expression.get_elements_that_satisfy_time_relation(
            time_relation, callback_cache)
        expression = self._apply_callbacks(expression)
        #expression._voice_name = self.voice_name
        return expression
Ejemplo n.º 22
0
    def __call__(self, divisions=None):
        r'''Calls division-maker on `divisions`.

        ..  container:: example

            **Example 1.** Division without remainder:

            ::

                >>> maker = makertools.SplitByDurationsDivisionCallback(
                ...     cyclic=True,
                ...     durations=[(1, 4)],
                ...     )

            ::

                >>> time_signatures = [(3, 4)]
                >>> division_lists = maker(time_signatures)
                >>> for division_list in division_lists:
                ...     division_list
                [Division(1, 4), Division(1, 4), Division(1, 4)]

            ::

                >>> maker = rhythmmakertools.NoteRhythmMaker()
                >>> divisions = sequencetools.flatten_sequence(division_lists)
                >>> music = maker(divisions)
                >>> lilypond_file = rhythmmakertools.make_lilypond_file(
                ...     music,
                ...     divisions,
                ...     time_signatures=time_signatures,
                ...     )
                >>> show(lilypond_file) # doctest: +SKIP

            ..  doctest::

                >>> staff = maker._get_rhythmic_staff(lilypond_file)
                >>> f(staff)
                \new RhythmicStaff {
                    {
                        \time 3/4
                        c'4
                        c'4
                        c'4
                    }
                }

        ..  container:: example

            **Example 2.** Division with remainder:

            ::

                >>> maker = makertools.SplitByDurationsDivisionCallback(
                ...     durations=[(1, 4)],
                ...     )

            ::

                >>> time_signatures = [(7, 8)]
                >>> division_lists = maker(time_signatures)
                >>> for division_list in division_lists:
                ...     division_list 
                [Division(1, 4), Division(1, 4), Division(1, 4), Division(1, 8)]

            ::

                >>> maker = rhythmmakertools.NoteRhythmMaker()
                >>> divisions = sequencetools.flatten_sequence(division_lists)
                >>> music = maker(divisions)
                >>> lilypond_file = rhythmmakertools.make_lilypond_file(
                ...     music,
                ...     divisions,
                ...     time_signatures=time_signatures,
                ...     )
                >>> show(lilypond_file) # doctest: +SKIP

            ..  doctest::

                >>> staff = maker._get_rhythmic_staff(lilypond_file)
                >>> f(staff)
                \new RhythmicStaff {
                    {
                        \time 7/8
                        c'4
                        c'4
                        c'4
                        c'8
                    }
                }

            Positions remainder at right of output because divison-maker
            `remainder` defaults to right.

        ..  container:: example

            **Example 3.** Multiple divisions:

            ::

                >>> maker = makertools.SplitByDurationsDivisionCallback(
                ...     cyclic=True,
                ...     durations=[(1, 4)],
                ...     )

            ::

                >>> time_signatures = [(2, 4), (3, 4)]
                >>> division_lists = maker(time_signatures)
                >>> for division_list in division_lists:
                ...     division_list
                [Division(1, 4), Division(1, 4)]
                [Division(1, 4), Division(1, 4), Division(1, 4)]

            ::

                >>> maker = rhythmmakertools.NoteRhythmMaker()
                >>> divisions = sequencetools.flatten_sequence(division_lists)
                >>> music = maker(divisions)
                >>> lilypond_file = rhythmmakertools.make_lilypond_file(
                ...     music,
                ...     divisions,
                ...     time_signatures=time_signatures,
                ...     )
                >>> show(lilypond_file) # doctest: +SKIP

            ..  doctest::

                >>> staff = maker._get_rhythmic_staff(lilypond_file)
                >>> f(staff)
                \new RhythmicStaff {
                    {
                        \time 2/4
                        c'4
                        c'4
                    }
                    {
                        \time 3/4
                        c'4
                        c'4
                        c'4
                    }
                }

        ..  container:: example

            **Example 4.** No durations:

            ::

                >>> maker = makertools.SplitByDurationsDivisionCallback()

            ::

                >>> time_signatures = [(6, 32)]
                >>> division_lists = maker(time_signatures)
                >>> for division_list in division_lists:
                ...     division_list
                [Division(6, 32)]

            ::

                >>> maker = rhythmmakertools.NoteRhythmMaker()
                >>> divisions = sequencetools.flatten_sequence(division_lists)
                >>> music = maker(divisions)
                >>> lilypond_file = rhythmmakertools.make_lilypond_file(
                ...     music,
                ...     divisions,
                ...     time_signatures=time_signatures,
                ...     )
                >>> show(lilypond_file) # doctest: +SKIP

            ..  doctest::

                >>> staff = maker._get_rhythmic_staff(lilypond_file)
                >>> f(staff)
                \new RhythmicStaff {
                    {
                        \time 6/32
                        c'8.
                    }
                }

            Returns input division unchanged.

        ..  container:: example

            **Example 5.** Empty input:

            ::

                >>> maker = makertools.SplitByDurationsDivisionCallback(durations=[(1, 4)])
                >>> maker()
                []

            Returns empty list.

        Returns possibly empty list of division lists.
        '''
        divisions = divisions or []
        if not divisions:
            return divisions
        division_lists = []
        for i, division in enumerate(divisions):
            input_division = durationtools.Division(division)
            input_duration = durationtools.Duration(input_division)
            input_meter = metertools.Meter(input_division)
            assert 0 < input_division, repr(input_division)
            if not self.durations:
                division_list = [input_division]
                division_lists.append(division_list)
                continue
            if input_meter.is_simple or not self.durations:
                durations = self.durations[:]
            elif input_meter.is_compound:
                multiplier = self.compound_meter_multiplier
                durations = [
                    durationtools.Division(multiplier * _)
                    for _ in self.durations
                    ]
            #division_list = list(self.durations)
            division_list = list(durations)
            pattern_rotation_index = self.pattern_rotation_index or 0
            pattern_rotation_index *= i
            division_list = sequencetools.rotate_sequence(
                division_list,
                pattern_rotation_index,
                )
            if self.cyclic:
                division_list = sequencetools.repeat_sequence_to_weight(
                    division_list,
                    input_division,
                    allow_total=Less,
                    )
            total_duration = durationtools.Duration(sum(division_list))
            if total_duration == input_duration:
                division_lists.append(division_list)
                continue
            if self.remainder is None:
                message = 'can not fill {} from {} exactly.'
                #message = message.format(input_division, self.durations)
                message = message.format(input_division, durations)
                raise Exception(message)
            remainder = input_division - total_duration
            remainder = durationtools.Duration(remainder)
            remainder = durationtools.Division(remainder)
            if self.remainder == Left:
                if self.remainder_fuse_threshold is None:
                    division_list.insert(0, remainder)
                elif remainder <= self.remainder_fuse_threshold:
                    fused_value = division_list[0] + remainder
                    fused_value = durationtools.Division(fused_value)
                    division_list[0] = fused_value
                else:
                    division_list.insert(0, remainder)
            elif self.remainder == Right:
                if self.remainder_fuse_threshold is None:
                    division_list.append(remainder)
                elif remainder <= self.remainder_fuse_threshold:
                    fused_value = division_list[-1] + remainder
                    fused_value = durationtools.Division(fused_value)
                    division_list[-1] = fused_value
                else:
                    division_list.append(remainder)
            else:
                raise ValueError((self.remainder, remainder))
            total_duration = durationtools.Duration(sum(division_list))
            pair = total_duration, input_duration
            assert total_duration == input_duration, pair
            division_lists.append(division_list)
        for _ in division_lists:
            assert isinstance(_, list), repr(_)
        return division_lists
Ejemplo n.º 23
0
    def __call__(self, divisions=None):
        r'''Calls fuse-by-counts division callback.

        ..  container:: example

            **Example 1.** Returns divisions unfused:

            ::

                >>> division_maker = makertools.DivisionMaker()
                >>> division_maker = division_maker.fuse_by_counts()

            ::

                >>> input_divisions = [(2, 8), (2, 8), (4, 8), (4, 8), (2, 4)]
                >>> divisions = division_maker(input_divisions)
                >>> divisions
                [Division(2, 8), Division(2, 8), Division(4, 8), Division(4, 8), Division(2, 4)]

            ::

                >>> rhythm_maker = rhythmmakertools.NoteRhythmMaker()
                >>> music = rhythm_maker(divisions)
                >>> lilypond_file = rhythmmakertools.make_lilypond_file(
                ...     music,
                ...     divisions,
                ...     time_signatures=input_divisions,
                ...     )
                >>> show(lilypond_file) # doctest: +SKIP

            ..  doctest::

                >>> staff = rhythm_maker._get_rhythmic_staff(lilypond_file)
                >>> f(staff)
                \new RhythmicStaff {
                    {
                        \time 2/8
                        c'4
                    }
                    {
                        c'4
                    }
                    {
                        \time 4/8
                        c'2
                    }
                    {
                        c'2
                    }
                    {
                        \time 2/4
                        c'2
                    }
                }

        ..  container:: example

            **Example 2.** Fuses divisions two at a time:

            ::

                >>> division_maker = makertools.DivisionMaker()
                >>> division_maker = division_maker.fuse_by_counts(
                ...     counts=[2],
                ...     )

            ::

                >>> input_divisions = [(2, 8), (2, 8), (4, 8), (4, 8), (2, 4)]
                >>> divisions = division_maker(input_divisions)
                >>> divisions
                [Division(4, 8), Division(8, 8), Division(2, 4)]

            ::

                >>> rhythm_maker = rhythmmakertools.NoteRhythmMaker()
                >>> music = rhythm_maker(divisions)
                >>> lilypond_file = rhythmmakertools.make_lilypond_file(
                ...     music,
                ...     divisions,
                ...     time_signatures=input_divisions,
                ...     )
                >>> show(lilypond_file) # doctest: +SKIP

            ..  doctest::

                >>> staff = rhythm_maker._get_rhythmic_staff(lilypond_file)
                >>> f(staff)
                \new RhythmicStaff {
                    c'2
                    c'1
                    c'2
                }

        ..  container:: example

            **Example 3a.** Fuses divisions two at a time.
            Then splits fused divisions by ``3/16`` durations.

            Remainders to the right:
            
            ::

                >>> division_maker = makertools.DivisionMaker()
                >>> division_maker = division_maker.fuse_by_counts(
                ...     counts=[2],
                ...     )
                >>> division_maker = division_maker.split_by_durations(
                ...     durations=[Duration(3, 16)],
                ...     remainder=Right,
                ...     )

            ::

                >>> input_divisions = [(2, 8), (2, 8), (4, 8), (4, 8), (2, 4)]
                >>> division_lists = division_maker(input_divisions)
                >>> for division_list in division_lists:
                ...     division_list
                [Division(3, 16), Division(3, 16), Division(1, 8)]
                [Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16), Division(1, 16)]
                [Division(3, 16), Division(3, 16), Division(1, 8)]

            ::

                >>> rhythm_maker = rhythmmakertools.NoteRhythmMaker()
                >>> divisions = sequencetools.flatten_sequence(division_lists)
                >>> music = rhythm_maker(divisions)
                >>> lilypond_file = rhythmmakertools.make_lilypond_file(
                ...     music,
                ...     divisions,
                ...     time_signatures=input_divisions,
                ...     )
                >>> show(lilypond_file) # doctest: +SKIP

            ..  doctest::

                >>> staff = rhythm_maker._get_rhythmic_staff(lilypond_file)
                >>> f(staff)
                \new RhythmicStaff {
                    c'8.
                    c'8.
                    c'8
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                    c'16
                    c'8.
                    c'8.
                    c'8
                }

            **Example 3b.** Remainders to the left:
            
            ::

                >>> division_maker = makertools.DivisionMaker()
                >>> division_maker = division_maker.fuse_by_counts(
                ...     counts=[2],
                ...     )
                >>> division_maker = division_maker.split_by_durations(
                ...     durations=[Duration(3, 16)],
                ...     remainder=Left,
                ...     )

            ::

                >>> input_divisions = [(2, 8), (2, 8), (4, 8), (4, 8), (2, 4)]
                >>> division_lists = division_maker(input_divisions)
                >>> for division_list in division_lists:
                ...     division_list
                [Division(1, 8), Division(3, 16), Division(3, 16)]
                [Division(1, 16), Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16)]
                [Division(1, 8), Division(3, 16), Division(3, 16)]

            ::

                >>> rhythm_maker = rhythmmakertools.NoteRhythmMaker()
                >>> divisions = sequencetools.flatten_sequence(division_lists)
                >>> music = rhythm_maker(divisions)
                >>> lilypond_file = rhythmmakertools.make_lilypond_file(
                ...     music,
                ...     divisions,
                ...     time_signatures=input_divisions,
                ...     )
                >>> show(lilypond_file) # doctest: +SKIP

            ..  doctest::

                >>> staff = rhythm_maker._get_rhythmic_staff(lilypond_file)
                >>> f(staff)
                \new RhythmicStaff {
                    c'8
                    c'8.
                    c'8.
                    c'16
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                    c'8
                    c'8.
                    c'8.
                }

        ..  container:: example

            **Example 4.** Fuses all divisions:

            ::

                >>> division_maker = makertools.DivisionMaker()
                >>> division_maker = division_maker.fuse_by_counts(
                ...     counts=mathtools.Infinity,
                ...     )

            ::

                >>> input_divisions = [(2, 8), (2, 8), (4, 8), (4, 8), (2, 4)]
                >>> divisions = division_maker(input_divisions)
                >>> divisions
                [Division(16, 8)]

            ::

                >>> rhythm_maker = rhythmmakertools.NoteRhythmMaker()
                >>> music = rhythm_maker(divisions)
                >>> lilypond_file = rhythmmakertools.make_lilypond_file(
                ...     music,
                ...     divisions,
                ...     time_signatures=input_divisions,
                ...     )
                >>> show(lilypond_file) # doctest: +SKIP

            ..  doctest::

                >>> staff = rhythm_maker._get_rhythmic_staff(lilypond_file)
                >>> f(staff)
                \new RhythmicStaff {
                    c'\breve
                }

        ..  container:: example

            **Example 5a.** Fuses all divisions. Then splits fused divisions
            by ``3/8`` durations:

            Remainder at right:

            ::

                >>> division_maker = makertools.DivisionMaker()
                >>> division_maker = division_maker.fuse_by_counts(
                ...     counts=mathtools.Infinity,
                ...     )
                >>> division_maker = division_maker.split_by_durations(
                ...     durations=[Duration(3, 16)],
                ...     remainder=Right,
                ...     )

            ::

                >>> input_divisions = [(2, 8), (2, 8), (4, 8), (4, 8), (2, 4)]
                >>> division_lists = division_maker(input_divisions)
                >>> for division_list in division_lists:
                ...     division_list
                [Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16), Division(1, 8)]

            ::

                >>> rhythm_maker = rhythmmakertools.NoteRhythmMaker()
                >>> divisions = sequencetools.flatten_sequence(division_lists)
                >>> music = rhythm_maker(divisions)
                >>> lilypond_file = rhythmmakertools.make_lilypond_file(
                ...     music,
                ...     divisions,
                ...     time_signatures=input_divisions,
                ...     )
                >>> show(lilypond_file) # doctest: +SKIP

            ..  doctest::

                >>> staff = rhythm_maker._get_rhythmic_staff(lilypond_file)
                >>> f(staff)
                \new RhythmicStaff {
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                    c'8
                }

            **Example 5b.** Remainder at left:

            ::

                >>> division_maker = makertools.DivisionMaker()
                >>> division_maker = division_maker.fuse_by_counts(
                ...     counts=mathtools.Infinity,
                ...     )
                >>> division_maker = division_maker.split_by_durations(
                ...     durations=[Duration(3, 16)],
                ...     remainder=Left,
                ...     )

            ::

                >>> input_divisions = [(2, 8), (2, 8), (4, 8), (4, 8), (2, 4)]
                >>> division_lists = division_maker(input_divisions)
                >>> for division_list in division_lists:
                ...     division_list
                [Division(1, 8), Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16), Division(3, 16)]

            ::

                >>> rhythm_maker = rhythmmakertools.NoteRhythmMaker()
                >>> divisions = sequencetools.flatten_sequence(division_lists)
                >>> music = rhythm_maker(divisions)
                >>> lilypond_file = rhythmmakertools.make_lilypond_file(
                ...     music,
                ...     divisions,
                ...     time_signatures=input_divisions,
                ...     )
                >>> show(lilypond_file) # doctest: +SKIP

            ..  doctest::

                >>> staff = rhythm_maker._get_rhythmic_staff(lilypond_file)
                >>> f(staff)
                \new RhythmicStaff {
                    c'8
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                    c'8.
                }

        ..  container:: example

            **Example 6.** Empty input:

            ::

                >>> input_divisions = []
                >>> division_lists = division_maker(input_divisions)
                >>> for division_list in division_lists:
                ...     division_list

        Returns list of division lists.
        '''
        divisions = divisions or ()
        divisions = self._coerce_divisions(divisions)
        if not divisions:
            pass
        elif (self.counts == mathtools.Infinity or 
            self.counts == mathtools.Infinity()):
            divisions = [sum(divisions)]
        elif self.counts:
            parts = sequencetools.partition_sequence_by_counts(
                divisions,
                self.counts,
                cyclic=self.cyclic,
                overhang=True,
                )
            divisions = [sum(_) for _ in parts]
        divisions = [durationtools.Division(_) for _ in divisions]
        if self.secondary_division_maker is None:
            return divisions
        division_lists = []
        for division in divisions:
            if self.secondary_division_maker is not None:
                division_list = self.secondary_division_maker([division])[0]
            else:
                division_list = [division]
            division_list = [durationtools.Division(_) for _ in division_list]
            division_lists.append(division_list)
        return division_lists
    def __call__(self, divisions=None):
        r'''Calls rounded ratio division maker on `divisions`.

        ..  container:: example

            **Example 1.** Calls maker on nonempty input:

            ::

                >>> maker = makertools.SplitByRoundedRatiosDivisionCallback(
                ...     ratios=[mathtools.Ratio([1, 1])],
                ...     )
                >>> lists = maker([(7, 4), (6, 4)])
                >>> for list_ in lists:
                ...     list_
                [Division((4, 4)), Division((3, 4))]
                [Division((3, 4)), Division((3, 4))]

            Returns list of division lists.

        ..  container:: example

            **Example 2.** Calls maker on empty input:

            ::

                >>> maker = makertools.SplitByRoundedRatiosDivisionCallback(
                ...     ratios=[mathtools.Ratio([1, 1])],
                ...     )
                >>> maker([])
                []

            Returns empty list.

        ..  container:: example

            **Example 3.** Works with start offset:

            ::

                >>> maker = makertools.SplitByRoundedRatiosDivisionCallback(
                ...     ratios=[mathtools.Ratio([1, 1])],
                ...     )

            ::

                >>> divisions = [(7, 4), (6, 4)]
                >>> divisions = [durationtools.Division(_) for _ in divisions]
                >>> divisions[0]._start_offset = Offset(1, 4)
                >>> divisions
                [Division((7, 4), start_offset=Offset(1, 4)), Division((6, 4))]

            ::

                >>> division_lists = maker(divisions)
                >>> len(division_lists)
                2

            ::

                >>> for division in division_lists[0]:
                ...     division
                Division((4, 4), start_offset=Offset(1, 4))
                Division((3, 4), start_offset=Offset(5, 4))

            ::

                >>> for division in division_lists[1]:
                ...     division
                Division((3, 4), start_offset=Offset(2, 1))
                Division((3, 4), start_offset=Offset(11, 4))

        Returns possibly empty list of division lists.
        '''
        from experimental import makertools
        divisions = divisions or []
        if not divisions:
            return []
        divisions, start_offset = makertools.DivisionMaker._to_divisions(
            divisions)
        start_offset = divisions[0].start_offset
        division_lists = []
        ratios = self._get_ratios()
        for i, division in enumerate(divisions):
            ratio = ratios[i]
            numerators = mathtools.partition_integer_by_ratio(
                division.numerator,
                ratio,
                )
            division_list = [
                durationtools.Division((numerator, division.denominator))
                for numerator in numerators
                ]
            division_lists.append(division_list)
        division_lists, start_offset = makertools.DivisionMaker._to_divisions(
            division_lists,
            start_offset=start_offset,
            )
        return division_lists
Ejemplo n.º 25
0
    def __call__(self, divisions=None):
        r'''Calls division-maker on `divisions`.

        ..  container:: example

            Calls division-maker on division with no remainder:

            ::

                >>> maker = makertools.DivisionMaker(
                ...     cyclic=True,
                ...     pattern=[(1, 4)],
                ...     )
                >>> lists = maker([(3, 4)])
                >>> for list_ in lists:
                ...     list_
                [Division(1, 4), Division(1, 4), Division(1, 4)]

        ..  container:: example

            Calls division-maker cyclically on each division.
            Positions remainders to the right of each output list:

            ::

                >>> maker = makertools.DivisionMaker(
                ...     pattern=[(1, 4)],
                ...     )
                >>> lists = maker([(7, 8)])
                >>> for list_ in lists:
                ...     list_ 
                [Division(1, 4), Division(1, 4), Division(1, 4), Division(1, 8)]

            Positions remainder at right of output because divison-maker
            `remainder` defaults to right.

        ..  container:: example

            Calls division-maker with pattern set to none:

            ::

                >>> maker = makertools.DivisionMaker()
                >>> lists = maker([(6, 32)])
                >>> for list_ in lists:
                ...     list_
                [Division(6, 32)]

            Returns input division unchanged.

        ..  container:: example

            Calls division-maker on nothing:

            ::

                >>> maker = makertools.DivisionMaker(pattern=[(1, 4)])
                >>> maker()
                []

            Returns empty list.

        ..  container:: example

            Call division-maker on multiple divisions:

            ::

                >>> maker = makertools.DivisionMaker(
                ...     cyclic=True,
                ...     pattern=[(1, 4)],
                ...     )
                >>> lists = maker([(2, 4), (3, 4)])
                >>> for list_ in lists:
                ...     list_
                [Division(1, 4), Division(1, 4)]
                [Division(1, 4), Division(1, 4), Division(1, 4)]

        Returns possibly empty list of division lists.
        '''
        divisions = divisions or []
        if not divisions:
            return []
        division_lists = []
        for i, division in enumerate(divisions):
            input_division = durationtools.Division(division)
            input_duration = durationtools.Duration(input_division)
            assert 0 < input_division, repr(input_division)
            if not self.pattern:
                division_list = [input_division]
                division_lists.append(division_list)
                continue
            division_list = list(self.pattern)
            pattern_rotation_index = self.pattern_rotation_index or 0
            pattern_rotation_index *= i
            division_list = sequencetools.rotate_sequence(
                division_list,
                pattern_rotation_index,
            )
            if self.cyclic:
                division_list = sequencetools.repeat_sequence_to_weight(
                    division_list,
                    input_division,
                    allow_total=Less,
                )
            total_duration = durationtools.Duration(sum(division_list))
            if total_duration == input_duration:
                division_lists.append(division_list)
                continue
            if self.remainder is None:
                message = 'can not fill {} from {} exactly.'
                message = message.format(input_division, self.pattern)
                raise Exception(message)
            remainder = input_division - total_duration
            remainder = durationtools.Duration(remainder)
            remainder = durationtools.Division(remainder)
            if self.remainder == Left:
                if self.remainder_fuse_threshold is None:
                    division_list.insert(0, remainder)
                elif remainder <= self.remainder_fuse_threshold:
                    #division_list[0] += remainder
                    fused_value = division_list[0] + remainder
                    fused_value = durationtools.Division(fused_value)
                    division_list[0] = fused_value
                else:
                    division_list.insert(0, remainder)
            elif self.remainder == Right:
                if self.remainder_fuse_threshold is None:
                    division_list.append(remainder)
                elif remainder <= self.remainder_fuse_threshold:
                    #division_list[-1] += remainder
                    fused_value = division_list[-1] + remainder
                    fused_value = durationtools.Division(fused_value)
                    division_list[-1] = fused_value
                else:
                    division_list.append(remainder)
            else:
                raise ValueError((self.remainder, remainder))
            total_duration = durationtools.Duration(sum(division_list))
            pair = total_duration, input_duration
            assert total_duration == input_duration, pair
            division_lists.append(division_list)
        return division_lists