コード例 #1
0
def calculate_fitness_modulate(population, from_bar, to_bar, is_complex=True):
    "Return a melody that modulates from from_bar to to_bar"

    if is_complex:
        # Create a list of melodies including the bar before, the generated melody and the bar after.
        melodies = []
        track_from_bar = Track().add_bar(from_bar)
        track_to_bar = Track().add_bar(to_bar)
        for melody in population:
            track = copy.deepcopy(track_from_bar)
            Track_Functions.add_tracks(track, melody)
            Track_Functions.add_tracks(track, track_to_bar)
            melodies.append(track)

        population_size = len(population)
        fitness_values = np.zeros(population_size)

        default_bias = 10.0
        #For every melody in population calculate fitness THIS IS THE BIG CALCULATION PART
        for iPop in range(population_size):
            melody = melodies[iPop]
            notes = melody.get_notes()
            fitness = 1.0

            #----------------------------------------------------------------------------------------------------------------
            #Measure closeness to ideal value

            #Within the melody
            #Function that measures:                                                   Ideal value:                    Bias:
            fitness += near_calc(measure.repeating_note_length(melody),
                                 frac_repeating_note_length, default_bias)
            fitness += near_calc(measure.average_note_length_clusters(melody),
                                 nmb_note_length_clusters, default_bias)
            (x, y, frac_repeating_passage) = measure.repeating_passages(melody)
            fitness += near_calc(x, nmb_of_passage_rep, default_bias)
            fitness += near_calc(y, len_of_passage_rep, default_bias)

            #-----------------------------------------------------------------------------------------------------------------
            #Function that calculates fraction where 1 is best                          Bias:
            fitness += more_calc(frac_repeating_passage,
                                 default_bias)  #Calculated previously
            (on_beat, on_half_beat) = measure.count_notes_on_beat(melody)
            #When multiplying or dividing the default bias we change the relative weight of that function
            fitness += more_calc(on_beat, default_bias * 2)
            fitness += more_calc(on_half_beat, default_bias / 2)

            fitness -= more_calc(measure.repeating_note_pitch(melody, True),
                                 default_bias)
            fitness -= more_calc(
                measure.count_tritone_or_seventh_in_two_skips(melody),
                default_bias * 1.2)

            fitness += more_calc(measure.check_melody_intervals(melody),
                                 default_bias * 5)
            fitness += more_calc(measure.check_motion_of_melody(melody),
                                 default_bias * 5)

            durations = measure.check_note_durations(melody)
            for iDur in accepted_durations:
                fitness += more_calc(durations[iDur],
                                     points_duration[iDur] * default_bias)

            #Add resulting fitness value to list
            fitness_values[iPop] = fitness

        return fitness_values
    else:

        return calculate_fitness_C(population, 2)
