Spaces:
Running
Running
| 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 | |
| from MC.markov_chain import get_pngs | |
| #TODO: convert these into inputs | |
| # lengthofsong = 10 Should we control this? Setting it to random now | |
| timesignature = ['3/4','4/4','1/8','6/8','2/4'] #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 | |
| GlobalUIGallery = False | |
| #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 time_sigFinder(time_Signature): | |
| if time_Signature == "4/4": | |
| return 'M:4/4',4 | |
| elif time_Signature == "3/4": | |
| return 'M:3/4',3 | |
| elif time_Signature == "2/4": | |
| return 'M:2/4',2 | |
| elif time_Signature == "1/8": | |
| pass | |
| elif time_Signature == "2/4": | |
| return 'M:2/4',2 | |
| elif time_Signature == "2/2": | |
| return 'M:2/2',2 | |
| # def get_pngs(path): | |
| # filelist=os.listdir(path) | |
| # for fichier in filelist[:]: # filelist[:] makes a copy of filelist. | |
| # if not(fichier.endswith(".png")): | |
| # filelist.remove(fichier) | |
| # newlist = [path+'/'+x for x in filelist] #making it cwd | |
| # return newlist | |
| 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]) | |
| song_len = [len(x) for x in corpus if len(x)>10] | |
| song_len.sort() | |
| 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') | |
| 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) | |
| final_timeS,numOfnotes = time_sigFinder(time_Signature) | |
| songbeginning = ['X:1','T:' + title, 'R:song', 'C:Visakh Ajith', 'Z:id:hn-song-111', final_timeS, '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') | |
| newsong.writelines(songbeginning) | |
| for i in range(lastpart): | |
| newsong.write(" | ".join(song[i:i+numOfnotes]) + "\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") | |
| png_list = get_pngs(path) | |
| return png_list,song_path+".wav" | |