def test_insert(self): seq1 = NoteSeq("Ab Bb Eb") seq1.insert(2, Note("C#")) seq2 = NoteSeq("Ab Bb C# Eb") self.assertEqual(seq1, seq2)
def create_music(self, lyrics, invention_method): '''Generate music from text. Music is generated by deriving notes from text, harmonizing those notes, and splitting them into separate tracks, choosing a theme based on the text and then matching the tracks up. :returns: word_theme=a string representing inspiration, music_theme=tempo and instrument list, track_list=list of tracks composed of notes ''' #Read in characters in the lyrics, and convert to musical notes derived_notes = self.music_helper.convert_phrase_to_notes(lyrics) #Determine which musical key is dominant in the derived notes music_key = self.music_helper.determine_dominant_key(derived_notes) #Force all notes into the dominant key so we don't have dischord notes = self.music_helper.conform_notes_to_key(derived_notes, music_key) #Tokenize the word list lyric_words = nltk.word_tokenize(lyrics) #Find a word that will provide a theme for the song word_theme = random.choice( [word for word in lyric_words if len(word) > 4]) if word_theme == None: self.music_helper.determine_theme("random") else: tempo = max( 120, invention_method.method_list[0](word_theme) * invention_method.method_list[4](word_theme) % 400) instr1 = (invention_method.method_list[0](word_theme) * invention_method.method_list[3](word_theme)) % 127 instr2 = (invention_method.method_list[1](word_theme) * invention_method.method_list[2](word_theme)) % 127 instr3 = (invention_method.method_list[4](word_theme) * invention_method.method_list[0](word_theme)) % 127 music_theme = (tempo, [instr1, instr2, instr3]) track_list = [] lead_track = NoteSeq() other_notes = NoteSeq() lead_note_duration = (invention_method.method_list[0](lyrics) % 6) * 0.05 lead_rest_duration = (invention_method.method_list[1](lyrics) % 8) * 0.25 #Separate notes into lead track/others, assign word-based duration for i in range(0, len(notes)): #Associate each note for the lead track with a word in the lyrics, #until we're out of words, then put the rest in "other" if i < len(lyric_words): word_ptr = i word_for_note = lyric_words[word_ptr] #Exclude punctuation in lead track if word_for_note not in (',', '.', ';', '!', '?', '"', ':', '/', '\\'): #Set notes duration based on word length notes[i].dur = len(word_for_note) * lead_note_duration lead_track.append(notes[i]) else: other_notes.append(notes[i]) #Insert rests for lead track at punctuation marks rest_count = 0 for i in range(0, len(lead_track)): if lyric_words[i] in (',', '.', ';', '!', '?', '"', ':', '/', '\\'): lead_track.insert(i + rest_count, Rest(lead_rest_duration)) rest_count = rest_count + 1 #See how long the lead track is lead_track_duration = sum( [noteOrRest.dur for noteOrRest in lead_track]) #Then add it to our track list track_list.append(lead_track) #If there aren't enough notes, add some from the lead track if len(other_notes) < 8: lead_length = len(lead_track) for i in range(lead_length - 1, max(0, lead_length - 8), -1): if not isinstance(lead_track[i], Rest): other_notes.append(lead_track[i]) #Attempt to detect patterns in the lyrics in combination with the #other notes, for the purpose of creating more tracks using the agent's #preferred invention method if len(other_notes) > 0: pattern_tracks = self.music_helper.derive_tracks_from_lyrics( lyrics, other_notes, lead_track_duration, invention_method.method_list) for i in range(0, len(pattern_tracks)): track_list.append(pattern_tracks[i]) #Find out which track came out the longest in duration longest_duration = lead_track_duration for i in range(1, len(track_list)): this_track_duration = sum( [noteOrRest.dur for noteOrRest in track_list[i]]) if this_track_duration > longest_duration: longest_duration = this_track_duration #Make the tracks equal in duration, so there isn't long silence for i in range(0, len(track_list)): #Calculate this track duration this_track_duration = sum( [noteOrRest.dur for noteOrRest in track_list[i]]) #Add some rests before/during to make it centered if this_track_duration < longest_duration: insert_rest = (longest_duration - this_track_duration) / 2 track_list[i].insert(0, Rest(insert_rest)) track_list[i].append(Rest(insert_rest)) #Add a 2 second pause to the end of the longest track so it ends gracefully if this_track_duration == longest_duration: track_list[i].insert(0, Rest(2)) return word_theme, music_theme, track_list