コード例 #2
0
def calculate_fitness_harmony_and_modulate(population,
                                           from_bar,
                                           to_bar,
                                           input_melody,
                                           key,
                                           counter=False):
    "Return a melody that modulates from from_bar to to_bar and harmonizes the input_melody"

    if len(input_melody) == 0:
        print('Wrong input in fitness function')

    # Create a list of melodies including the bar before, the generated melody and the bar after.
    melodies = []
    track_from_bar = Track().add_bar(from_bar)
    track_to_bar = Track().add_bar(to_bar)
    for melody in population:
        track = copy.deepcopy(track_from_bar)
        Track_Functions.add_tracks(track, melody)
        Track_Functions.add_tracks(track, track_to_bar)
        melodies.append(track)

    population_size = len(population)
    fitness_values = np.zeros(population_size)

    default_bias = 10.0

    #For every melody in population calculate fitness THIS IS THE BIG CALCULATION PART
    for iPop in range(population_size):
        melody = melodies[iPop]
        notes = melody.get_notes()
        fitness = 1.0

        #----------------------------------------------------------------------------------------------------------------
        #Measure closeness to ideal value

        #Within the melody
        #Function that measures:                                                   Ideal value:                    Bias:
        fitness += near_calc(measure.repeating_note_length(melody),
                             frac_repeating_note_length, default_bias)
        fitness += near_calc(measure.average_note_length_clusters(melody),
                             nmb_note_length_clusters, default_bias)
        (x, y, frac_repeating_passage) = measure.repeating_passages(melody)
        fitness += near_calc(x, nmb_of_passage_rep, default_bias)
        fitness += near_calc(y, len_of_passage_rep, default_bias)

        #-----------------------------------------------------------------------------------------------------------------
        #Function that calculates fraction where 1 is best                          Bias:
        fitness += more_calc(frac_repeating_passage,
                             default_bias)  #Calculated previously
        (on_beat, on_half_beat) = measure.count_notes_on_beat(melody)
        #When multiplying or dividing the default bias we change the relative weight of that function
        fitness += more_calc(on_beat, default_bias * 2)
        fitness += more_calc(on_half_beat, default_bias / 2)

        fitness += more_calc(measure.count_notes_in_scale(melody, key),
                             default_bias * 5)
        fitness += more_calc(measure.check_same_pattern(input_melody, melody),
                             default_bias)

        consonant, too_long = measure.check_if_intervals_are_consonant_or_too_big(
            input_melody, melody)
        fitness += more_calc(consonant, default_bias * 2)
        fitness -= more_calc(too_long, default_bias * 5)

        fitness -= more_calc(measure.repeating_note_pitch(melody, True),
                             default_bias)
        fitness -= more_calc(
            measure.count_tritone_or_seventh_in_two_skips(melody),
            default_bias * 1.2)

        fitness += more_calc(measure.check_melody_intervals(melody),
                             default_bias * 5)
        fitness += more_calc(measure.check_motion_of_melody(melody),
                             default_bias * 5)

        contrapuntal_motion_values = measure.contrapuntal_motion(
            input_melody, melody)
        fitness += more_calc(contrapuntal_motion_values['Contrary'],
                             default_bias * 2)

        # If included, should add less than Contrary. Contrary is good, oblique and similar is okay.
        fitness += more_calc(contrapuntal_motion_values['Oblique'],
                             default_bias * 1.2)
        fitness += more_calc(contrapuntal_motion_values['Similar'],
                             default_bias * 1.2)

        # Having parallel motion or rest in both tracks is considered bad.
        fitness -= more_calc(contrapuntal_motion_values['Parallel'],
                             default_bias * 3)
        fitness -= more_calc(contrapuntal_motion_values['Rest'], default_bias)

        durations = measure.check_note_durations(melody)
        for iDur in accepted_durations:
            fitness += more_calc(durations[iDur],
                                 points_duration_ending[iDur] * default_bias)

        #Add resulting fitness value to list
        fitness_values[iPop] = fitness

    return fitness_values
