## python 2.6.2 from tkFileDialog import askopenfilename, askdirectory
def nowindow(function): def windowless(): from Tkinter import Tk Tk().withdraw() return function() return windowless getfilename = nowindow(askopenfilename) getdirectoryname = nowindow(askdirectory) def haskellize(pathname): return '\\'.join(pathname.split('/')) def newname(): from time import time return 'NAME_' + ''.join(str(time()).split('.')) def mangle(name): return '__' + name + '__' def pathsafe(name): return '_'.join(name.split('/')) def changefilename(filename,directoryname=None,rewrite=lambda name:name): from os.path import split, splitext, join dirname, filename = split(filename) filename, extension = splitext(filename) filename = rewrite(filename) directoryname = directoryname or dirname return join(directoryname,filename) + extension def readbytes(filename): return [ord(x) for x in file(filename,'rb').read()] def writebytes(numbers,filename): file(filename,'wb').write(''.join([chr(x) for x in numbers])) def playbytes(numbers): from os import startfile filename = newname() + '.mid' writebytes(numbers,filename) startfile(filename) def IfThenElse(criterion,optionTrue,optionFalse): if bool(criterion)==True: return optionTrue if bool(criterion)==False: return optionFalse def flatten(homogeneouslist): from itertools import chain while type(homogeneouslist[0])==list: homogeneouslist = list(chain (*homogeneouslist)) return homogeneouslist def number2digits(number,base): digits = [number] while digits[0]>=base: digits[0:1] = [digits[0]//base, digits [0]%base] return digits def digits2number(digits,base): reversedigits = list(reversed(digits)) return sum([reversedigits[i]*(base**i) for i in range(len (digits))]) def number2fixedlength(number,numbytes): digits = number2digits(number,2**8) numleadingzeros = IfThenElse(len(digits)<numbytes,numbytes-len (digits),0) return [0]*numleadingzeros + digits def fixedlength2number(digits): while digits[0]==0: digits = digits[1:] return digits2number(digits,2**8) def number2variablelength(number): digits = number2digits(number,2**7) padding = [2**7]*(len(digits)-1) + [0] return [x+y for (x,y) in zip(digits,padding)] def variablelength2number(variablelength): digits = [x-(2**7) for x in variablelength[:-1]] + variablelength [-1:] return digits2number(digits,2**7) def getfixedlength(numbers,startindex,numbytes): endindex = startindex + numbytes return numbers[startindex:endindex], endindex def getvariablelength(numbers,startindex): index = startindex while numbers[index]>=(2**7): index = index + 1 endindex = index + 1 return numbers[startindex:endindex], endindex headeridentifier = [ord(x) for x in 'MThd'] trackidentifier = [ord(x) for x in 'MTrk'] eventtypes = range(2**3) noteoff = eventtypes[0] ## notenumber, velocity = parameters noteon = eventtypes[1] ## notenumber, velocity = parameters noteaftertouch = eventtypes[2] ## notenumber, aftertouchvalue = parameters controller = eventtypes[3] ## controllernumber, controllervalue = parameters programchange = eventtypes[4] ## programnumber = parameters[0] channelaftertouch = eventtypes[5] ## aftertouchvalue = parameters[0] pitchbend = eventtypes[6] ## pitchvalueLSB, pitchvalueMSB = parameters nonmidicontrol = eventtypes[7] channels = range(2**4) systemexclusive = channels[0] meta = channels[15] def chunk(identifier,flatdata): return identifier + number2fixedlength(len(flatdata),4) + flatdata def analyzeheaderdata(data): formattype = data[0:2] numtracks = data[2:4] timedivision = data[4:6] return [digits2number(x,2**8) for x in [formattype, numtracks, timedivision]] def synthesizeheaderdata(formattype,numtracks,timedivision): datasegments = [number2fixedlength(x,2) for x in [formattype, numtracks, timedivision]] return datasegments[0] + datasegments[1] + datasegments[2] def headerchunk(formattype,numtracks,timedivision): return chunk(headeridentifier, synthesizeheaderdata(formattype, numtracks, timedivision)) def trackchunk(events): return chunk(trackidentifier,flatten(events)) def analyzestatus(status): number = status[0] eventtype = (number - 2**7) // (2**4) channel = number % (2**4) return eventtype, channel def synthesizestatus(eventtype,channel): number = (2**7) + eventtype*(2**4) + channel return [number] def midicontrolevent(deltatime,eventtype,channel,*parameters): deltatime = number2variablelength(deltatime) status = synthesizestatus(eventtype, channel) return [deltatime, status, list(parameters)] def nonmidicontrolevent(deltatime,messagedata,metatype=[]): deltatime = number2variablelength(deltatime) eventtype = nonmidicontrol channel = IfThenElse(metatype, meta, systemexclusive) status = synthesizestatus(eventtype, channel) datalength = number2variablelength(len(messagedata)) return [deltatime, status, (metatype + datalength + messagedata)] def getchunk(numbers,startindex): identifier, startindex = getfixedlength(numbers,startindex,4) chunksize, startindex = getfixedlength(numbers,startindex,4) chunkdata, startindex = getfixedlength (numbers,startindex,fixedlength2number(chunksize)) return [identifier, chunksize, chunkdata], startindex def file2chunks(numbers): strictupperbound = len(numbers) startindex = 0 chunks = [] while startindex < strictupperbound: chunk, startindex = getchunk(numbers,startindex) chunks.append(chunk) return chunks def getevent(numbers,startindex,runningstatus): deltatime, startindex = getvariablelength(numbers,startindex) status, startindex = getfixedlength (numbers,startindex,IfThenElse(numbers[startindex]>=(2**7),1,0)) runningstatus = status or runningstatus eventtype, channel = analyzestatus(runningstatus) if eventtype==nonmidicontrol: metatype, startindex = getfixedlength (numbers,startindex,IfThenElse(channel==meta,1,0)) messagelength, startindex = getvariablelength (numbers,startindex) message, startindex = getfixedlength (numbers,startindex,variablelength2number(messagelength)) eventbody = metatype + messagelength + message if eventtype<>nonmidicontrol: numparameters = IfThenElse(eventtype in [programchange, channelaftertouch], 1, 2) eventbody, startindex = getfixedlength (numbers,startindex,numparameters) return [deltatime,runningstatus, eventbody], startindex, runningstatus def trackdata2events(numbers): strictupperbound = len(numbers) startindex = 0 runningstatus = [None] events = [] while startindex < strictupperbound: event, startindex, runningstatus = getevent(numbers, startindex, runningstatus) events.append(event) return events def parsefile(numbers): chunks = file2chunks(numbers) formattype, numtracks, timedivision = analyzeheaderdata(chunks[0] [2]) eventstreams = [trackdata2events(chunkdata) for [identifier, chunksize, chunkdata] in chunks[1:]] return formattype, timedivision, eventstreams def unparsefile(parsedfile): formattype, timedivision, eventstreams = parsedfile numtracks = len(eventstreams) header = headerchunk(formattype, numtracks, timedivision) tracks = [trackchunk(events) for events in eventstreams] return header + flatten(tracks) def takeindexedtracks(parsedfile,*indices): formattype, timedivision, eventstreams = parsedfile return formattype, timedivision, [eventstreams[i] for i in indices] def getname(events): deltatime = [0] status = synthesizestatus(nonmidicontrol, meta) metatype = 3 for event in events: if event[0:2]==[deltatime, status] and event[2][0]==metatype: numbers = event[2] namelength, startindex = getvariablelength(numbers,1) namebytes, startindex = getfixedlength (numbers,startindex,variablelength2number(namelength)) return ''.join([chr(x) for x in namebytes]) def noteevent(event): return analyzestatus(event[1])[0] in [noteoff, noteon, noteaftertouch] def firstnoteindex(events): for i in range(len(events)): if noteevent(events[i]): return i def lastnoteindex(events): for i in reversed(range(len(events))): if noteevent(events[i]): return i def explodefile(filename,directoryname=None): formattype, timedivision, eventstreams = parsefile(readbytes (filename)) index = IfThenElse(formattype==1 and firstnoteindex(eventstreams [0])==None, 1, 0) temposettings, eventstreams = eventstreams[:index], eventstreams [index:] for i in range(len(eventstreams)): trackname = getname(eventstreams[i]) or ('track_' + str(i)) rewrite = lambda name: name + '_' + pathsafe(trackname) singletrackfilename = changefilename (filename,directoryname,rewrite) singletrackfile = (formattype, timedivision, temposettings + eventstreams[i:i+1]) writebytes(unparsefile(singletrackfile),singletrackfilename) def reflectpitch(event): if not noteevent(event): return event notenumber, velocity = event[2] newnotenumber = (2**7) - notenumber return event[:2] + [[newnotenumber, velocity]] def translatepitch(event,deltapitch): if not noteevent(event): return event notenumber, velocity = event[2] newnotenumber = notenumber + deltapitch assert newnotenumber in range(2**7) return event[:2] + [[newnotenumber, velocity]] def invert(events): return [reflectpitch(event) for event in events] def transpose(event,deltapitch): return [translatepitch(event,deltapitch) for event in events] def withoutemptytracks(parsedfile): formattype, timedivision, eventstreams = parsedfile index = IfThenElse(formattype==1 and firstnoteindex(eventstreams [0])==None, 1, 0) temposettings, eventstreams = eventstreams[:index], eventstreams [index:] neweventstreams = temposettings + [events for events in eventstreams if firstnoteindex(events)<>None] return formattype, timedivision, neweventstreams def withoutcountin(parsedfile): formattype, timedivision, eventstreams = parsedfile firstnoteindices = [firstnoteindex(events) for events in eventstreams] time = lambda i,j: variablelength2number(eventstreams[i][j][0]) StreamEventTime = [(i,j,time(i,j)) for (i,j) in enumerate (firstnoteindices) if j<>None] starttime = min([t for (i,j,t) in StreamEventTime]) time = lambda t: number2variablelength(t-starttime) StreamEventTime = [(i,j,time(t)) for (i,j,t) in StreamEventTime] neweventstreams = eventstreams[:] for (i,j,t) in StreamEventTime: newevent = [t] + neweventstreams[i][j][1:] neweventstreams[i] = neweventstreams[i][:j] + [newevent] + neweventstreams[i][j+1:] return formattype, timedivision, neweventstreams def preprocessfiles(): from os import listdir, mkdir directoryname = getdirectoryname() filenames = listdir(directoryname) subdirectoryname = directoryname + '/preprocessed' mkdir(subdirectoryname) for filename in filenames: oldfilepath = directoryname + '/' + filename newfilepath = subdirectoryname + '/' + filename writebytes(unparsefile(withoutcountin(withoutemptytracks (parsefile(readbytes(oldfilepath))))),newfilepath) def retrograde(events): prefixindex = firstnoteindex(events) suffixindex = lastnoteindex(events) + 1 prefix, noteevents, suffix = events[:prefixindex], events [prefixindex: suffixindex], events[suffixindex:] noteevents = list(reversed(noteevents)) nextdeltatime = noteevents[-1][0] for i in range(len(noteevents)): deltatime, status, body = noteevents[i] eventtype, channel = analyzestatus(status) neweventtype = IfThenElse(eventtype==noteoff,noteon,IfThenElse (eventtype==noteon,noteoff,eventtype)) newstatus = synthesizestatus(neweventtype,channel) noteevents[i] = [nextdeltatime, newstatus, body] nextdeltatime = deltatime return prefix + noteevents + suffix """################################################################################""" """ filename = getfilename() formattype, timedivision, eventstreams = parsedfile = parsefile (readbytes(filename)) newfile = formattype, timedivision, ### playbytes(unparsefile(newfile)) """ -- http://mail.python.org/mailman/listinfo/python-list