示例#1
0
def split(sequential_event: events.basic.SequentialEvent, nth_child: int,
          *durations: parameters.abc.DurationType):
    child = sequential_event[nth_child]
    difference = child.duration - sum(durations)
    assert difference >= 0
    absolute_time = sequential_event.absolute_times[nth_child]
    for duration in durations:
        absolute_time += duration
        sequential_event.split_child_at(absolute_time)
示例#2
0
 def _split_concatenated_cengkok_chain_to_cengkok_chain(
     self, concatenated_cengkok_chain: events.basic.SequentialEvent
 ) -> typing.Tuple[events.basic.SequentialEvent, ...]:
     concatenated_cengkok_chain.cut_off(0, self._added_delay_size)
     cengkok_chain = [events.basic.SequentialEvent([])]
     for index, event in enumerate(concatenated_cengkok_chain):
         cengkok_chain[-1].append(event)
         if event.is_goal and index + 1 != len(concatenated_cengkok_chain):
             cengkok_chain.append(events.basic.SequentialEvent([]))
     return cengkok_chain
示例#3
0
def delay(
    sequential_event: events.basic.SequentialEvent,
    nth: int,
    duration: parameters.abc.DurationType,
):
    previous_event_index = nth - 1
    if previous_event_index >= 0 and is_rest(
            sequential_event[previous_event_index]):
        sequential_event[previous_event_index].duration += duration
    else:
        sequential_event.insert(nth, events.music.NoteLike([], duration))
    sequential_event[nth].duration -= duration
示例#4
0
    def _prolong_notes_before_next_bar(
        self, sequential_event: events.basic.SequentialEvent
    ) -> events.basic.SequentialEvent:
        for absolute_time in self.absolute_times[1:]:
            item_index = sequential_event.get_event_index_at(absolute_time)
            responsible_event = sequential_event[item_index]
            if hasattr(responsible_event, "is_root") and responsible_event.is_root:
                previous_item = sequential_event[item_index - 1]
                if (
                    hasattr(previous_item, "pitch_or_pitches")
                    and previous_item.pitch_or_pitches
                ):
                    if not previous_item.playing_indicators.glissando.is_active:
                        if (
                            responsible_event.duration.denominator % 3 != 0
                            and previous_item.duration.denominator % 3 != 0
                        ):
                            if self.prolong_al_generator(self.prolong_al):
                                if responsible_event.duration.denominator % 3 == 0:
                                    prolong_duration = fractions.Fraction(1, 12)
                                else:
                                    prolong_duration = fractions.Fraction(1, 16)
                                if responsible_event.duration > prolong_duration:
                                    responsible_event.duration -= prolong_duration
                                    previous_item.duration += prolong_duration

        return sequential_event
示例#5
0
    def _prolong_last_beat_of_previous_bar(
        self,
        restructured_phrase_parts: typing.Tuple[structure.RestructuredPhrasePart, ...],
        sequential_event: events.basic.SequentialEvent,
    ):
        is_first = True
        for absolute_time, restructured_phrase_part in zip(
            restructured_phrase_parts.absolute_times, restructured_phrase_parts
        ):
            event_index_to_shorten = sequential_event.get_event_index_at(absolute_time)
            event_to_prolong = sequential_event[event_index_to_shorten - 1]
            event_to_shorten = sequential_event[event_index_to_shorten]
            if (
                restructured_phrase_part.bar_character
                not in (structure.END, structure.END_AND_START)
                and not is_first
                and hasattr(event_to_prolong, "pitch_or_pitches")
                and event_to_prolong.pitch_or_pitches
                and event_to_shorten.duration.denominator % 2 == 0
                and event_to_shorten.duration.denominator % 3 != 0
                and event_to_prolong.duration.denominator % 2 == 0
                and event_to_prolong.duration.denominator % 3 != 0
            ):
                if self.prolong_al_generator(self.prolong_al):
                    event_to_shorten.duration /= 2
                    event_to_prolong.duration += event_to_shorten.duration

            is_first = False

        return sequential_event
示例#6
0
def shorten(
    sequential_event: events.basic.SequentialEvent,
    nth: int,
    duration: parameters.abc.DurationType,
    add_rest: bool = True,
):
    sequential_event[nth].duration -= duration
    next_index = nth + 1
    try:
        next_event = sequential_event[next_index]
    except IndexError:
        next_event = None
    if next_event and (is_rest(next_event) or not add_rest):
        sequential_event[next_index].duration += duration
    else:
        sequential_event.insert(nth + 1, events.music.NoteLike([], duration))
