def repeat_to_duration(self, duration):
        r'''Repeat start-positioned division payload expression to `duration`.

        ::

            >>> payload = [(6, 8), (6, 8), (3, 4)]
            >>> expression = musicexpressiontools.StartPositionedDivisionPayloadExpression(
            ...     payload, Offset(0))

        ::

            >>> result = expression.repeat_to_duration(Duration(13, 4))

        ::

            >>> print(format(result))
            musicexpressiontools.StartPositionedDivisionPayloadExpression(
                payload=musicexpressiontools.DivisionList(
                    [
                        durationtools.Division(6, 8),
                        durationtools.Division(6, 8),
                        durationtools.Division(3, 4),
                        durationtools.Division(6, 8),
                        durationtools.Division(2, 8),
                        ],
                    start_offset=durationtools.Offset(0, 1),
                    ),
                start_offset=durationtools.Offset(0, 1),
                )

        Returns newly constructed start-positioned division payload expression.
        '''
        divisions = sequencetools.repeat_sequence_to_weight(self.payload, duration)
        result = type(self)(payload=divisions, voice_name=self.voice_name, start_offset=self.start_offset)
        return result
    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
Esempio n. 3
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
    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
Esempio n. 5
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
Esempio n. 6
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
    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 = [musicexpressiontools.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
Esempio n. 8
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
Esempio n. 9
0
    def repeat_to_duration(self, duration):
        r'''Repeat start-positioned division payload expression to `duration`.

        ::

            >>> payload = [(6, 8), (6, 8), (3, 4)]
            >>> expression = musicexpressiontools.StartPositionedDivisionPayloadExpression(
            ...     payload, Offset(0))

        ::

            >>> result = expression.repeat_to_duration(Duration(13, 4))

        ::

            >>> print(format(result))
            musicexpressiontools.StartPositionedDivisionPayloadExpression(
                payload=musicexpressiontools.DivisionList(
                    [
                        durationtools.Division(6, 8),
                        durationtools.Division(6, 8),
                        durationtools.Division(3, 4),
                        durationtools.Division(6, 8),
                        durationtools.Division(2, 8),
                        ],
                    start_offset=durationtools.Offset(0, 1),
                    ),
                start_offset=durationtools.Offset(0, 1),
                )

        Returns newly constructed start-positioned division payload expression.
        '''
        divisions = sequencetools.repeat_sequence_to_weight(
            self.payload, duration)
        result = type(self)(payload=divisions,
                            voice_name=self.voice_name,
                            start_offset=self.start_offset)
        return result
Esempio n. 10
0
def split_sequence(sequence, weights, cyclic=False, overhang=False):
    """Splits sequence by weights.

    ..  container:: example

        **Example 1.** Split sequence cyclically by weights with overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     (10, -10, 10, -10),
            ...     (3, 15, 3),
            ...     cyclic=True,
            ...     overhang=True,
            ...     )
            [(3,), (7, -8), (-2, 1), (3,), (6, -9), (-1,)]

    ..  container:: example

        **Example 2.** Split sequence cyclically by weights without overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     (10, -10, 10, -10),
            ...     (3, 15, 3),
            ...     cyclic=True,
            ...     overhang=False,
            ...     )
            [(3,), (7, -8), (-2, 1), (3,), (6, -9)]

    ..  container:: example

        **Example 3.** Split sequence once by weights with overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     (10, -10, 10, -10),
            ...     (3, 15, 3),
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [(3,), (7, -8), (-2, 1), (9, -10)]

    ..  container:: example

        **Example 4.** Split sequence once by weights without overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     (10, -10, 10, -10),
            ...     (3, 15, 3),
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            [(3,), (7, -8), (-2, 1)]

    Returns list of sequence types.
    """
    from abjad.tools import sequencetools

    result = []
    current_index = 0
    current_piece = []

    if cyclic:
        weights = sequencetools.repeat_sequence_to_weight(weights, mathtools.weight(sequence), allow_total=Less)

    for weight in weights:
        current_piece_weight = mathtools.weight(current_piece)
        while current_piece_weight < weight:
            current_piece.append(sequence[current_index])
            current_index += 1
            current_piece_weight = mathtools.weight(current_piece)
        if current_piece_weight == weight:
            current_piece = type(sequence)(current_piece)
            result.append(current_piece)
            current_piece = []
        elif weight < current_piece_weight:
            overage = current_piece_weight - weight
            current_last_element = current_piece.pop(-1)
            needed = abs(current_last_element) - overage
            needed *= mathtools.sign(current_last_element)
            current_piece.append(needed)
            current_piece = type(sequence)(current_piece)
            result.append(current_piece)
            overage *= mathtools.sign(current_last_element)
            current_piece = [overage]

    if overhang:
        last_piece = current_piece
        last_piece.extend(sequence[current_index:])
        if last_piece:
            last_piece = type(sequence)(last_piece)
            result.append(last_piece)

    return result
Esempio n. 11
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
Esempio n. 12
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
    def __call__(self, divisions=None):
        r'''Calls division-maker on `divisions`.

        ..  container:: example

            **Example 1.** Splits divisions 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.** Splits divisions 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.

        ..  container:: example

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

            ::

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

            ::

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

            ::

                >>> division_lists = callback(divisions)
                >>> for division_list in division_lists:
                ...     division_list
                [Division((1, 4), start_offset=Offset(1, 4)), Division((1, 4), start_offset=Offset(1, 2))]
                [Division((1, 4), start_offset=Offset(3, 4)), Division((1, 4), start_offset=Offset(1, 1)), Division((1, 4), start_offset=Offset(5, 4))]

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

            ::

                >>> 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,
                ...     )

            ::

                >>> divisions = [(2, 8), (2, 8), (4, 8), (4, 8), (2, 4)]
                >>> divisions = [durationtools.Division(_) for _ in divisions]
                >>> divisions[0]._start_offset = Offset(1, 4)

            ::

                >>> division_lists = division_maker(divisions)
                >>> len(division_lists)
                1

            ::

                >>> for division in division_lists[0]:
                ...     division
                Division((1, 8), start_offset=Offset(1, 4))
                Division((3, 16), start_offset=Offset(3, 8))
                Division((3, 16), start_offset=Offset(9, 16))
                Division((3, 16), start_offset=Offset(3, 4))
                Division((3, 16), start_offset=Offset(15, 16))
                Division((3, 16), start_offset=Offset(9, 8))
                Division((3, 16), start_offset=Offset(21, 16))
                Division((3, 16), start_offset=Offset(3, 2))
                Division((3, 16), start_offset=Offset(27, 16))
                Division((3, 16), start_offset=Offset(15, 8))
                Division((3, 16), start_offset=Offset(33, 16))

        Returns possibly empty list of division lists.
        '''
        from experimental import makertools
        divisions = divisions or []
        if not divisions:
            return divisions
        divisions, start_offset = makertools.DivisionMaker._to_divisions(
            divisions)
        start_offset = divisions[0].start_offset
        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.Duration(multiplier * _)
                    for _ in 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, durations)
                raise Exception(message)
            remainder = input_division - total_duration
            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(_)
        division_lists, start_offset = makertools.DivisionMaker._to_divisions(
            division_lists,
            start_offset
            )
        return division_lists
