def addCopyright(self, offset, msg): """ Insert copyright. """ # should never happen since the caller sets offset=0 if offset != 0: error("Copyright message must be at offset 0, not %s." % offset) # We need to bypass addToTrack to force copyright to the start of the track. # Create the copyright event ev = packBytes((0xff, 0x02), intToVarNumber(len(msg)), msg) tr = self.miditrk # this is the meta track # We keep a pointer (ipoint) which points to the position of # the last copyright string. If there isn't one, we create # it in the expect; else it's just incremented try: self.ipoint += 1 except AttributeError: self.ipoint = 0 if offset in tr: tr[offset].insert(self.ipoint, ev) else: tr[offset] = [ev]
def addTrkName(self, offset, msg): """ Creates a midi track name event. """ offset = 0 # ignore user offset, always put this at 0 self.trackname = msg cmd = packBytes((0xff, 0x03)) self.delDup(offset, cmd) self.addToTrack(offset, packBytes(cmd, intToVarNumber(len(msg)), msg))
def writeMidiTrack(self, out): """ Create/write the MIDI track. We convert timing offsets to midi-deltas. """ tr = self.miditrk """ If the -1 command line option is set we need to add a terminate to the end of each track. This is done to make looping software like seq24 happy. We do this by truncating all data in the file past the current tick pointer and inserting an all-notes-off at that position. """ if mma.MMA.sync.endsync and self.channel >= 0: eof = gbl.tickOffset for offset in tr.keys(): if offset > eof: del tr[offset] self.addToTrack(eof, packBytes((0xb0 | self.channel, 0x7b, 0))) """ To every MIDI track we generate we add (if the -0 flag was set) an on/off beep at offset 0. This makes for easier sync in multi-tracks. """ if mma.MMA.sync.synctick and self.channel >= 0: t, v = mma.MMA.sync.syncTone self.addToTrack(0, packBytes((0x90 | self.channel, t, v))) self.addToTrack(1, packBytes((0x90 | self.channel, t, 0))) if mma.MMA.debug.debug: ttl = 0 lg = 1 for t in tr: a = len(tr[t]) if a > lg: lg = a ttl += a if self.channel == -1: nm = "META" else: nm = self.trackname dPrint("<%s> Unique ts: %s; Ttl events %s; Average ev/ts %.2f" % (nm, len(tr), ttl, float(ttl) / len(tr))) last = 0 # Convert all events to MIDI deltas and store in # the track array/list tdata = [] # empty track container lastSts = None # Running status tracker for a in sorted(tr.keys()): delta = a - last if not tr[a]: continue # this skips the delta offset update! for d in tr[a]: """ Running status check. For each packet compare the first byte with the first byte of the previous packet. If it is can be converted to running status we strip out byte 0. Note that valid running status byte are 0x80..0xef. 0xfx are system messages and are not suitable for running status. """ if len(d) > 1: if d[0] == lastSts: d = d[1:] else: lastSts = d[0] if lastSts < 0x80 or lastSts > 0xef or not gbl.runningStatus: lastSts = None tdata.extend([intToVarNumber(delta), d]) delta = 0 last = a # Add an EOF to the track (included in total track size) tdata.append(intToVarNumber(0)) tdata.append(packBytes((0xff, 0x2f, 0x00))) tdata = bytearray(b'').join(tdata) totsize = len(tdata) out.write(b"MTrk") out.write(intToLong(totsize)) out.write(tdata)
def addCuePoint(self, offset, msg): """ Create a MIDI cue pointr event. """ self.addToTrack(offset, packBytes((0xff, 0x07), intToVarNumber(len(msg)), msg))
def addLyric(self, offset, msg): """ Create a midi lyric event. """ self.addToTrack(offset, packBytes((0xff, 0x05), intToVarNumber(len(msg)), msg))
def addText(self, offset, msg): """ Create a midi TextEvent.""" self.addToTrack(offset, packBytes((0xff, 0x01), intToVarNumber(len(msg)), msg))
def addMarker(self, offset, msg): """ Create a midi MARKER event.""" self.addToTrack(offset, packBytes((0xff, 0x06), intToVarNumber(len(msg)), msg))