All pastes #935880 Raw Edit

Mine

public text v1 · immutable
·published 2008-03-09 23:49 UTC
rendered paste body
import struct
import os


class MIDIEvent:
    def __init__(self, time):
        self.timeVal = time
        self.vel = 0
        self.note = 0
        
    def setChannel(self, val):
        self.channel = val
    
    def setType(self, type):
        self.type = type

    def setOffset(self, type):
        self.offset = type
        
    def setNote(self, note):
        self.note = note

    def setVelocity(self, vel):
        self.vel = vel

    def setAftertouch(self, val):
        self.aftertouch = val

    def setProgram(self, val):
        self.program = val

    def setController(self, val):
        self.controller = val

    def setValue(self, val):
        self.value = val

    def setChannelAftertouch(self, val):
        self.channelAftertouch = val

    def setPitchBend(self, val):
        self.pitchBend = val

                     
class MIDITrack:
    def __init__(self):
        self.endian = '>'
        self.events = []
        self.setName('')
        self.setMaxTime(0)
        self.setHasNormalEvent(False)
        
    def parseBuffer(self, buffer):

        fmt = self.endian+'i'  
        c = struct.calcsize(fmt)                  
        chunkSize, = struct.unpack(fmt, buffer[:c])
        buffer = buffer[c:]                                
        
        #print "chunkSize=", chunkSize
        
        # read the chunk
        chunk = buffer[:chunkSize]

        # get data after chunk
        buffer = buffer[chunkSize:]
            
        timeOffset = 0
        
        #count = 0
        # loop through all events
        while len(chunk) > 0:
            timeVal, chunk = self.readVarLen(chunk)
            
            timeOffset += timeVal            
                
            ### print "timeVal=", timeVal                        
            eventType, = struct.unpack('B', chunk[:1])
                                    
            #print "event=", event
            if eventType == 0xff:
                #print "meta"                            
                chunk = chunk[1:]
                chunk = self.parseMetaEvent(timeVal, chunk)

            elif eventType == 0xF0:
                print "SysEx"
                chunk = chunk[1:]
                val, chunk = self.readVarLen(chunk)
                chunk = chunk[val:]
                                
            elif eventType == 0xF7:
                print "DivSysEx"

            else:                        
                self.setHasNormalEvent(True)
                chunk = self.parseEvent(eventType, timeOffset, chunk)

                #count += 1                
                #if count > 10:
                #    break

        self.setMaxTime(timeOffset)
        
        return buffer

    def setMaxTime(self, time):
        self._maxTime = time

    def maxTime(self):
        return self._maxTime
        
    def setHasNormalEvent(self, val):
        self.normalEvent = val
    
    def hasNormalEvent(self):
        return self.normalEvent
        
    def setName(self, name):
        self._name = name

    def name(self):
        return self._name
        
    def parseEvent(self, eventType, timeVal, buffer):
        type = (eventType & 0xF0) >> 4;                        
        ### print "NORMAL EVENT : ", type
        
        if type < 0x08:
            type = self.lastType
            # running status
            ### print "lastType=", type
            
        else:
            # advance
            buffer = buffer[1:]
        
        self.lastType = type
            
        channel = eventType & 0x0F
        
        e = MIDIEvent(timeVal)
        e.setChannel(channel)
        e.setType(type)
        e.setOffset(timeVal)
                    
        if type == 0x08:  # note off
            fmt = '2B'
            c = struct.calcsize(fmt)
            note, vel = struct.unpack(fmt, buffer[:c])
            buffer = buffer[c:]
            
            e.setNote(note)
            e.setVelocity(vel)
            
        elif type == 0x09: # note on
            fmt = '2B'
            c = struct.calcsize(fmt)
            note, vel = struct.unpack(fmt, buffer[:c])
            buffer = buffer[c:]

            e.setNote(note)
            e.setVelocity(vel)

        elif type == 0x0a: # note aftertouch
            fmt = '2B'
            c = struct.calcsize(fmt)
            note, aftertouch = struct.unpack(fmt, buffer[:c])
            buffer = buffer[c:]

            e.setNote(note)
            e.setAftertouch(aftertouch)

        elif type == 0x0b: # controller
            fmt = '2B'
            c = struct.calcsize(fmt)
            controller, value = struct.unpack(fmt, buffer[:c])
            buffer = buffer[c:]

            e.setController(controller)
            e.setValue(value)

        elif type == 0x0c: # program change
            fmt = '1B'
            c = struct.calcsize(fmt)
            pgm,  = struct.unpack(fmt, buffer[:c])
            buffer = buffer[c:]

            e.setProgram(pgm)

        elif type == 0x0d: # channel aftertouch
            fmt = '1B'
            c = struct.calcsize(fmt)
            chnAftertouch,  = struct.unpack(fmt, buffer[:c])
            buffer = buffer[c:]

            e.setChannelAftertouch(chnAftertouch)
            
        elif type == 0x0e: # pitch bend
            fmt = '2B'
            c = struct.calcsize(fmt)
            b1, b2 = struct.unpack(fmt, buffer[:c])
            buffer = buffer[c:]

            val = (b1 << 7) | (b2 & 0x7f)

            e.setPitchBend(val)
            
        elif type == 0xf0: # sys ex
            val, buffer = self.readVarLen(buffer)
            buffer = buffer[val:]
            
        elif type == 0xf7: # div sys ex
            val, buffer = self.readVarLen(buffer)
            buffer = buffer[val:]

        elif type == 0xff: # meta event
            val, buffer = self.readVarLen(buffer)
            buffer = buffer[val:]

        self.events.append(e)
            
        return buffer
        
    def parseMetaEvent(self, timeVal, buffer):
        type, = struct.unpack('B', buffer[:1])
        buffer = buffer[1:]
        
        ### print "parseMetaEvent = ", type

        if type == 0: # seq number            
            seqLen, buffer = self.getByte(buffer)
            
            fmt = '2B'
            c = struct.calcsize(fmt)
            msb, lsb = struct.unpack(fmt, buffer[:c])
            buffer = buffer[c:]

        elif type == 1: # text event
            strlen, buffer = self.getByte(buffer)

            fmt = str(strlen)+'s'
            c = struct.calcsize(fmt)
            txt, = struct.unpack(fmt, buffer[:strlen])
            
            buffer = buffer[c:]
            #print "txtEvent=", txt
            
        elif type == 2: # copyright
            strlen, buffer = self.getByte(buffer)
                        
            fmt = str(strlen)+'s'
            c = struct.calcsize(fmt)
            cr, = struct.unpack(fmt, buffer[:strlen])
            
            buffer = buffer[c:]
            #print "cr=", cr
            
        elif type == 3: # seq name
            strlen, buffer = self.getByte(buffer)
        
            fmt = str(strlen)+'s'
            c = struct.calcsize(fmt)
            seqName, = struct.unpack(fmt, buffer[:strlen])
            
            buffer = buffer[c:]
            #print "seqName=", seqName
            
            self.setName(seqName)
            
        elif type == 4: # instr name
            strlen, buffer = self.getByte(buffer)
        
            fmt = str(strlen)+'s'
            c = struct.calcsize(fmt)
            instrName, = struct.unpack(fmt, buffer[:strlen])
            
            buffer = buffer[c:]
            #print "instrName=", instrName
            
        elif type == 5: # lyrics
            strlen, buffer = self.getByte(buffer)
        
            fmt = str(strlen)+'s'
            c = struct.calcsize(fmt)
            lyrics, = struct.unpack(fmt, buffer[:strlen])
            
            buffer = buffer[c:]
            #print "lyrics=", lyrics

        elif type == 6: # marker
            strlen, buffer = self.getByte(buffer)
        
            fmt = str(strlen)+'s'
            c = struct.calcsize(fmt)
            marker, = struct.unpack(fmt, buffer[:strlen])
            
            buffer = buffer[c:]
            #print "marker=", marker

        elif type == 7: # cue point
            strlen, buffer = self.getByte(buffer)
        
            fmt = str(strlen)+'s'
            c = struct.calcsize(fmt)
            cuePoint, = struct.unpack(fmt, buffer[:strlen])
            
            buffer = buffer[c:]
            #print "cuePoint=", cuePoint

        elif type == 32: # chan prefix
            val, buffer = self.getByte(buffer)
            
            # TODO
            len, buffer = self.getByte(buffer)

        elif type == 47: # end of track        
            buffer = buffer[1:]
            
        elif type == 81: # set tempo
            len, buffer = self.getByte(buffer)
            
            fmt = '3B'
            c = struct.calcsize(fmt)
            b1, b2, b3 = struct.unpack(fmt, buffer[:c])
            buffer = buffer[c:]

            val = (b1 << 16) | (b2 << 8) | b3
            
            self.bpm = 60000000 / val
            
            #print "b1=", b1
            #print "b2=", b2
            #print "b3=", b3                        
            #print "tempo=", val
            #print "bpm=", bpm
            
        elif type == 84: # smpte
            len, buffer = self.getByte(buffer)

            fmt = '5B'
            c = struct.calcsize(fmt)
            b1, b2, b3, b4, b5 = struct.unpack(fmt, buffer[:c])
            buffer = buffer[c:]
            
        elif type == 88: # time sig
            len, buffer = self.getByte(buffer)
        
            fmt = '4B'
            c = struct.calcsize(fmt)
            num, denom, metro, _32nds = struct.unpack(fmt, buffer[:c])
            buffer = buffer[c:]

            self.num = num
            self.denom = denom
            self.metro = metro
            self._32nds = _32nds
            
            #print "num=", num
            #print "denom=", denom
            #print "metro=", metro
            #print "_32nds=", _32nds
                                                

        elif type == 89: # key sig
            len, buffer = self.getByte(buffer)

            fmt = '2B'
            c = struct.calcsize(fmt)
            b1, b2 = struct.unpack(fmt, buffer[:c])
            buffer = buffer[c:]
        
        elif type == 127: # seq specific
            val, buffer = self.readVarLen(buffer)
            buffer = buffer[val:]
                        
        else:
            #print "unknown meta-event"
            len, buffer = self.getByte(buffer)
            buffer = buffer[len:]
            
        return buffer

    def getByte(self, buffer):
        fmt = self.endian+'B'
        c = struct.calcsize(fmt)
        val, = struct.unpack(fmt, buffer[:c])
        buffer = buffer[c:]
        
        return val, buffer
        
    def readVarLen(self, buffer):
        result = 0
        for i in range(4):
            c, = struct.unpack('B', buffer[:1])
            
            buffer = buffer[1:]
            
            result = (result << 7) | (c & 0x7f)            
                        
            if c & 0x80 == 0:
                break

        return (result, buffer)
    