Esempio n. 14
0
 def _split(
     self,
     durations,
     cyclic=False,
     fracture_spanners=False,
     tie_split_notes=True,
     use_messiaen_style_ties=False,
     ):
     from abjad.tools import pitchtools
     from abjad.tools import selectiontools
     from abjad.tools import scoretools
     from abjad.tools import spannertools
     durations = [durationtools.Duration(x) for x in durations]
     if cyclic:
         durations = sequencetools.repeat_sequence_to_weight(
             durations, self._get_duration())
     durations = [durationtools.Duration(x) for x in durations]
     if sum(durations) < self._get_duration():
         last_duration = self._get_duration() - sum(durations)
         durations.append(last_duration)
     sequencetools.truncate_sequence(
         durations,
         weight=self._get_duration(),
         )
     result = []
     leaf_prolation = self._get_parentage(include_self=False).prolation
     timespan = self._get_timespan()
     start_offset = timespan.start_offset
     for duration in durations:
         new_leaf = copy.copy(self)
         preprolated_duration = duration / leaf_prolation
         shard = new_leaf._set_duration(
             preprolated_duration,
             use_messiaen_style_ties=use_messiaen_style_ties,
             )
         for x in shard:
             if isinstance(x, scoretools.Leaf):
                 x_duration = x.written_duration * leaf_prolation
             else:
                 x_duration = x.multiplied_duration * leaf_prolation
             stop_offset = x_duration + start_offset
             x._start_offset = start_offset
             x._stop_offset = stop_offset
             x._timespan = timespantools.Timespan(
                 start_offset=start_offset,
                 stop_offset=stop_offset,
                 )
             start_offset = stop_offset
         shard = [x._get_parentage().root for x in shard]
         result.append(shard)
     flattened_result = sequencetools.flatten_sequence(result)
     flattened_result = selectiontools.SliceSelection(flattened_result)
     prototype = (spannertools.Tie,)
     parentage = self._get_parentage()
     if parentage._get_spanners(prototype=prototype):
         selection = select(flattened_result)
         for component in selection:
             # TODO: make top-level detach() work here
             for spanner in component._get_spanners(prototype):
                 spanner._sever_all_components()
             #detach(prototype, component)
     # replace leaf with flattened result
     selection = selectiontools.SliceSelection(self)
     parent, start, stop = selection._get_parent_and_start_stop_indices()
     if parent:
         parent.__setitem__(slice(start, stop + 1), flattened_result)
     else:
         selection._give_dominant_spanners(flattened_result)
         selection._withdraw_from_crossing_spanners()
     # fracture spanners
     if fracture_spanners:
         first_shard = result[0]
         for spanner in first_shard[-1]._get_spanners():
             index = spanner._index(first_shard[-1])
             spanner._fracture(index, direction=Right)
         last_shard = result[-1]
         for spanner in last_shard[0]._get_spanners():
             index = spanner._index(last_shard[0])
             spanner._fracture(index, direction=Left)
         for middle_shard in result[1:-1]:
             for spanner in middle_shard[0]._get_spanners():
                 index = spanner._index(middle_shard[0])
                 spanner._fracture(index, direction=Left)
             for spanner in middle_shard[-1]._get_spanners():
                 index = spanner._index(middle_shard[-1])
                 spanner._fracture(index, direction=Right)
     # adjust first leaf
     first_leaf = flattened_result[0]
     self._detach_grace_containers(kind='after')
     # adjust any middle leaves
     for middle_leaf in flattened_result[1:-1]:
         middle_leaf._detach_grace_containers(kind='grace')
         self._detach_grace_containers(kind='after')
         detach(object, middle_leaf)
     # adjust last leaf
     last_leaf = flattened_result[-1]
     last_leaf._detach_grace_containers(kind='grace')
     detach(object, last_leaf)
     # tie split notes, rests and chords as specified
     if pitchtools.Pitch.is_pitch_carrier(self) and tie_split_notes:
         flattened_result_leaves = iterate(flattened_result).by_class(
             scoretools.Leaf)
         # TODO: implement SliceSelection._attach_tie_spanner_to_leaves()
         for leaf_pair in sequencetools.iterate_sequence_nwise(
             flattened_result_leaves):
             selection = selectiontools.ContiguousSelection(leaf_pair)
             selection._attach_tie_spanner_to_leaf_pair(
                 use_messiaen_style_ties=use_messiaen_style_ties,
                 )
     # return result
     return result