コード例 #3
0
def generate_longer_fugue(key, subject, nr_parts=1, order_of_parts=None):
    #If subject doesn't fill full bars fill out rest of last bar of subject with rest
    #if last bar is not full
    if not (subject[-1].is_full()):
        #place a rest at the end of the last bar with the length of 1/(remaining fraction of bar)
        subject[-1].place_rest(int(1.0 / subject[-1].space_left()))

    # Create first bar with subject in first voice and rest in second voice.
    rest_1bar = Bar(key)
    rest_1bar.place_rest(1)
    first_voice = copy.deepcopy(subject)

    #Add same amount of "rest bars" as the number of bars in the subject
    for i in range(len(subject)):
        second_voice.add_bar(copy.deepcopy(rest_1bar))

    total_nr_evolutionary_parts = 3 + 3 * nr_parts

    # Create second bar with answer in second voice.
    answer = Track_Functions.create_answer(subject, key)

    Track_Functions.add_tracks(second_voice, answer)

    # Generate countersubject
    nr_current_generated = 1
    eg_counter = EvolutionaryGenerator(key,
                                       nr_bars=1,
                                       fitness_function='counter',
                                       input_melody=subject,
                                       nr_generations=counter_nr_generations)
    print(
        f"Generating evolutionary part {nr_current_generated} of {total_nr_evolutionary_parts}"
    )
    nr_current_generated += 1
    eg_counter.run_evolution()
    counter_subject = copy.deepcopy(eg_counter.best_individual)

    Track_Functions.add_tracks(first_voice, counter_subject)

    # Save subject, answer and countersubject
    first_voice_first_part = copy.deepcopy(first_voice)
    second_voice_first_part = copy.deepcopy(second_voice)

    # Save bar 2 for later modulation
    bar_prev = first_voice[-1]

    variants = ['Minor', 'Reverse', 'Inverse']
    iParts = 0

    if order_of_parts is None:
        order_of_parts = []
        for i in range(nr_parts):
            rVariant = rnd.choice(variants)
            order_of_parts.append(rVariant)

    while iParts < nr_parts:
        current_variant = order_of_parts[iParts]

        if current_variant == 'Minor':
            # Generate development in minor
            # Transposed -3 to minor (stämma i second voice tills vidare tom)
            new_first_voice = Track_Functions.transpose_to_relative_minor(
                first_voice, key, False)
            new_second_voice = Track_Functions.transpose_to_relative_minor(
                second_voice, key, False)

            bar_after = new_first_voice[0]

            # Generate harmony in second voice first bar
            eg_harmony = EvolutionaryGenerator(
                key,
                nr_bars=1,
                fitness_function='harmony',
                input_melody=Track().add_bar(copy.deepcopy(
                    new_first_voice[0])),
                nr_generations=harmony_nr_generations)

            print(
                f"Generating evolutionary part {nr_current_generated} of {total_nr_evolutionary_parts}"
            )
            nr_current_generated += 1
            eg_harmony.run_evolution()

            new_second_voice[0] = eg_harmony.best_individual[0]

        elif current_variant == 'Reverse':
            # Generate reverse development

            new_first_voice = Track_Functions.reverse(first_voice_first_part,
                                                      key)
            new_second_voice = Track_Functions.reverse(second_voice_first_part,
                                                       key)

            bar_after = new_first_voice[0]

            # Generate harmony in second voice first bar
            eg_harmony = EvolutionaryGenerator(
                key,
                nr_bars=1,
                fitness_function='harmony',
                input_melody=Track().add_bar(copy.deepcopy(
                    new_first_voice[1])),
                nr_generations=harmony_nr_generations)

            print(
                f"Generating evolutionary part {nr_current_generated} of {total_nr_evolutionary_parts}"
            )
            nr_current_generated += 1
            eg_harmony.run_evolution()
            new_second_voice[1] = eg_harmony.best_individual[0]

        elif current_variant == 'Inverse':
            # Generate inverse development

            new_first_voice = Track_Functions.inverse(first_voice_first_part)
            new_second_voice = Track_Functions.inverse(second_voice_first_part)

            bar_after = new_first_voice[0]

            # Generate harmony in second voice first bar
            eg_harmony = EvolutionaryGenerator(
                key,
                nr_bars=1,
                fitness_function='harmony',
                input_melody=Track().add_bar(copy.deepcopy(
                    new_first_voice[0])),
                nr_generations=harmony_nr_generations)

            print(
                f"Generating evolutionary part {nr_current_generated} of {total_nr_evolutionary_parts}"
            )
            nr_current_generated += 1
            eg_harmony.run_evolution()
            new_second_voice[0] = eg_harmony.best_individual[0]

        # Generate the two bars linking this new part to the previous parts

        eg_modulate = EvolutionaryGenerator(
            key,
            nr_bars=2,
            fitness_function='modulate',
            from_bar=bar_prev,
            to_bar=bar_after,
            nr_generations=modulate_nr_generations)

        print(
            f"Generating evolutionary part {nr_current_generated} of {total_nr_evolutionary_parts}"
        )
        nr_current_generated += 1
        eg_modulate.run_evolution()
        modulate_first_voice = copy.deepcopy(eg_modulate.best_individual)

        # Generate second voice as harmony to this linking part

        eg_second_voice_modulate = EvolutionaryGenerator(
            key,
            nr_bars=2,
            fitness_function='harmony',
            input_melody=modulate_first_voice,
            nr_generations=harmony_nr_generations)

        print(
            f"Generating evolutionary part {nr_current_generated} of {total_nr_evolutionary_parts}"
        )
        nr_current_generated += 1
        eg_second_voice_modulate.run_evolution()
        modulate_second_voice = copy.deepcopy(
            eg_second_voice_modulate.best_individual)

        # Add new bars to the voice tracks
        Track_Functions.add_tracks(first_voice, modulate_first_voice)
        Track_Functions.add_tracks(second_voice, modulate_second_voice)

        Track_Functions.add_tracks(first_voice, new_first_voice)
        Track_Functions.add_tracks(second_voice, new_second_voice)

        bar_prev = first_voice[-1]

        iParts += 1

    # Create canon in bar 9 and 10.
    # subject i first voice
    # second voice is subject but shifted (half a bar for now)

    canon_first_voice = Track()
    canon_first_voice.add_bar(copy.deepcopy(subject[0]))

    bar_after = canon_first_voice[0]

    canon_second_voice = Track_Functions.shift(subject, 2)

    # Create modulation from minor to major in 7 and 8

    eg_modulate_to_major = EvolutionaryGenerator(
        key,
        nr_bars=2,
        fitness_function='modulate',
        from_bar=bar_prev,
        to_bar=bar_after,
        nr_generations=modulate_nr_generations)

    print(
        f"Generating evolutionary part {nr_current_generated} of {total_nr_evolutionary_parts}"
    )
    nr_current_generated += 1
    eg_modulate_to_major.run_evolution()
    modulate_back_first_voice = copy.deepcopy(
        eg_modulate_to_major.best_individual)

    # Generate second voice as harmony to the first voice in bar 7 and 8

    eg_second_voice_modulate_back = EvolutionaryGenerator(
        key,
        nr_bars=2,
        fitness_function='harmony',
        input_melody=modulate_first_voice,
        nr_generations=harmony_nr_generations)

    print(
        f"Generating evolutionary part {nr_current_generated} of {total_nr_evolutionary_parts}"
    )
    nr_current_generated += 1
    eg_second_voice_modulate_back.run_evolution()
    modulate_back_second_voice = copy.deepcopy(
        eg_second_voice_modulate.best_individual)

    # Add bar 7-10 to the voice tracks
    Track_Functions.add_tracks(first_voice, modulate_back_first_voice)
    Track_Functions.add_tracks(second_voice, modulate_back_second_voice)

    Track_Functions.add_tracks(first_voice, canon_first_voice)
    Track_Functions.add_tracks(second_voice, canon_second_voice)

    # Add cadence ending to second voice
    Track_Functions.second_voice_ending(second_voice, key)

    second_voice_ending = Track().add_bar(copy.deepcopy(second_voice[-3]))
    second_voice_ending.add_bar(copy.deepcopy(second_voice[-2]))

    # Generate harmony to cadence in first voice
    first_voice_last_bar = Track_Functions.first_voice_ending(first_voice, key)

    eg_first_voice_ending = EvolutionaryGenerator(
        key,
        nr_bars=2,
        fitness_function='ending',
        input_melody=second_voice_ending,
        from_bar=subject[0],
        to_bar=first_voice_last_bar[0],
        nr_generations=harmony_nr_generations)

    print(
        f"Generating evolutionary part {nr_current_generated} of {total_nr_evolutionary_parts}"
    )
    eg_first_voice_ending.run_evolution()
    first_voice_ending = copy.deepcopy(eg_first_voice_ending.best_individual)
    Track_Functions.add_tracks(first_voice, first_voice_ending)
    Track_Functions.add_tracks(first_voice, first_voice_last_bar)

    #Add voices together to create a final composition
    fugue.add_track(first_voice)
    fugue.add_track(second_voice)

    #Generate lilypond file for fugue named final_fugue (removed for submission)
    finished_fugue = LilyPond.from_Composition(fugue)
    to_LilyPond_file(finished_fugue, "final_fugue")

    #Generate MIDI output for fugue named final_fugue
    midi_file_out.write_Composition("final_fugue.mid", fugue)
    return
