|
@@ -29,7 +29,11 @@ class InputStreamWrapper:
|
|
|
def record(self, rec=True):
|
|
|
self.doRecord=rec
|
|
|
|
|
|
-
|
|
|
+def littleEndian(x, n):
|
|
|
+ b=bytes()
|
|
|
+ for i in range(n):
|
|
|
+ b+=bytes([(x >> (8 * (n - 1 - i))) & 0xff])
|
|
|
+ return b
|
|
|
|
|
|
class MIDIChunk:
|
|
|
def __init__(self, fd):
|
|
@@ -42,6 +46,9 @@ class MIDIChunk:
|
|
|
|
|
|
def print(self):
|
|
|
pass
|
|
|
+
|
|
|
+ def write(self, fd):
|
|
|
+ pass
|
|
|
|
|
|
def readMagick(self):
|
|
|
return self.fd.read(4).decode('ascii')
|
|
@@ -53,23 +60,26 @@ class MIDIChunk:
|
|
|
out+= (x[i]<< (8*(n-1-i)))
|
|
|
return out
|
|
|
|
|
|
- def intN(self, n):
|
|
|
- return self.reverseMsb(self.fd.read(n))
|
|
|
+ def intN(self, n, x=None):
|
|
|
+ if x!=None:
|
|
|
+ for i in range(n):
|
|
|
+ self.fd.write(bytes([ (x>>(8*(n-1-i)) )& 0xff]))
|
|
|
+ else: return self.reverseMsb(self.fd.read(n))
|
|
|
|
|
|
- def int4(self):
|
|
|
- return self.intN(4)
|
|
|
+ def int4(self, x=None):
|
|
|
+ self.intN(4,x)
|
|
|
|
|
|
- def int2(self):
|
|
|
- return self.intN(2)
|
|
|
+ def int2(self, x=None):
|
|
|
+ return self.intN(2,x)
|
|
|
|
|
|
- def byte(self):
|
|
|
- return self.intN(1)
|
|
|
+ def byte(self, x=None):
|
|
|
+ return self.intN(1,x)
|
|
|
|
|
|
def skip(self, n=1):
|
|
|
self.fd.read(n)
|
|
|
|
|
|
class MIDIHeaderChunk(MIDIChunk):
|
|
|
- def __init__(self, fd):
|
|
|
+ def __init__(self, fd=None):
|
|
|
MIDIChunk.__init__(self,fd)
|
|
|
self.format=0
|
|
|
self.tracks=0
|
|
@@ -80,7 +90,17 @@ class MIDIHeaderChunk(MIDIChunk):
|
|
|
|
|
|
self.variableTicks=False
|
|
|
self.ticksPerQuarter=0 # beat per quarter note
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
+ def write(self, fd):
|
|
|
+ self.fd=fd
|
|
|
+ self.fd.write("MThd".encode())
|
|
|
+ self.int4(self.length)
|
|
|
+ self.int2(self.format)
|
|
|
+ self.int2(self.tracks)
|
|
|
+ self.int2(self.division)
|
|
|
+
|
|
|
+
|
|
|
def parse(self):
|
|
|
f=self.fd
|
|
|
self.magick=self.readMagick()
|
|
@@ -97,7 +117,7 @@ class MIDIHeaderChunk(MIDIChunk):
|
|
|
self.ticksPerQuarter= self.division & 0x7fff
|
|
|
|
|
|
class MIDITrackChunk(MIDIChunk):
|
|
|
- def __init__(self, fd, skipTrack=False):
|
|
|
+ def __init__(self, fd=None, skipTrack=False):
|
|
|
MIDIChunk.__init__(self,fd)
|
|
|
self.time=0
|
|
|
self.events=[]
|
|
@@ -118,7 +138,41 @@ class MIDITrackChunk(MIDIChunk):
|
|
|
|
|
|
self.time+=ret
|
|
|
return ret
|
|
|
-
|
|
|
+
|
|
|
+ def write(self, fd):
|
|
|
+ self.fd=fd
|
|
|
+ self.fd.write("MTrk".encode())
|
|
|
+ self.int4(self.length)
|
|
|
+ b=bytes()
|
|
|
+ count=0
|
|
|
+ for evt in self.events:
|
|
|
+ e=littleEndian(int(evt[0]*960),1)+bytes([0xff])+bytes(evt[1].bytes())
|
|
|
+ count+=len(e)
|
|
|
+ print(evt[1].bytes())
|
|
|
+ print(bytes(evt[1].bytes()))
|
|
|
+ count+=evt[0]
|
|
|
+ b+=e
|
|
|
+ print(b)
|
|
|
+ b+=bytes([0])+bytes(EndOfTrack().bytes())
|
|
|
+ print(b)
|
|
|
+ self.fd.write(b)
|
|
|
+
|
|
|
+ def addEvent(self, time, evt):
|
|
|
+ self.events.append((time, evt))
|
|
|
+
|
|
|
+
|
|
|
+ def addNote(self, time, note, channel=0):
|
|
|
+ non= NoteOn(channel)
|
|
|
+ non.key=note
|
|
|
+ non.velocity=0x7f
|
|
|
+ self.events.append((self.time,non))
|
|
|
+ nof= NoteOff(channel)
|
|
|
+ nof.key=note
|
|
|
+ self.events.append((self.time+time*960,nof))
|
|
|
+ self.time+=time*960
|
|
|
+ print(time*960)
|
|
|
+
|
|
|
+
|
|
|
def parse(self):
|
|
|
f=self.fd
|
|
|
self.magick=self.readMagick()
|
|
@@ -137,6 +191,7 @@ class MIDITrackChunk(MIDIChunk):
|
|
|
events.append((self.time, evt))
|
|
|
if evt.isEndTrack():
|
|
|
break
|
|
|
+ self.events=events
|
|
|
return events
|
|
|
|
|
|
|
|
@@ -145,12 +200,14 @@ class MIDITrackChunk(MIDIChunk):
|
|
|
return MidiMessage.parse(self.fd)
|
|
|
|
|
|
class MidiFile:
|
|
|
- def __init__(self, path):
|
|
|
- self.path=path
|
|
|
+ def __init__(self, path=None):
|
|
|
+ if path:
|
|
|
+ self.path=path
|
|
|
self.tracksCount=0
|
|
|
self.header=None
|
|
|
self.tracks=[]
|
|
|
self.loaded=False
|
|
|
+ self.events=[]
|
|
|
|
|
|
def parse(self):
|
|
|
self.fd=0
|