def partition_sequence_by_counts(
    sequence,
    counts,
    cyclic=False,
    overhang=False,
    copy_elements=False,
    ):
    r'''Partitions sequence by counts.

    ..  container:: example

        **Example 1a.** Partition sequence once by counts without overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            [[0, 1, 2]]

    ..  container:: example

        **Example 1b.** Partition sequence once by counts without overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6]]

    ..  container:: example

        **Example 2a.** Partition sequence cyclically by counts without
        overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=True,
            ...     overhang=False,
            ...     )
            [[0, 1, 2], [3, 4, 5], [6, 7, 8]]

    ..  container:: example

        **Example 2b.** Partition sequence cyclically by counts without
        overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=True,
            ...     overhang=False,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10], [11, 12, 13]]

    ..  container:: example

        **Example 3a.** Partition sequence once by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [[0, 1, 2], [3, 4, 5, 6, 7, 8, 9]]

    ..  container:: example

        **Example 3b.** Partition sequence once by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14, 15]]

    ..  container:: example

        **Example 4a.** Partition sequence cyclically by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=True,
            ...     overhang=True,
            ...     )
            [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

    ..  container:: example

        **Example 4b.** Partition sequence cyclically by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=True,
            ...     overhang=True,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10], [11, 12, 13], [14, 15]]

    Returns list of sequence objects.
    '''
    from abjad.tools import sequencetools

    result = []

    if cyclic:
        if overhang:
            counts = sequencetools.repeat_sequence_to_weight(
                counts, len(sequence))
        else:
            counts = sequencetools.repeat_sequence_to_weight(
                counts, len(sequence), allow_total=Less)
    elif overhang:
        weight_counts = mathtools.weight(counts)
        len_sequence = len(sequence)
        if weight_counts < len_sequence:
            counts = list(counts)
            counts.append(len(sequence) - weight_counts)

    for start, stop in mathtools.cumulative_sums_pairwise(counts):
        result.append(type(sequence)(sequence[start:stop]))

    return result