コード例 #4
0
def generate_fugue(key, subject):

    #If subject doesn't fill full bars fill out rest of last bar of subject with rest
    #if last bar is not full
    if not (subject[-1].is_full()):
        #place a rest at the end of the last bar with the length of 1/(remaining fraction of bar)
        subject[-1].place_rest(int(1.0 / subject[-1].space_left()))

    # Create first bar with subject in first voice and rest in second voice.
    rest_1bar = Bar(key)
    rest_1bar.place_rest(1)
    first_voice = copy.deepcopy(subject)

    #Add same amount of "rest bars" as the number of bars in the subject
    for i in range(len(subject)):
        second_voice.add_bar(copy.deepcopy(rest_1bar))

    # Create second bar with answer in second voice.
    answer = Track_Functions.create_answer(subject, key)

    #second_voice = second_voice + answer
    Track_Functions.add_tracks(second_voice, answer)

    # Generate countersubject
    eg_counter = EvolutionaryGenerator(key,
                                       nr_bars=1,
                                       fitness_function='counter',
                                       input_melody=subject,
                                       nr_generations=counter_nr_generations)
    print('Generating evolutionary part 1 of 7')
    eg_counter.run_evolution()
    counter_subject = copy.deepcopy(eg_counter.best_individual)

    Track_Functions.add_tracks(first_voice, counter_subject)

    # Save bar 2 for later modulation
    bar_2 = first_voice[-1]

    # Generate development in minor in bar 5 and 6.
    # Transposed -3 to minor + (stämma i för second voice tills vidare tom)
    minor_first_voice = Track_Functions.transpose_to_relative_minor(
        first_voice, key, False)
    minor_second_voice = Track_Functions.transpose_to_relative_minor(
        second_voice, key, False)

    bar_5 = minor_first_voice[0]

    # Generate harmony in second voice in bar 5
    eg_harmony_minor = EvolutionaryGenerator(
        key,
        nr_bars=1,
        fitness_function='harmony',
        input_melody=Track().add_bar(copy.deepcopy(minor_first_voice[0])),
        nr_generations=harmony_nr_generations)

    print('Generating evolutionary part 2 of 7')
    eg_harmony_minor.run_evolution()

    minor_second_voice[0] = eg_harmony_minor.best_individual[0]

    # Generate bar 3 and 4 as a modulation between bar 2 and 5

    eg_modulate_to_minor = EvolutionaryGenerator(
        key,
        nr_bars=2,
        fitness_function='modulate',
        from_bar=bar_2,
        to_bar=bar_5,
        nr_generations=modulate_nr_generations)

    print('Generating evolutionary part 3 of 7')
    eg_modulate_to_minor.run_evolution()
    modulate_first_voice = copy.deepcopy(eg_modulate_to_minor.best_individual)

    # Generate second voice as harmony to the first voice in bar 3 and 4

    eg_second_voice_modulate = EvolutionaryGenerator(
        key,
        nr_bars=2,
        fitness_function='harmony',
        input_melody=modulate_first_voice,
        nr_generations=harmony_nr_generations)

    print('Generating evolutionary part 4 of 7')
    eg_second_voice_modulate.run_evolution()
    modulate_second_voice = copy.deepcopy(
        eg_second_voice_modulate.best_individual)

    # Add bar 3-6 to the voice tracks
    Track_Functions.add_tracks(first_voice, modulate_first_voice)
    Track_Functions.add_tracks(second_voice, modulate_second_voice)

    Track_Functions.add_tracks(first_voice, minor_first_voice)
    Track_Functions.add_tracks(second_voice, minor_second_voice)

    bar_6 = first_voice[-1]

    # Create canon in bar 9 and 10.
    # subject i first voice
    # second voice is subject but shifted (half a bar for now)

    canon_first_voice = Track()
    canon_first_voice.add_bar(copy.deepcopy(subject[0]))

    bar_9 = canon_first_voice[0]

    canon_second_voice = Track_Functions.shift(subject, 2)

    # Create modulation from minor to major in 7 and 8

    eg_modulate_to_major = EvolutionaryGenerator(
        key,
        nr_bars=2,
        fitness_function='modulate',
        from_bar=bar_6,
        to_bar=bar_9,
        nr_generations=modulate_nr_generations)

    print('Generating evolutionary part 5 of 7')
    eg_modulate_to_major.run_evolution()
    modulate_back_first_voice = copy.deepcopy(
        eg_modulate_to_major.best_individual)

    # Generate second voice as harmony to the first voice in bar 7 and 8

    eg_second_voice_modulate_back = EvolutionaryGenerator(
        key,
        nr_bars=2,
        fitness_function='harmony',
        input_melody=modulate_first_voice,
        nr_generations=harmony_nr_generations)

    print('Generating evolutionary part 6 of 7')
    eg_second_voice_modulate_back.run_evolution()
    modulate_back_second_voice = copy.deepcopy(
        eg_second_voice_modulate.best_individual)

    # Add bar 7-10 to the voice tracks
    Track_Functions.add_tracks(first_voice, modulate_back_first_voice)
    Track_Functions.add_tracks(second_voice, modulate_back_second_voice)

    Track_Functions.add_tracks(first_voice, canon_first_voice)
    Track_Functions.add_tracks(second_voice, canon_second_voice)

    # Add cadence ending to second voice
    Track_Functions.second_voice_ending(second_voice, key)

    second_voice_ending = Track().add_bar(copy.deepcopy(second_voice[-3]))
    second_voice_ending.add_bar(copy.deepcopy(second_voice[-2]))

    # Generate harmony to cadence in first voice
    first_voice_last_bar = Track_Functions.first_voice_ending(first_voice, key)

    eg_first_voice_ending = EvolutionaryGenerator(
        key,
        nr_bars=2,
        fitness_function='ending',
        input_melody=second_voice_ending,
        from_bar=subject[0],
        to_bar=first_voice_last_bar[0],
        nr_generations=harmony_nr_generations)

    print('Generating evolutionary part 7 of 7')
    eg_first_voice_ending.run_evolution()
    first_voice_ending = copy.deepcopy(eg_first_voice_ending.best_individual)
    Track_Functions.add_tracks(first_voice, first_voice_ending)
    Track_Functions.add_tracks(first_voice, first_voice_last_bar)

    #Add voices together to create a final composition
    fugue.add_track(first_voice)
    fugue.add_track(second_voice)

    #Generate lilypond file for fugue named final_fugue
    finished_fugue = LilyPond.from_Composition(fugue)
    to_LilyPond_file(finished_fugue, "final_fugue")

    #Generate MIDI output for fugue named final_fugue
    midi_file_out.write_Composition("final_fugue.mid", fugue)
