midi file toolkit

S

Sean McIlroy

## 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*(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 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): return i

def lastnoteindex(events):
for i in reversed(range(len(events))):
if noteevent(events): 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) 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[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[j][1:]
neweventstreams = neweventstreams[:j] + [newevent] +
neweventstreams[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
eventtype, channel = analyzestatus(status)
neweventtype = IfThenElse(eventtype==noteoff,noteon,IfThenElse
(eventtype==noteon,noteoff,eventtype))
newstatus = synthesizestatus(neweventtype,channel)
noteevents = [nextdeltatime, newstatus, body]
nextdeltatime = deltatime
return prefix + noteevents + suffix

"""################################################################################"""

"""
filename = getfilename()
formattype, timedivision, eventstreams = parsedfile = parsefile
(readbytes(filename))
newfile = formattype, timedivision, ###
playbytes(unparsefile(newfile))
"""
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,062
Latest member
OrderKetozenseACV

Latest Threads

Top