Esempio n. 16
0
def split_sequence(sequence, weights, cyclic=False, overhang=False):
    '''Splits sequence by weights.

    ..  container:: example

        **Example 1.** Split sequence cyclically by weights with overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     (10, -10, 10, -10),
            ...     (3, 15, 3),
            ...     cyclic=True,
            ...     overhang=True,
            ...     )
            [(3,), (7, -8), (-2, 1), (3,), (6, -9), (-1,)]

    ..  container:: example

        **Example 2.** Split sequence cyclically by weights without overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     (10, -10, 10, -10),
            ...     (3, 15, 3),
            ...     cyclic=True,
            ...     overhang=False,
            ...     )
            [(3,), (7, -8), (-2, 1), (3,), (6, -9)]

    ..  container:: example

        **Example 3.** Split sequence once by weights with overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     (10, -10, 10, -10),
            ...     (3, 15, 3),
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [(3,), (7, -8), (-2, 1), (9, -10)]

    ..  container:: example

        **Example 4.** Split sequence once by weights without overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     (10, -10, 10, -10),
            ...     (3, 15, 3),
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            [(3,), (7, -8), (-2, 1)]

    Returns list of sequence types.
    '''
    from abjad.tools import sequencetools

    result = []
    current_index = 0
    current_piece = []

    if cyclic:
        weights = sequencetools.repeat_sequence_to_weight(
            weights, mathtools.weight(sequence), allow_total=Less)

    for weight in weights:
        current_piece_weight = mathtools.weight(current_piece)
        while current_piece_weight < weight:
            current_piece.append(sequence[current_index])
            current_index += 1
            current_piece_weight = mathtools.weight(current_piece)
        if current_piece_weight == weight:
            current_piece = type(sequence)(current_piece)
            result.append(current_piece)
            current_piece = []
        elif weight < current_piece_weight:
            overage = current_piece_weight - weight
            current_last_element = current_piece.pop(-1)
            needed = abs(current_last_element) - overage
            needed *= mathtools.sign(current_last_element)
            current_piece.append(needed)
            current_piece = type(sequence)(current_piece)
            result.append(current_piece)
            overage *= mathtools.sign(current_last_element)
            current_piece = [overage]

    if overhang:
        last_piece = current_piece
        last_piece.extend(sequence[current_index:])
        if last_piece:
            last_piece = type(sequence)(last_piece)
            result.append(last_piece)

    return result
