File size: 3,220 Bytes
1d4f575
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import os, sys
import random
import datetime
import glob
import markov
import pickle


corpus = []
song = []

"Generate sheet music for a new song from a corpus of existing songs in abc format"


# get the list of filenames (abc files downloaded from http://www.norbeck.nu/abc/)
# getdirs = []
# dirs = ["hn201612/i/*.abc", "hn201612/s/*.abc"]
# dirs = ["data/*.abc"]
# dirs = ["data"]
# for dir1 in dirs:
# 	for filename in glob.iglob(dir1):
# 		getdirs += [filename]


#Finds all absolute paths in directory
#https://stackoverflow.com/questions/9816816/get-absolute-paths-of-all-files-in-a-directory
def abs_paths(dir):
    for dir_path,_,filenames in os.walk(dir):
        for f in filenames:
            yield os.path.abspath(os.path.join(dir_path, f))
# ex_filename = "hn201612/i/hnsong1.abc"
# parsing on file to extract songs and add them to corpus
for filename in abs_paths("n-grams/data/hard"):
	with open(filename) as f:
		lines = f.readlines()
		last = len(lines)
		for index, line in enumerate(lines):
			if (line.find("|") < 0 and index - 1 == last):
				# if the next line does not have pipes add song to corpus and then set song variable empty again
				corpus.append(song)
				song = []

			else:
				if line.find("|") > -1:
					# a line should be split on "|" and copied to the corpus if it has pipes
					sline = line.split("|")
					# add the list of measures to the song
					song += [x.strip("\r\n") for x in sline if len(x.strip("\r\n")) > 0]
					last = index

print("Training on {} songs...".format(len(corpus)))

# MARKOV PART
# n-gram length for markov model
n = 1

model = markov.generate_model_from_token_lists(corpus, n)


# save pickle
with open('markov_chain.pickle', 'wb') as handle:
	pickle.dump(model, handle)


def nextword(word):
	return markov.generate(model, 3, seed=word, max_iterations=1)


def writesong(songlength, first):
	song = [first]
	for i in range(songlength):
		song += nextword(str(song[-1]))
	return song

# choose a random song length from list of song lengths in corpus
lengthofsong = random.choice([len(x) for x in corpus if len(x) > 10])
print("Song length will be {}".format(lengthofsong))


firstnote = markov.generate(model, n, max_iterations=3)[0]
# print "first note: {}".format(firstnote)

print("Here is the song in abc format:")
song = writesong(lengthofsong, firstnote)
dob = datetime.datetime.now().strftime('%H%M')

print(dob)
print(song)

# make song file
songname = "n-grams/gen_songs_abc/gen_song_{}.abc".format(dob)
print("\n\nYou can find the song in {}".format(songname))
lastpart = lengthofsong - lengthofsong%4

# hack to include dictionary at the beginning of every abc file
# will add a more sophisticated way to generate the values in the future
title = "Markov Song {}".format(dob)
songbeginning = ['X:1','T:' + title, 'R:song', 'C:Visakh Ajith', 'Z:id:hn-song-111', 'M:3/4', 'L:1/8', 'Q:1/4=120', 'K:G'
]
songbeginning = [x+"\n" for x in songbeginning]

# convert song to abc format and write to file
newsong = open(songname, 'w')
newsong.writelines(songbeginning)
for i in range(lastpart):
	newsong.write(" | ".join(song[i:i+3]) + "\n")
newsong.write(" | ".join(song[lastpart:lengthofsong]))

#abc2ly markov.abc
# lilypond -fpng markov.ly