コード例 #5
0
    def cross_over(self, chromosomes):
        """Change chromosome by using crossover between two chromosomes.
        It decides a beat to split and exchange tails after this beat
        between the two chromosomes.
        """

        # Decide at which semiquaver to cross
        bar_to_break_in = rnd.randrange(self.nr_bars)
        beat_to_break_at = rnd.randrange(16) / 16

        # Initialize list to save heads and tails of each chromosome
        head_chromosome = [Track(), Track()]
        tail_chromosome = [Track(), Track()]

        # Place to save the half bars that should be part of tail
        end_head_chromosome = [Bar(self.key), Bar(self.key)]
        start_tail_chromosome = [Bar(self.key), Bar(self.key)]

        for iChrom in range(2):

            bar_nr = 0
            for bar in chromosomes[iChrom]:
                # Bar before the break bar is added to head
                if bar_nr < bar_to_break_in:
                    head_chromosome[iChrom].add_bar(bar)

                # Bar after the break bar is added to tail
                elif bar_nr > bar_to_break_in:
                    tail_chromosome[iChrom].add_bar(bar)

                # The break bar is breaked in two parts.
                else:
                    # If breaking between bars, add the break bar to the tail
                    if beat_to_break_at == 0:
                        tail_chromosome[iChrom].add_bar(bar)
                        bar_nr += 1
                        continue

                    beat = 0
                    note_index = 0
                    while beat < 1.0:
                        note_pitch = bar[note_index][2]
                        note_duration = bar[note_index][1]

                        # If note stops before or at breakpoint, add to first part
                        if beat + 1 / bar[note_index][1] <= beat_to_break_at:
                            end_head_chromosome[iChrom].place_notes(
                                note_pitch, note_duration)

                        # If note starts at or after breakpoint, add to second part
                        elif beat >= beat_to_break_at:
                            # If the first one after break, add it at the breakpoint. Otherwise, add it after the previous.
                            if beat == beat_to_break_at:
                                start_tail_chromosome[
                                    iChrom].current_beat = beat_to_break_at

                            start_tail_chromosome[iChrom].place_notes(
                                note_pitch, note_duration)

                        else:
                            # Divide to one part from beat to breakpoint, and one the length left over starting at breakpoint
                            first_part_duration = 1 / (beat_to_break_at - beat)
                            second_part_duration = 1 / (
                                1 / note_duration - 1 / first_part_duration)

                            end_head_chromosome[iChrom].place_notes(
                                note_pitch, first_part_duration)
                            start_tail_chromosome[
                                iChrom].current_beat = beat_to_break_at
                            start_tail_chromosome[iChrom].place_notes(
                                note_pitch, second_part_duration)
                        beat += 1 / bar[note_index][1]
                        note_index += 1

                bar_nr += 1

        middle_bars = []
        cross_chromosomes = []
        for i in range(2):

            if beat_to_break_at != 0:
                # Combine the two middle parts in the new way
                middle_bars.append(
                    self.combine_bars(end_head_chromosome[i],
                                      start_tail_chromosome[1 - i]))

                # Add the changed middlebar to the head_chromosome
                head_chromosome[i].add_bar(middle_bars[i])

            # Create a new chromosome by adding the new tail to the head
            Track_Functions.add_tracks(head_chromosome[i],
                                       tail_chromosome[1 - i])
            new_chromosome = head_chromosome[i]

            # Add the new chromosome to the list to be returned
            cross_chromosomes.append(new_chromosome)

        return cross_chromosomes