Esempio n. 17
0
File: Leaf.py Progetto: ajyoon/abjad
 def _split(
     self,
     durations,
     cyclic=False,
     fracture_spanners=False,
     tie_split_notes=True,
     use_messiaen_style_ties=False,
     ):
     from abjad.tools import pitchtools
     from abjad.tools import selectiontools
     from abjad.tools import scoretools
     from abjad.tools import spannertools
     durations = [durationtools.Duration(x) for x in durations]
     if cyclic:
         durations = sequencetools.repeat_sequence_to_weight(
             durations, self._get_duration())
     durations = [durationtools.Duration(x) for x in durations]
     if sum(durations) < self._get_duration():
         last_duration = self._get_duration() - sum(durations)
         durations.append(last_duration)
     sequencetools.truncate_sequence(
         durations,
         weight=self._get_duration(),
         )
     result = []
     leaf_prolation = self._get_parentage(include_self=False).prolation
     timespan = self._get_timespan()
     start_offset = timespan.start_offset
     for duration in durations:
         new_leaf = copy.copy(self)
         preprolated_duration = duration / leaf_prolation
         shard = new_leaf._set_duration(
             preprolated_duration,
             use_messiaen_style_ties=use_messiaen_style_ties,
             )
         for x in shard:
             if isinstance(x, scoretools.Leaf):
                 x_duration = x.written_duration * leaf_prolation
             else:
                 x_duration = x.multiplied_duration * leaf_prolation
             stop_offset = x_duration + start_offset
             x._start_offset = start_offset
             x._stop_offset = stop_offset
             x._timespan = timespantools.Timespan(
                 start_offset=start_offset,
                 stop_offset=stop_offset,
                 )
             start_offset = stop_offset
         shard = [x._get_parentage().root for x in shard]
         result.append(shard)
     flattened_result = sequencetools.flatten_sequence(result)
     flattened_result = selectiontools.Selection(flattened_result)
     prototype = (spannertools.Tie,)
     parentage = self._get_parentage()
     if parentage._get_spanners(prototype=prototype):
         selection = select(flattened_result)
         for component in selection:
             # TODO: make top-level detach() work here
             for spanner in component._get_spanners(prototype):
                 spanner._sever_all_components()
             #detach(prototype, component)
     # replace leaf with flattened result
     selection = selectiontools.Selection(self)
     parent, start, stop = selection._get_parent_and_start_stop_indices()
     if parent:
         parent.__setitem__(slice(start, stop + 1), flattened_result)
     else:
         selection._give_dominant_spanners(flattened_result)
         selection._withdraw_from_crossing_spanners()
     # fracture spanners
     if fracture_spanners:
         first_shard = result[0]
         for spanner in first_shard[-1]._get_spanners():
             index = spanner._index(first_shard[-1])
             spanner._fracture(index, direction=Right)
         last_shard = result[-1]
         for spanner in last_shard[0]._get_spanners():
             index = spanner._index(last_shard[0])
             spanner._fracture(index, direction=Left)
         for middle_shard in result[1:-1]:
             for spanner in middle_shard[0]._get_spanners():
                 index = spanner._index(middle_shard[0])
                 spanner._fracture(index, direction=Left)
             for spanner in middle_shard[-1]._get_spanners():
                 index = spanner._index(middle_shard[-1])
                 spanner._fracture(index, direction=Right)
     # adjust first leaf
     first_leaf = flattened_result[0]
     self._detach_grace_containers(kind='after')
     # adjust any middle leaves
     for middle_leaf in flattened_result[1:-1]:
         middle_leaf._detach_grace_containers(kind='grace')
         self._detach_grace_containers(kind='after')
         detach(object, middle_leaf)
     # adjust last leaf
     last_leaf = flattened_result[-1]
     last_leaf._detach_grace_containers(kind='grace')
     detach(object, last_leaf)
     # tie split notes, rests and chords as specified
     if pitchtools.Pitch.is_pitch_carrier(self) and tie_split_notes:
         flattened_result_leaves = iterate(flattened_result).by_class(
             scoretools.Leaf)
         # TODO: implement Selection._attach_tie_spanner_to_leaves()
         for leaf_pair in sequencetools.iterate_sequence_nwise(
             flattened_result_leaves):
             selection = selectiontools.Selection(leaf_pair)
             selection._attach_tie_spanner_to_leaf_pair(
                 use_messiaen_style_ties=use_messiaen_style_ties,
                 )
     # return result
     return result