class MIDIFile:
    def __init__(self, filename):
        
        self._filename = filename
        
        f = file(filename)
        buffer = f.read()
        f.close()

        #print "buffer=", buffer
        #print len(buffer)
        self.tracks = []
        
        self.endian = '>'
        
        fmt = self.endian+'4c'
        header = struct.unpack(fmt, buffer[0:4])
                
        if header[0] == 'M' and header[1] == 'T' and header[2] == 'h' and header[3] == 'd':
            fmt = self.endian+'ihhh'
            c = struct.calcsize(fmt)
        
            buffer = buffer[4:]
            chunkSize, formatType, nTracks, self.timeDivision = struct.unpack(fmt, buffer[0:c])

            #print chunkSize, formatType, nTracks, timeDivision

            self._numTracks = nTracks
            
            buffer = buffer[c:]
            
            # loop through tracks
            for i in range(nTracks):
                
                fmt = self.endian + '4c'
                header = struct.unpack(fmt, buffer[0:4])
                if header[0] == 'M' and header[1] == 'T' and header[2] == 'r' and header[3] == 'k':
                    buffer = buffer[4:]
                    
                    #print "========== TRACK ", i
                    
                    track = MIDITrack()
                    buffer = track.parseBuffer(buffer)
                    
                    self.tracks.append(track)
                    
                else:
                    raise Exception('Invalid track')
                    
                
        else:
            raise Exception('Invalid header')

    def numTracks(self):
        return self._numTracks

    def track(self, index):
        return self.tracks[index]




if __name__ == "__main__":    

    try:
        m = MIDIFile('midiFiles/children/3blindmiceMelody.mid')
        
        #print "num=", m.numTracks()        
        track = m.track(0)
        
        print "name=", track.name()
        print "bpm=", track.bpm
        print track.num, "/", track.denom
        print "time", m.timeDivision
        print "metro=", track.metro
        print "_32nds=", track._32nds
        
        #print "events=", track.events
        
    except Exception, msg:
        print msg