示例#7
0
    def _make_moving_part(
        self,
        nth_grid: int,
        n_grids: int,
        grid_data,
        restructured_phrase_part: structure.RestructuredPhrasePart,
        next_restructured_phrase_part: structure.RestructuredPhrasePart,
        restructured_phrase_parts: typing.Tuple[structure.RestructuredPhrasePart, ...],
        cengkok_line: events.basic.SequentialEvent,
        counter_melody: events.basic.SequentialEvent,
    ):
        grid_step_size, grid = grid_data
        if restructured_phrase_part.bar_character == structure.CADENZA:
            density = self.cadenza_density
        else:
            density = self._density_curve.value_at(nth_grid / n_grids)
        n_added_notes = int((len(grid) - 1) * density)
        positions = tuple(
            utilities.tools.accumulate_from_zero([grid_step_size for _ in grid])
        )[1:-1]
        choosen_indices = tuple(
            sorted(
                self._random.choice(
                    positions,
                    p=utilities.tools.scale_sequence_to_sum(grid[1:], 1),
                    size=n_added_notes,
                    replace=False,
                )
            )
        )
        rhythm = events.basic.SequentialEvent([])
        for position0, position1 in zip(
            (0,) + choosen_indices,
            choosen_indices + (len(grid) * grid_step_size,),
        ):
            duration = position1 - position0
            rhythm.append(
                events.music.NoteLike(
                    [
                        restructured_phrase_part.phrase_event.root
                        - parameters.pitches.JustIntonationPitch("2/1")
                    ],
                    duration=duration,
                )
            )

        cut_out_start = counter_melody.duration
        cengkok_extract = cengkok_line.cut_out(
            cut_out_start, cut_out_start + rhythm.duration, mutate=False
        )

        self._assign_pitches(
            rhythm,
            restructured_phrase_parts[nth_grid],
            next_restructured_phrase_part,
            cengkok_extract,
        )

        return rhythm
示例#8
0
 def __call__(
     self,
     bar_to_adapt: events.basic.SequentialEvent,
     nth_bar: int,
     modulation_pitch: parameters.pitches.JustIntonationPitch,
 ) -> events.basic.SequentialEvent:
     if self.gantungan_al(self.activity_level):
         return self._add_gantungan(bar_to_adapt, nth_bar, modulation_pitch)
     else:
         return bar_to_adapt.copy()
示例#9
0
 def __call__(
     self,
     bar_to_adapt: events.basic.SequentialEvent,
     nth_bar: int,
     modulation_pitch: parameters.pitches.JustIntonationPitch,
 ) -> events.basic.SequentialEvent:
     bar_to_adapt = bar_to_adapt.copy()
     bar_to_adapt[0].duration = bar_to_adapt.duration
     for _ in bar_to_adapt[1:]:
         del bar_to_adapt[1]
     bar_to_adapt[0].pitch_or_pitches[0].register(-1)
     bar_to_adapt[0].pitch_or_pitches[0].add(modulation_pitch)
     return bar_to_adapt
示例#10
0
 def _convert_sequential_event(
     self,
     sequential_event_to_convert: events.basic.SequentialEvent,
     absolute_entry_delay: parameters.abc.DurationType,
 ) -> events.basic.SequentialEvent:
     if isinstance(sequential_event_to_convert[0], events.basic.SimpleEvent):
         sequential_event_to_apply_pitches_to = sequential_event_to_convert.copy()
         self._apply_pitches_on_sequential_event(
             sequential_event_to_apply_pitches_to
         )
         return sequential_event_to_apply_pitches_to
     else:
         return super()._convert_sequential_event(
             sequential_event_to_convert, absolute_entry_delay
         )
