Spaces:
Runtime error
Runtime error
File size: 6,782 Bytes
e849e3b 1d4f575 d020229 1d4f575 e849e3b 1d4f575 eada2cd 1d4f575 3b240b2 eada2cd 3b240b2 eada2cd 3b240b2 eada2cd 1d4f575 eada2cd e849e3b 1d4f575 e08994d e849e3b eada2cd 1d4f575 eada2cd 3b240b2 eada2cd fad2ef7 eada2cd 2a6e99c eada2cd 2a6e99c eada2cd 8f37861 d020229 eada2cd da72176 eada2cd e08994d |
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 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
from distutils.log import debug
import os, sys
import random
import datetime
import glob
# from xml.dom.minidom import Document
import markov
import pickle
import subprocess
import gradio as gr
import time
#TODO: convert these into inputs
# lengthofsong = 10 Should we control this? Setting it to random now
timesignature = ['3/4','4/4','1/8','C|'] #Sometimes the letter “C” (meaning common time) will be used in place of 4/4.
#Both C and 4/4 indicate that there are four quarter note beats in each measure.
keysignature = ["C","G","D","No selection"]
difficulty = ["beginner","intermediate","expert"]
key_enforced = False
key_enforced = True #Set to true if user wants in specific key
# 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]
selected_timeSign = '3/4' #Default values
selected_keySign = 'C' #Default Values
deployed = True
#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))
def music_gen(difficulty,time_Signature, Key_Signature):
if deployed:
#delete all files stored in gen_songs_abc
command = "rm -r gen_songs_abc/*"
subprocess.Popen(command,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
corpus = []
song = []
selected_timeSign = time_Signature
selected_keySign = Key_Signature
data_path = "data/"+str(difficulty)
# ex_filename = "hn201612/i/hnsong1.abc"
# parsing on file to extract songs and add them to corpus
for filename in abs_paths(data_path):
with open(filename) as f:
lines = f.readlines()
last = len(lines)
accepted = False
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
if accepted and key_enforced and key_accepted:
corpus.append(song)
accepted = False
key_accepted = False
if accepted:
corpus.append(song)
accepted = False
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
elif "M:" in line:
#time signature
if selected_timeSign == "4/4":
if "4/4" in line or "C|" in line:
accepted = True
elif selected_timeSign in line:
accepted = True
elif line.find("K:") and key_enforced:
#key signature
if selected_keySign in line:
key_accepted = True
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))
song_len = [len(x) for x in corpus if len(x)>10]
song_len.sort()
print("Song lengths",song_len)
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%S')
print(dob)
print(song)
modifier = format(dob)
path = "gen_songs_abc/song_"+modifier
# make song file
# songname = "./gen_songs_abc/gen_song_{}.abc".modifier
song_path = path+"/gen_song_"+modifier #without extension
songname = path+"/gen_song_"+modifier+".abc"
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
if not os.path.exists(path):
os.makedirs("gen_songs_abc/song_"+modifier)
newsong = open(os.path.abspath(songname), 'w')
print(songname)
newsong.writelines(songbeginning)
for i in range(lastpart):
newsong.write(" | ".join(song[i:i+3]) + "\n")
newsong.write(" | ".join(song[lastpart:lengthofsong]))
newsong.close()
#abc2ly markov.abc
# lilypond -fpng markov.ly
#convert abc to markov
#create folder with that name and push .ly, midi and abc there?
f = open(song_path+".ly","w")
# subprocess.Popen(['/usr/bin/abc2midi',songname],stdout=subprocess.PIPE).communicate()
command = "abc2ly "+"-o "+song_path+".ly"+" "+songname
# cmd1 = subprocess.Popen(['/usr/bin/abc2ly','-o',song_path+".ly",songname],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
# cmd1 = subprocess.Popen(command,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
subprocess.Popen(command,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
# os.system(command)
f.close()
# out, err = cmd1.communicate()
# # time.sleep(2)
cmd2 = subprocess.Popen(['lilypond','-fpng','-o',path,song_path+".ly"]).communicate()
# cmd2.wait()
#fluidsynth() dependency
# subprocess.Popen(['midi2audio',song_path+'.midi',song_path+'.wav']).communicate()
subprocess.Popen(['timidity',song_path+'.midi','-Ow','-o',song_path+'.wav']).communicate()
# output = str(temp.communicate())
#Introduces this wait time as we were returning file path even before lilypond converted the abc file
# final_path = os.path.abspath(song_path+".png")
return song_path+'.png',song_path+".wav"
#UI SECTION : Build using Gradio.
#Documentation :
# interface = gr.Interface(fn = music_gen,
# inputs=[gr.Radio(difficulty,label="Difficulty"),
# gr.Radio(timesignature,label="Time Signature"),
# gr.Dropdown(keysignature,label="Key Signature")],
# outputs = ["image","audio"],
# title="Sheet Music Generation for Sight-Reading",
# description="TO be added")
# interface.launch(inline=False)
|