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