Пример #1
0
def readMidi(filename):
    """ Read existing midi file, parse and return events, textevents & lyrics """

    global offset, midifile, beatDivision, istart, iend, firstNote, ignorePC

    try:
        inpath = file(filename, "rb")
    except:
        error("Unable to open MIDI file %s for reading" % filename)

    midifile=inpath.read()
    inpath.close()

    # Create our storage:
    #    A dic with the channels 0-15 as keys for the midi note events
    #    2 lists for lyrics and text events. These have tuples for (time, text)

    events={}
    for c in range(0,16):
        events[c]=[]

    textEvs=[]
    lyricEvs=[]

    # Ensure this is valid header

    hd=midifile[0:4]
    if hd != 'MThd':
        error("Expecting 'MThd', %s not a standard midi file" % filename)

    offset = 4
    a = m32i()

    if a != 6:
        error("Expecting a 32 bit value of 6 in header")

    format=m16i()

    if format not in (0,1):
        error("MIDI file format %s not recognized" % format)

    ntracks=m16i()
    beatDivision=m16i()

    if beatDivision != gbl.BperQ:
        warning("MIDI file '%s' tick/beat of %s differs from MMA's "
            "%s. Will try to compensate" %
            (filename, beatDivision, gbl.BperQ))

    # Adjust start/end to the file's tick

    istart *= beatDivision
    iend   *= beatDivision

    midievents={}
    firstNote = 0xffffff

    for tr in range(ntracks):
        tm=0

        hdr = midifile[offset:offset+4]
        offset+=4

        if hdr != 'MTrk':
            error("Malformed MIDI file in track header")
        trlen = m32i()    # track length, not used?

        lastevent = None

        """ Parse the midi file. We have to parse off each event, even
            though many will just be thrown away. You can't just skip around
            in a midi file :) In the future we might decide to include meta
            stuff, etc. Or, we may not :) For now, we keep:
                - note on
                - note off
                 - key pressure
                - control change
                - program change
                - channel pressure
                - pitch blend
                - text event
                - lyric event
        """

        while 1:
            tm += mvarlen()        # adjust total offset by delta

            ev=m1i()

            if ev < 0x80:
                if not lastevent:
                    error("Illegal running status in %s at %s" % (midifile, offset))
                offset -= 1
                ev=lastevent


            sValue = ev>>4        # Shift MSBs to get a 4 bit value
            channel = ev & 0x0f

            if sValue == 0x8:        # note off event

                note=m1i()
                vel=m1i()

                if octAdjust and channel != 10:
                    note += octAdjust
                    while note < 0:  note += 12
                    while note >127: note -= 12
                events[channel].append([tm, ev & 0xf0, chr(note)+chr(vel)])

            elif sValue == 0x9:        # note on event
                if tm < firstNote:
                    firstNote = tm
                note=m1i()
                vel=m1i()

                if octAdjust and channel != 10:
                    note += octAdjust
                    while note < 0:  note += 12
                    while note >127: note -= 12

                if volAdjust != 100:
                    vel = int( (vel*volAdjust)/100)
                    if vel<0: vel=1
                    if vel>127: vel=127

                events[ev & 0xf].append([tm, ev & 0xf0, chr(note)+chr(vel)])

            elif sValue == 0xa:        # key pressure
                events[ev & 0xf].append([tm, ev & 0xf0, chars(2)])

            elif sValue == 0xb:        # control change
                events[ev & 0xf].append([tm, ev & 0xf0, chars(2)])
            
            elif sValue == 0xc:        # program change
                if ignorePC:  # default is to ignore these
                    offset += 1  
                else:         # set with option IgnorePC=1
                    events[ev & 0xf].append([tm, ev & 0xf0, chars(1)])

            elif sValue == 0xd:        # channel pressure
                events[ev & 0xf].append([tm, ev & 0xf0, chars(1)])

            elif sValue == 0xe:        # pitch blend
                events[ev & 0xf].append([tm, ev & 0xf0, chars(2)])

            elif sValue == 0xf:        # system, mostly ignored
                if ev == 0xff:        # meta events
                    a=m1i()

                    if a == 0x00:    # sequence number
                        l=mvarlen()
                        offset += l

                    elif a == 0x01: # text (could be lyrics)
                        textEvs.append((tm, chars(mvarlen())))

                    elif a == 0x02: # copyright
                        l=mvarlen()
                        offset += l

                    elif a == 0x03: # seq/track name
                        l=mvarlen()
                        offset += l

                    elif a == 0x04: # instrument name
                        l=mvarlen()
                        offset += l

                    elif a == 0x05: # lyric
                        lyricEvs.append((tm, chars(mvarlen())))

                    elif a == 0x06: # marker
                        l=mvarlen()
                        offset += l

                    elif a == 0x07: # cue point
                        l=mvarlen()
                        offset += l

                    elif a == 0x21: # midi port
                        l=mvarlen()
                        offset += l

                    elif a == 0x2f: # end of track
                        l=mvarlen()
                        offset += l
                        break

                    elif a == 0x51: #tempo
                        l=mvarlen()
                        offset += l

                    elif a == 0x54: # SMPTE offset
                        l=mvarlen()
                        offset += l

                    elif a == 0x58: # time sig
                        l=mvarlen()
                        offset += l

                    elif a == 0x59: # key sig
                        l=mvarlen()
                        offset += l

                    else:        # probably 0x7f, proprietary event
                        l=mvarlen()
                        offset += l


                elif ev == 0xf0:    # system exclusive
                    l=mvarlen()
                    offset += l

                elif ev == 0xf2:    # song position pointer, 2 bytes
                    offset += 2

                elif ev == 0xf3:    # song select, 1 byte
                    offset += 1

                else:        # all others are single byte commands
                    pass

            if ev >= 0x80 and ev <= 0xef:
                lastevent = ev

    return (events, textEvs, lyricEvs)