Esempio n. 18
0
def split_sequence(sequence, weights, cyclic=False, overhang=False):
    '''Splits sequence by weights.

    ..  container:: example

        **Example 1.** Splits sequence cyclically by weights with overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     (10, -10, 10, -10),
            ...     (3, 15, 3),
            ...     cyclic=True,
            ...     overhang=True,
            ...     )
            ((3,), (7, -8), (-2, 1), (3,), (6, -9), (-1,))

    ..  container:: example

        **Example 2.** Splits sequence cyclically by weights without overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     (10, -10, 10, -10),
            ...     (3, 15, 3),
            ...     cyclic=True,
            ...     overhang=False,
            ...     )
            ((3,), (7, -8), (-2, 1), (3,), (6, -9))

    ..  container:: example

        **Example 3.** Splits sequence once by weights with overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     (10, -10, 10, -10),
            ...     (3, 15, 3),
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            ((3,), (7, -8), (-2, 1), (9, -10))

    ..  container:: example

        **Example 4.** Splits sequence once by weights without overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     (10, -10, 10, -10),
            ...     (3, 15, 3),
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            ((3,), (7, -8), (-2, 1))

    ..  container:: example

        **Example 5.** Splits list once by weights without overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     [10, -10, 10, -10],
            ...     (3, 15, 3),
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            [[3], [7, -8], [-2, 1]]

    Returns new object of `sequence` type with elements also of `sequence`
    type.
    '''
    from abjad.tools import sequencetools

    if not isinstance(sequence, collections.Sequence):
        message = 'must by sequence {!r}.'
        message = message.format(sequence)
        raise Exception(message)

    sequence_type = type(sequence)

    result = []
    current_index = 0
    current_piece = []

    if cyclic:
        weights = sequencetools.repeat_sequence_to_weight(
            weights,
            mathtools.weight(sequence),
            allow_total=Less,
            )

    for weight in weights:
        current_piece_weight = mathtools.weight(current_piece)
        while current_piece_weight < weight:
            current_piece.append(sequence[current_index])
            current_index += 1
            current_piece_weight = mathtools.weight(current_piece)
        if current_piece_weight == weight:
            current_piece = type(sequence)(current_piece)
            result.append(current_piece)
            current_piece = []
        elif weight < current_piece_weight:
            overage = current_piece_weight - weight
            current_last_element = current_piece.pop(-1)
            needed = abs(current_last_element) - overage
            needed *= mathtools.sign(current_last_element)
            current_piece.append(needed)
            current_piece = type(sequence)(current_piece)
            result.append(current_piece)
            overage *= mathtools.sign(current_last_element)
            current_piece = [overage]

    if overhang:
        last_piece = current_piece
        last_piece.extend(sequence[current_index:])
        if last_piece:
            last_piece = type(sequence)(last_piece)
            result.append(last_piece)

    result = sequence_type(result)
    return result