示例#11
0
 def _add_gantungan(
     self,
     bar_to_adapt: events.basic.SequentialEvent,
     nth_bar: int,
     modulation_pitch: parameters.pitches.JustIntonationPitch,
 ) -> events.basic.SequentialEvent:
     adapted_bar = bar_to_adapt.copy()
     to_remain = self.gantungan_pattern_duration
     absolute_times = adapted_bar.absolute_times
     items_to_remain = 1
     for absolute_time in reversed(absolute_times):
         if absolute_time % to_remain == 0:
             break
         else:
             items_to_remain += 1
     adapted_bar = adapted_bar[-items_to_remain:]
     free_space = bar_to_adapt.duration - adapted_bar.duration
     if free_space:
         n_gantungan_pattern = int(free_space // to_remain)
         gantungan = events.basic.SequentialEvent([])
         for nth_gantungan_pattern in range(n_gantungan_pattern):
             nth_gantungan_pattern_percentage = nth_gantungan_pattern / (
                 n_gantungan_pattern
             )
             gantungan_pattern = next(self.gantungan_pattern_cycle)
             gantungan.extend(
                 self._convert_gantungan_pattern_to_sequential_event(
                     gantungan_pattern,
                     nth_bar,
                     modulation_pitch,
                     nth_gantungan_pattern_percentage,
                 )
             )
         adapted_bar = gantungan + adapted_bar
     assert adapted_bar.duration == bar_to_adapt.duration
     return adapted_bar
示例#12
0
    def _get_pitches_by_backtracking(
        self,
        ambitus: ot2_parameters.ambitus.Ambitus,
        start_pitch: parameters.pitches.JustIntonationPitch,
        end_pitch: parameters.pitches.JustIntonationPitch,
        cengkok_extract: events.basic.SequentialEvent,
        rhythm: events.basic.SequentialEvent,
        restructured_phrase_part: structure.RestructuredPhrasePart,
    ) -> typing.Sequence[parameters.pitches.JustIntonationPitch]:
        def is_valid(choices, choice_indices) -> bool:
            elements = tuple(
                choice[index] for index, choice in zip(choice_indices, choices)
            )
            are_in_ambitus = all(map(ambitus.is_member, elements))
            is_close_enough_to_goal_pitch = True
            if len(elements) == len(rhythm):
                is_close_enough_to_goal_pitch = (
                    abs((elements[-1] - end_pitch).cents) < 280
                )
            return are_in_ambitus and is_close_enough_to_goal_pitch

        def find_choices():
            last_pitch = choices[-1][choice_indices[-1]]
            available_pitches = restructured_phrase_part.phrase_event.all_pitches
            valid_ambitus = ot2_parameters.ambitus.Ambitus(
                last_pitch - parameters.pitches.JustIntonationPitch("5/4"),
                last_pitch + parameters.pitches.JustIntonationPitch("5/4"),
            )
            legal_pitches = []
            for pitch in available_pitches:
                variants = valid_ambitus.find_all_pitch_variants(pitch)
                for variant in variants:
                    if variant != last_pitch:
                        legal_pitches.append(variant)
            legal_pitches = RestructuredPhrasePartsAndCengkokLineToCounterVoiceConverter._sort_legal_pitches(
                cengkok_part_per_event, choices, legal_pitches, last_pitch
            )
            return legal_pitches

        cengkok_part_per_event = tuple(
            cengkok_extract.cut_out(start, end, mutate=False)
            for start, end in rhythm.start_and_end_time_per_event
        )

        choices = [(start_pitch,)]
        choice_indices = [0]
        # backtracking algorithm
        while True:
            if is_valid(choices, choice_indices):
                if len(choices) < len(rhythm):
                    choices.append(find_choices())
                    choice_indices.append(0)
                else:
                    break
            else:
                while choice_indices[-1] + 1 == len(choices[-1]):
                    choice_indices = choice_indices[:-1]
                    choices = choices[:-1]
                    if len(choices) == 0:
                        raise ValueError("No solution found")

                choice_indices[-1] += 1

        pitches = tuple(choice[index] for index, choice in zip(choice_indices, choices))
        return pitches
示例#13
0
    def __call__(
        self,
        bar_to_adapt: events.basic.SequentialEvent,
        nth_bar: int,
        modulation_pitch: parameters.pitches.JustIntonationPitch,
    ) -> events.basic.SequentialEvent:
        # return bar_to_adapt

        goal_pitch = self._restructured_phrase_parts[nth_bar].connection_pitch1
        if not goal_pitch:
            try:
                goal_pitch = self._restructured_phrase_parts[nth_bar + 1].root
            except IndexError:
                goal_pitch = self._restructured_phrase_parts[nth_bar].root

        goal_pitch.register(-1)
        goal_pitch.add(modulation_pitch)

        start_pitch = bar_to_adapt[0].pitch_or_pitches[0]

        if start_pitch == goal_pitch:
            return bar_to_adapt.copy()

        sorted_goal_and_start_pitch = sorted((goal_pitch, start_pitch))

        ambitus = ot2_parameters.ambitus.Ambitus(*sorted_goal_and_start_pitch)

        pitch_line = [start_pitch, goal_pitch]
        for pitch in self._restructured_phrase_parts[nth_bar].all_pitches:
            for pitch_variant in ambitus.find_all_pitch_variants(pitch):
                if pitch_variant not in pitch_line:
                    pitch_line.append(pitch_variant)

        sorted_pitch_line = sorted(
            pitch_line, reverse=start_pitch == sorted_goal_and_start_pitch[1]
        )[:-1]
        n_pitches_in_pitch_line = len(sorted_pitch_line)

        advanced_pitch_line = functools.reduce(
            operator.add,
            zip(
                sorted_pitch_line,
                sorted_pitch_line[2:] + list(reversed(sorted_pitch_line[-2:])),
            ),
        )

        advanced_pitch_line = sorted_pitch_line

        n_factor = 1
        n_needed_beats = n_pitches_in_pitch_line * n_factor

        available_duration = bar_to_adapt.duration

        pulse_size = available_duration
        n_pulses = 1
        while n_pulses < n_needed_beats:
            pulse_size /= 2
            n_pulses = int(available_duration / pulse_size)

        rhythm = generators.toussaint.euclidean(n_pulses, n_needed_beats)
        cadential_bar = events.basic.SequentialEvent([])
        for n_beats, pitch in zip(rhythm, advanced_pitch_line):
            note = events.music.NoteLike(
                [pitch], duration=n_beats * pulse_size, volume="p"
            )
            cadential_bar.append(note)

        try:
            cadential_bar[-2].pitch_or_pitches = [goal_pitch]
        except IndexError:
            cadential_bar[-1].pitch_or_pitches = [goal_pitch]

        assert cadential_bar.duration == bar_to_adapt.duration

        return cadential_bar