Пример #2
0
        print
    print "No data created. Did you remember to set a groove/sequence?"
    if fileExist:
        print "Existing file '%s' has not been modified." % outfile
    sys.exit(1)

lyric.leftovers()

if fileExist:
    print "Overwriting existing",
else:
    print "Creating new",
print "midi file (%s bars, %.2f min): '%s'" %  (gbl.barNum, gbl.totTime, outfile)

try:
    out = file(outfile, 'wb')
except:
    error("Can't open file '%s' for writing" % outfile)

MMA.midi.writeTracks(out)
out.close()

if gbl.playFile:
    import MMA.player
    MMA.player.playMidi(outfile)

if gbl.debug:
    print "Completed processing file '%s'." % outfile


Пример #3
0
def readMidi(filename):
    """ Read existing midi file, parse and return events, textevents & lyrics """

    global offset, midifile, firstNote, ignorePC

    try:
        inpath = file(filename, "rb")
    except:
        error("MidiInc: Unable to open MIDI file %s for reading" % filename)

    midifile = inpath.read()
    inpath.close()

    # Create our storage:
    #    A dic with the channels 0-15 as keys for the midi note events
    #    2 lists for lyrics and text events. These have tuples for (time, text)

    events = {}
    for c in range(0, 16):
        events[c] = []

    textEvs = []
    lyricEvs = []

    # Ensure this is valid header

    hd = midifile[0:4]
    if hd != 'MThd':
        error("MidiInc: Expecting 'MThd', %s not a standard midi file" %
              filename)

    offset = 4
    a = m32i()

    if a != 6:
        error("MidiInc: Expecting a 32 bit value of 6 in header")

    format = m16i()

    if format not in (0, 1):
        error("MidiInc: MIDI file format %s not recognized" % format)

    ntracks = m16i()
    beatDivision = m16i()

    if beatDivision != gbl.BperQ:
        warning("MIDI file '%s' tick/beat of %s differs from MMA's "
                "%s. Will try to compensate" %
                (filename, beatDivision, gbl.BperQ))
        beatad = gbl.BperQ / float(beatDivision)
    else:
        beatad = None

    midievents = {}
    firstNote = 0xffffff

    for tr in range(ntracks):
        tm = 0

        hdr = midifile[offset:offset + 4]
        offset += 4

        if hdr != 'MTrk':
            error("MidiInc: Malformed MIDI file in track header")
        trlen = m32i()  # track length, not used?

        lastevent = None
        """ Parse the midi file. We have to parse off each event, even
            though many will just be thrown away. You can't just skip around
            in a midi file :) In the future we might decide to include meta
            stuff, etc. Or, we may not :) For now, we keep:
                - note on
                - note off
                 - key pressure
                - control change
                - program change
                - channel pressure
                - pitch blend
                - text event
                - lyric event
        """

        while 1:
            tm += mvarlen()  # adjust total offset by delta

            ev = m1i()

            if ev < 0x80:
                if not lastevent:
                    error("MidiInc: Illegal running status in %s at %s" %
                          (midifile, offset))
                offset -= 1
                ev = lastevent

            sValue = ev >> 4  # Shift MSBs to get a 4 bit value
            channel = ev & 0x0f

            if sValue == 0x8:  # note off event

                note = m1i()
                vel = m1i()

                if octAdjust and channel != 9:  # drums are 9 when 0..15 (not 10!)
                    note += octAdjust
                    while note < 0:
                        note += 12
                    while note > 127:
                        note -= 12
                events[channel].append([tm, ev & 0xf0, chr(note) + chr(vel)])

            elif sValue == 0x9:  # note on event
                if tm < firstNote:
                    firstNote = tm
                note = m1i()
                vel = m1i()

                if octAdjust and channel != 9:
                    note += octAdjust
                    while note < 0:
                        note += 12
                    while note > 127:
                        note -= 12

                if volAdjust != 100:
                    vel = int((vel * volAdjust) / 100)
                    if vel < 0: vel = 1
                    if vel > 127: vel = 127

                events[ev & 0xf].append([tm, ev & 0xf0, chr(note) + chr(vel)])

            elif sValue == 0xa:  # key pressure
                events[ev & 0xf].append([tm, ev & 0xf0, chars(2)])

            elif sValue == 0xb:  # control change
                events[ev & 0xf].append([tm, ev & 0xf0, chars(2)])

            elif sValue == 0xc:  # program change
                if ignorePC:  # default is to ignore these
                    offset += 1
                else:  # set with option IgnorePC=1
                    events[ev & 0xf].append([tm, ev & 0xf0, chars(1)])

            elif sValue == 0xd:  # channel pressure
                events[ev & 0xf].append([tm, ev & 0xf0, chars(1)])

            elif sValue == 0xe:  # pitch blend
                events[ev & 0xf].append([tm, ev & 0xf0, chars(2)])

            elif sValue == 0xf:  # system, mostly ignored
                if ev == 0xff:  # meta events
                    a = m1i()

                    if a == 0x00:  # sequence number
                        l = mvarlen()
                        offset += l

                    elif a == 0x01:  # text (could be lyrics)
                        textEvs.append([tm, chars(mvarlen())])

                    elif a == 0x02:  # copyright
                        l = mvarlen()
                        offset += l

                    elif a == 0x03:  # seq/track name
                        l = mvarlen()
                        offset += l

                    elif a == 0x04:  # instrument name
                        l = mvarlen()
                        offset += l

                    elif a == 0x05:  # lyric
                        lyricEvs.append([tm, chars(mvarlen())])

                    elif a == 0x06:  # marker
                        l = mvarlen()
                        offset += l

                    elif a == 0x07:  # cue point
                        l = mvarlen()
                        offset += l

                    elif a == 0x21:  # midi port
                        l = mvarlen()
                        offset += l

                    elif a == 0x2f:  # end of track
                        l = mvarlen()
                        offset += l
                        break

                    elif a == 0x51:  #tempo
                        l = mvarlen()
                        offset += l

                    elif a == 0x54:  # SMPTE offset
                        l = mvarlen()
                        offset += l

                    elif a == 0x58:  # time sig
                        l = mvarlen()
                        offset += l

                    elif a == 0x59:  # key sig
                        l = mvarlen()
                        offset += l

                    else:  # probably 0x7f, proprietary event
                        l = mvarlen()
                        offset += l

                elif ev == 0xf0:  # system exclusive
                    l = mvarlen()
                    offset += l

                elif ev == 0xf2:  # song position pointer, 2 bytes
                    offset += 2

                elif ev == 0xf3:  # song select, 1 byte
                    offset += 1

                else:  # all others are single byte commands
                    pass

            if ev >= 0x80 and ev <= 0xef:
                lastevent = ev

    # Modify the lists of events to compensate for timing
    if beatad:
        if verbose:
            print "Adjusting all deltas by %s." % beatad
        for ch in events:
            for e in events[ch]:
                e[0] = int(e[0] * beatad)
        for e in textEvs:
            e[0] = int(e[0] * beatad)
        for e in lyricEvs:
            e[0] = int(e[0] * beatad)

    return (events, textEvs, lyricEvs)
Пример #4
0
        print
    print "No data created. Did you remember to set a groove/sequence?"
    if fileExist:
        print "Existing file '%s' has not been modified." % outfile
    sys.exit(1)

lyric.leftovers()

if fileExist:
    print "Overwriting existing",
else:
    print "Creating new",
print "midi file (%s bars, %.2f min): '%s'" %  (gbl.barNum, gbl.totTime, outfile)

try:
    out = file(outfile, 'wb')
except IOError:
    error("Can't open file '%s' for writing" % outfile)

MMA.midi.writeTracks(out)
out.close()

if gbl.playFile:
    import MMA.player
    MMA.player.playMidi(outfile)

if gbl.debug:
    print "Completed processing file '%s'." % outfile