Esempio n. 19
0
def partition_sequence_by_counts(
    sequence,
    counts,
    cyclic=False,
    overhang=False,
    copy_elements=False,
):
    r'''Partitions sequence by counts.

    ..  container:: example

        **Example 1a.** Partition sequence once by counts without overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            [[0, 1, 2]]

    ..  container:: example

        **Example 1b.** Partition sequence once by counts without overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6]]

    ..  container:: example

        **Example 2a.** Partition sequence cyclically by counts without
        overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=True,
            ...     overhang=False,
            ...     )
            [[0, 1, 2], [3, 4, 5], [6, 7, 8]]

    ..  container:: example

        **Example 2b.** Partition sequence cyclically by counts without
        overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=True,
            ...     overhang=False,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10], [11, 12, 13]]

    ..  container:: example

        **Example 3a.** Partition sequence once by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [[0, 1, 2], [3, 4, 5, 6, 7, 8, 9]]

    ..  container:: example

        **Example 3b.** Partition sequence once by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14, 15]]

    ..  container:: example

        **Example 4a.** Partition sequence cyclically by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=True,
            ...     overhang=True,
            ...     )
            [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

    ..  container:: example

        **Example 4b.** Partition sequence cyclically by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=True,
            ...     overhang=True,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10], [11, 12, 13], [14, 15]]

    Returns list of sequence objects.
    '''
    from abjad.tools import sequencetools

    if not isinstance(counts, (tuple, list)):
        message = 'must be list or tuple: {!r}.'
        message = message.format(counts)
        raise TypeError(message)

    result = []

    if cyclic:
        if overhang:
            counts = sequencetools.repeat_sequence_to_weight(
                counts,
                len(sequence),
            )
        else:
            counts = sequencetools.repeat_sequence_to_weight(
                counts,
                len(sequence),
                allow_total=Less,
            )
    elif overhang:
        weight_counts = mathtools.weight(counts)
        len_sequence = len(sequence)
        if weight_counts < len_sequence:
            counts = list(counts)
            counts.append(len(sequence) - weight_counts)

    for start, stop in mathtools.cumulative_sums_pairwise(counts):
        result.append(type(sequence)(sequence[start:stop]))

    return result
    def __call__(self, divisions=None):
        r'''Calls division-maker on `divisions`.

        ..  container:: example

            **Example 1.** NonreducedFraction 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
                [NonreducedFraction(1, 4), NonreducedFraction(1, 4), NonreducedFraction(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.** NonreducedFraction 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 
                [NonreducedFraction(1, 4), NonreducedFraction(1, 4), NonreducedFraction(1, 4), NonreducedFraction(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
                [NonreducedFraction(1, 4), NonreducedFraction(1, 4)]
                [NonreducedFraction(1, 4), NonreducedFraction(1, 4), NonreducedFraction(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
                [NonreducedFraction(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 = mathtools.NonreducedFraction(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 = [
                    mathtools.NonreducedFraction(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 = mathtools.NonreducedFraction(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 = mathtools.NonreducedFraction(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 = mathtools.NonreducedFraction(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
Esempio n. 21
0
def partition_sequence_by_counts(
    sequence,
    counts,
    cyclic=False,
    overhang=False,
    reversed_=False,
    ):
    r'''Partitions `sequence` by `counts`.

    ..  container:: example

        **Example 1.** Partitions sequence once by counts without overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            [[0, 1, 2]]

        **Example 2.** Partitions sequence once by counts without overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6]]

    ..  container:: example

        **Example 3.** Partitions sequence cyclically by counts without
        overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=True,
            ...     overhang=False,
            ...     )
            [[0, 1, 2], [3, 4, 5], [6, 7, 8]]

        **Example 4.** Partitions sequence cyclically by counts without
        overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=True,
            ...     overhang=False,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10], [11, 12, 13]]

    ..  container:: example

        **Example 5.** Partitions sequence once by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [[0, 1, 2], [3, 4, 5, 6, 7, 8, 9]]

        **Example 6.** Partitions sequence once by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14, 15]]

    ..  container:: example

        **Example 7.** Partitions sequence cyclically by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=True,
            ...     overhang=True,
            ...     )
            [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

        **Example 8.** Partitions sequence cyclically by counts with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(16)),
            ...     [4, 3],
            ...     cyclic=True,
            ...     overhang=True,
            ...     )
            [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10], [11, 12, 13], [14, 15]]

    ..  container:: example

        **Example 9.** Partitions sequence once by counts and asserts
        that sequence partitions exactly (with no overhang):

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [2, 3, 5],
            ...     cyclic=False,
            ...     overhang=Exact,
            ...     )
            [[0, 1], [2, 3, 4], [5, 6, 7, 8, 9]]

        **Example 10.** Partitions sequence cyclically by counts and asserts
        that sequence partitions exactly (with no overhang):

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [2],
            ...     cyclic=True,
            ...     overhang=Exact,
            ...     )
            [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]

    ..  container:: example

        **Example 11.** Partitions list:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     list(range(10)),
            ...     [3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [[0, 1, 2], [3, 4, 5, 6, 7, 8, 9]]

        **Example 12.** Partitions tuple:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     tuple(range(10)),
            ...     [3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            [(0, 1, 2), (3, 4, 5, 6, 7, 8, 9)]

        **Example 13.** Partitions string:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     'some text',
            ...     [3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            ['som', 'e text']

    ..  container:: example

        **Example 14.** Reverses cyclic partition with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
            ...     [3],
            ...     cyclic=True,
            ...     overhang=True,
            ...     reversed_=True,
            ...     )
            [[0], [1, 2, 3], [4, 5, 6], [7, 8, 9]]

        **Example 15.** Reverses cyclic partition without overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
            ...     [3],
            ...     cyclic=True,
            ...     overhang=False,
            ...     reversed_=True,
            ...     )
            [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

        **Example 16.** Reverses acyclic partition with overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
            ...     [3],
            ...     cyclic=False,
            ...     overhang=True,
            ...     reversed_=True,
            ...     )
            [[0, 1, 2, 3, 4, 5, 6], [7, 8, 9]]

        **Example 17.** Reverses acyclic partition without overhang:

        ::

            >>> sequencetools.partition_sequence_by_counts(
            ...     [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
            ...     [3],
            ...     cyclic=False,
            ...     overhang=False,
            ...     reversed_=True,
            ...     )
            [[7, 8, 9]]

    Returns list of objects with type equal to that of `sequence`.
    '''
    from abjad.tools import sequencetools

    if not isinstance(sequence, collections.Sequence):
        message = 'must be sequence: {!r}.'
        message = message.format(sequence)
        raise TypeError(message)
    if not isinstance(counts, collections.Iterable):
        message = 'must be iterable: {!r}.'
        message = message.format(counts)
        raise TypeError(message)

    sequence_type = type(sequence)
    if reversed_:
        sequence = reversed(sequence)    
        sequence = sequence_type(sequence)

    if overhang == Exact:
        result_with_overhang = partition_sequence_by_counts(
            sequence,
            counts,
            cyclic=cyclic,
            overhang=True,
            )
        result_without_overhang = partition_sequence_by_counts(
            sequence,
            counts,
            cyclic=cyclic,
            overhang=False,
            )
        if result_with_overhang == result_without_overhang:
            return result_without_overhang
        else:
            message = 'sequence does not partition exactly.'
            raise Exception(message)

    result = []
    if cyclic:
        if overhang:
            counts = sequencetools.repeat_sequence_to_weight(
                counts,
                len(sequence),
                )
        else:
            counts = sequencetools.repeat_sequence_to_weight(
                counts, 
                len(sequence), 
                allow_total=Less,
                )
    elif overhang:
        weight_counts = mathtools.weight(counts)
        len_sequence = len(sequence)
        if weight_counts < len_sequence:
            counts = list(counts)
            counts.append(len(sequence) - weight_counts)
    for start, stop in mathtools.cumulative_sums_pairwise(counts):
        part = sequence[start:stop]
        result.append(part)

    if reversed_:
        result_ = []
        for part in reversed(result):
            part_type = type(part)
            part = reversed(part)
            part = part_type(part)
            result_.append(part)
        result = result_

    return result
Esempio n. 22
0
def split_sequence(sequence, weights, cyclic=False, overhang=False):
    '''Splits sequence by weights.

    ..  container:: example

        **Example 1.** Splits sequence cyclically by weights with overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     (10, -10, 10, -10),
            ...     (3, 15, 3),
            ...     cyclic=True,
            ...     overhang=True,
            ...     )
            ((3,), (7, -8), (-2, 1), (3,), (6, -9), (-1,))

    ..  container:: example

        **Example 2.** Splits sequence cyclically by weights without overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     (10, -10, 10, -10),
            ...     (3, 15, 3),
            ...     cyclic=True,
            ...     overhang=False,
            ...     )
            ((3,), (7, -8), (-2, 1), (3,), (6, -9))

    ..  container:: example

        **Example 3.** Splits sequence once by weights with overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     (10, -10, 10, -10),
            ...     (3, 15, 3),
            ...     cyclic=False,
            ...     overhang=True,
            ...     )
            ((3,), (7, -8), (-2, 1), (9, -10))

    ..  container:: example

        **Example 4.** Splits sequence once by weights without overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     (10, -10, 10, -10),
            ...     (3, 15, 3),
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            ((3,), (7, -8), (-2, 1))

    ..  container:: example

        **Example 5.** Splits list once by weights without overhang:

        ::

            >>> sequencetools.split_sequence(
            ...     [10, -10, 10, -10],
            ...     (3, 15, 3),
            ...     cyclic=False,
            ...     overhang=False,
            ...     )
            [[3], [7, -8], [-2, 1]]

    Returns new object of `sequence` type with elements also of `sequence`
    type.
    '''
    from abjad.tools import sequencetools

    if not isinstance(sequence, collections.Sequence):
        message = 'must by sequence {!r}.'
        message = message.format(sequence)
        raise Exception(message)

    sequence_type = type(sequence)

    result = []
    current_index = 0
    current_piece = []

    if cyclic:
        weights = sequencetools.repeat_sequence_to_weight(
            weights,
            mathtools.weight(sequence),
            allow_total=Less,
        )

    for weight in weights:
        current_piece_weight = mathtools.weight(current_piece)
        while current_piece_weight < weight:
            current_piece.append(sequence[current_index])
            current_index += 1
            current_piece_weight = mathtools.weight(current_piece)
        if current_piece_weight == weight:
            current_piece = type(sequence)(current_piece)
            result.append(current_piece)
            current_piece = []
        elif weight < current_piece_weight:
            overage = current_piece_weight - weight
            current_last_element = current_piece.pop(-1)
            needed = abs(current_last_element) - overage
            needed *= mathtools.sign(current_last_element)
            current_piece.append(needed)
            current_piece = type(sequence)(current_piece)
            result.append(current_piece)
            overage *= mathtools.sign(current_last_element)
            current_piece = [overage]

    if overhang:
        last_piece = current_piece
        last_piece.extend(sequence[current_index:])
        if last_piece:
            last_piece = type(sequence)(last_piece)
            result.append(last_piece)

    result = sequence_type(result)
    return result