Exemplo n.º 1
0
 def test_insert(self):
     seq1 = NoteSeq("Ab Bb Eb")
     seq1.insert(2, Note("C#"))
     seq2 = NoteSeq("Ab Bb C# Eb")
     self.assertEqual(seq1, seq2)
Exemplo n.º 2
0
 def test_insert(self):
     seq1 = NoteSeq("Ab Bb Eb")
     seq1.insert(2, Note("C#"))
     seq2 = NoteSeq("Ab Bb C# Eb")
     self.assertEqual(seq1, seq2)
Exemplo n.º 3
0
    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