|
|
MIDI Class
Added on 3/25/2004
|
Parent Script for reading, writing, analyzing, modifying, and creating standard MIDI files (*.mid, *.rmi) of type 0 or 1.
Download PC Source
--/****************************************************************************
--Software: MIDI CLASS
--Version: 1.0
--Date: 2003/12/23
--Author: Valentin Schmidt
--Contact: fluxus@freenet.de
--License: Freeware
--
--You may use and modify this software as you wish.
--****************************************************************************/
property pTracks --array of tracks, where each track is array of message strings
property pTimebase --timebase = ticks per frame (quarter note)
property pTempo --tempo as integer (0 for unknown)
property pTempoMsgNum --position of tempo event in track 0
property pLF
property pCR
--/****************************************************************************
--* *
--* Public methods *
--* *
--****************************************************************************/
-----------------------------------------------------------------
-- creates (or resets to) new empty MIDI song
-----------------------------------------------------------------
on new (me,timebase)
if voidP(timebase) then timebase=480
me.pTempo = 0 --125000 = 120 bpm
me.pTimebase = timebase
me.pTracks = []
pLF=chr(10) --
pCR=chr(13) --
return me
end
-----------------------------------------------------------------
-- sets tempo by replacing set tempo msg in track 0 (or adding new track 0)
-----------------------------------------------------------------
on setTempo (me,tempo)
tempo = integer(tempo)
if (NOT voidP(me.pTempoMsgNum)) then
me.pTracks[1][me.pTempoMsgNum] = "0 Tempo "&tempo
else
pTempoTrack = ["0 TimeSig 4/4 24 8","0 Tempo "&tempo,"0 Meta TrkEnd"]
--array_unshift(me.pTracks, pTempoTrack)
tmp=[pTempoTrack]
repeat with i = 1 to count(me.pTracks)
tmp.add(me.pTracks[i])
end repeat
me.pTracks=tmp
me.pTempoMsgNum = 1
end if
me.pTempo = tempo
end
-----------------------------------------------------------------
-- returns tempo (0 if not set)
-----------------------------------------------------------------
on getTempo (me)
return me.pTempo
end
-----------------------------------------------------------------
-- sets tempo corresponding to given bpm
-----------------------------------------------------------------
on setBpm (me,bpm)
tempo = integer(60000000/bpm)
me.setTempo(tempo)
end
-----------------------------------------------------------------
-- returns bpm corresponding to tempo
-----------------------------------------------------------------
on getBpm (me)
if (me.pTempo<>0) then return 60000000/me.pTempo
else return 0
end
-----------------------------------------------------------------
-- sets timebase
-----------------------------------------------------------------
on setTimebase (me,tb)
me.pTimebase = tb
end
-----------------------------------------------------------------
-- returns timebase
-----------------------------------------------------------------
on getTimebase (me)
return me.pTimebase
end
-----------------------------------------------------------------
-- adds new track, returns new track count
-----------------------------------------------------------------
on newTrack (me)
tracks=me.pTracks
tracks.add([])
me.pTracks=tracks
return count(me.pTracks)
end
-----------------------------------------------------------------
-- returns track tn as array of msg strings
-----------------------------------------------------------------
on getTrack (me,tn)
return me.pTracks[tn]
end
-----------------------------------------------------------------
-- returns number of messages of track tn
-----------------------------------------------------------------
on getMsgCount (me,tn)
return count(me.pTracks[tn])
end
-----------------------------------------------------------------
-- adds message to end of track tn
-----------------------------------------------------------------
on addMsg (me,tn, msgStr, ttype) --0:absolute, 1:delta
if voidP(ttype) then ttype=0
track = me.pTracks[tn]
if (ttype=1) then
last = me._getTime(track.getLast())
msg = explode(" ",msgStr)
dt = integer(msg[1])
msg[1] = last + dt
msgStr = implode(" ",msg)
end if
track.add(msgStr)
me.pTracks[tn] = track
end
-----------------------------------------------------------------
-- adds message at adequate position of track n (slower than addMsg)
-----------------------------------------------------------------
on insertMsg (me,tn,msgStr)
time = me._getTime(msgStr)
track = me.pTracks[tn]
mc = count(track)
repeat with i=1 to mc
t = me._getTime(track[i])
if (t>=time) then exit repeat
end repeat
array_splice(me.pTracks[tn], i, 0, msgStr)
end
-----------------------------------------------------------------
-- returns message number mn of track tn
-----------------------------------------------------------------
on getMsg (me,tn,mn)
return me.pTracks[tn][mn]
end
-----------------------------------------------------------------
-- deletes message number mn of track tn
-----------------------------------------------------------------
on deleteMsg (me,tn,mn)
array_splice(me.pTracks[tn], mn, 1)
end
-----------------------------------------------------------------
-- deletes track tn
-----------------------------------------------------------------
on deleteTrack (me,tn)
array_splice(me.pTracks, tn, 1)
return count(me.pTracks)
end
-----------------------------------------------------------------
-- deletes track tn
-----------------------------------------------------------------
on getTrackCount (me)
return count(me.pTracks)
end
-----------------------------------------------------------------
-- deletes all tracks except track tn (and track 1 which contains tempo info)
-----------------------------------------------------------------
on soloTrack (me,tn)
if (tn=1) then me.pTracks = [me.pTracks[1]]
else me.pTracks = [me.pTracks[1],me.pTracks[tn]]
end
-----------------------------------------------------------------
-- transposes song by dn half tone steps
-----------------------------------------------------------------
on transpose (me,dn)
tc = count(me.pTracks)
repeat with i = 1 to tc
transposeTrack(i,dn)
end repeat
end
-----------------------------------------------------------------
-- transposes track tn by dn half tone steps
-----------------------------------------------------------------
on transposeTrack (me,tn, dn)
track = me.pTracks[tn]
mc = count(track)
repeat with i = 1 to mc
msg = explode(" ",track[i])
if (msg[2] = "On" OR msg[2] = "Off") then
do(msg[4]) -- n
n = max(0,min(127,n+dn))
msg[4] = "n=n"
track[i] = join(" ",msg)
end if
end repeat
me.pTracks[tn] = track
end
-----------------------------------------------------------------
-- import whole MIDI song as text (mf2t-format)
-----------------------------------------------------------------
on importTxt (me,txt)
if NOT (txt starts "MFile") then me._err(">>> no valid MIDI text!")
txt = trim(txt)
-- make unix text format
if (txt contains pCR) AND NOT (txt contains pLF) then -- MAC
txt = str_replace(pCR,pLF,txt)
else -- PC?
txt = str_replace(pCR,"",txt)
end if
txt = txt&pLF-- makes things easier
the itemdelimiter=pLF
headerStr = txt.item[1]
header = explode(" ",headerStr) --"MFile type tc pTimebase"
--me.pType = header[2]
me.pTimebase = header[4]
me.pTempo = 0
trackstrings = explode("MTrk"&pLF,txt)
trackstrings.deleteAt(1)
tracks = []
repeat with trackstr in trackstrings
track = explode(pLF,trackstr)
track.deleteAt(track.count)
track.deleteAt(track.count)
if (track[1]="TimestampType=Delta") then--delta
track.deleteAt(1)
track = me._delta2Absolute(track)
end if
tracks.add(track)
end repeat
me.pTracks = tracks
me._findTempo()
end
-----------------------------------------------------------------
-- imports track as text (mf2t-format)
-----------------------------------------------------------------
on importTrackTxt (me,txt, tn)
txt = trim(txt)
-- make unix text format
if (txt contains pCR) AND NOT (txt contains pLF) then -- MAC
txt = str_replace(pCR,pLF,txt)
else -- maybe PC, 0D 0A?
txt = str_replace(pCR,"",txt)
end if
track = explode(pLF,txt)
if (track[1]="MTrk") then track.deleteAt(1)
if (track.getLast()="TrkEnd") then track.deleteAt(track.count)
if (track[1]="TimestampType=Delta") then --delta
track.deleteAt(1)
track = me._delta2Absolute(track)
end if
if voidP(tn) then tn=count(me.pTracks)
me.pTracks[tn] = track
if (tn=0) then me._findTempo()
end
-----------------------------------------------------------------
-- returns MIDI song as text
-----------------------------------------------------------------
on getTxt (me,ttype,ret) --0:absolute, 1:delta
if voidP(ttype) then ttype=0
if voidP(ret) then ret=pLF
timebase = me.pTimebase
tracks = me.pTracks
tc = count(me.pTracks)
type=integer(tc>1)
str = "MFile" && type && tc && timebase &ret
repeat with i=1 to tc
str=str& me.getTrackTxt(i,ttype,ret)
end repeat
return str
end
-----------------------------------------------------------------
-- returns track as text
-----------------------------------------------------------------
on getTrackTxt (me,tn,ttype,ret) --0:absolute, 1:delta
if voidP(ttype) then ttype=0
if voidP(ret) then ret=pLF
track = me.pTracks[tn]
str = "MTrk" &ret
if (ttype=1) then --time as delta
str=str& "TimestampType=Delta" &ret
last = 0
repeat with msg in track
t=integer(msg.word[1])
dt=t-last
delete word 1 of msg
str=str& dt && msg &ret
last = t
end repeat
else
repeat with msg in track
str=str& msg &ret
end repeat
end if
str=str& "TrkEnd" &ret
return str
end
-----------------------------------------------------------------
-- imports Standard MIDI File (typ 0 or 1) (and RMID)
-- (if optional parameter tn set, only track tn is imported)
-----------------------------------------------------------------
on importMid (me,smf_path,tn)
song = readBinFile(smf_path) -- Standard MIDI File, typ 0 or 1, or RMID
if (offset("MThd",song)>1) then delete char 1 to offset("MThd",song)-1 of song -- get rid of RMID header
header = song.char[1..14]
if NOT (header starts "MThd"&chr(0)&chr(0)&chr(0)&chr(6)) then me._err(">>> wrong MIDI-header!")
type = ord(header.char[10])
if (type>1) then me._err(">>> only SMF Typ 0 and 1 supported!")
--trackCnt = ord(header[10])*256 + ord(header[11]) --ignore
timebase = ord(header.char[13])*256 + ord(header.char[14])
--me.pType = type
me.pTimebase = timebase
me.pTempo = 0 -- maybe (hopefully!) overwritten by _parseTrack
trackstrings = explode("MTrk",song)
trackstrings.deleteAt(1)
tracks = []
tsc = count(trackstrings)
if (NOT voidP(tn)) then
if (tn>=tsc) then me._err(">>> SMF has less tracks than "&tn&"!")
tracks.add(me._parseTrack(trackstrings[tn],tn))
else
repeat with i = 1 to tsc
tracks.add(me._parseTrack(trackstrings[i],i))
end repeat
end if
me.pTracks = tracks
end
-----------------------------------------------------------------
-- returns binary MIDI string
-----------------------------------------------------------------
on getMid (me)
pTracks = me.pTracks
tc = count(pTracks)
type = integer(tc > 1)
midStr = "MThd"&chr(0)&chr(0)&chr(0)&chr(6)&chr(0) & chr(type) & me._getBytes(tc,2) & me._getBytes(me.pTimebase,2)
repeat with i = 1 to tc
track = pTracks[i]
mc = count(track)
time = 0
midStr=midStr& "MTrk"
trackstart = length(midStr)
last = ""
repeat with j = 1 to mc
lin = track[j]
t = me._getTime(lin)
dt = t - time
time = t
midStr=midStr& me._writeVarLen(dt)
-- REPETITION: same event, same channel, omit first byte (smaller file size)
str = me._getMsgStr(lin)
start = ord(str.char[1])
if (start=last AND start>=128 AND start<=239) then --239 --159
delete char 1 of str
end if
last = start
midStr=midStr& str
end repeat
trackLen = length(midStr) - trackstart
midStr = midStr.char[1..trackstart] & me._getBytes(trackLen,4) & midStr.char[trackstart+1..length(midStr)] --???
end repeat
return midStr
end
-----------------------------------------------------------------
-- saves MIDI song as Standard MIDI File
-----------------------------------------------------------------
on saveMidFile (me,mid_path)
if (count(me.pTracks)<1) then me._err("MIDI song has no tracks!")
--writeFile(me.getMid(),mid_path)
saveTxtFile(mid_path,me.getMid())
end
--/****************************************************************************
--* *
--* Private methods *
--* *
--****************************************************************************/
-----------------------------------------------------------------
-- returns time code of message string
-----------------------------------------------------------------
on _getTime (me,msgStr)
return integer(msgStr.word[1]) --strtok(msgStr," "))
end
-----------------------------------------------------------------
-- returns binary code for message string
-----------------------------------------------------------------
on _getMsgStr (me,lin){
ch=VOID
p=VOID
n=VOID
v=VOID
c=VOID
msg = explode(" ",lin)
case (msg[2]) of
"PrCh": -- 0x0C
do(msg[3]) -- chan
do(msg[4]) -- prog
return chr(192+ch-1)&chr(p) --0xC0
"On": -- 0x09
do(msg[3]) -- chan
do(msg[4]) -- note
do(msg[5]) -- vel
return chr(144+ch-1)&chr(n)&chr(v)--0x90
"Off": -- 0x08
do(msg[3]) -- chan
do(msg[4]) -- note
do(msg[5]) -- vel
return chr(128+ch-1)&chr(n)&chr(v)--0x80
"PoPr": -- 0x0A = PolyPressure
do(msg[3]) -- chan
do(msg[4]) -- note
do(msg[5]) -- val
return chr(160+ch-1)&chr(n)&chr(v)--0xA0
"Par": -- 0x0B = ControllerChange
do(msg[3]) -- chan
do(msg[4]) -- controller
do(msg[5]) -- val
return chr(176+ch-1)&chr(c)&chr(v)--0xB0
"ChPr": -- 0x0D = ChannelPressure
do(msg[3]) -- chan
do(msg[4]) -- val
return chr(208+ch-1)&chr(v)--0xD0
"Pb": -- 0x0E = PitchBend
do(msg[3]) -- chan
do(msg[4]) -- val (2 Bytes!)
a = v mod 256
b = 64 + (v - a)/128
return chr(224+ch-1)&chr(a)&chr(b)--0xE0
-- META EVENTS
"Seqnr": -- 0x00 = sequence_number
num = chr(msg[3])
return chr(255)&chr(0)&chr(2)&num --"xFFx00x02"&num
"Meta":
type = msg[3]
case (type) of
-- 0x01: Meta Text
-- 0x02: Meta Copyright
-- 0x03: Meta TrackName ???SeqName???
-- 0x04: Meta InstrumentName
-- 0x05: Meta Lyrics
-- 0x06: Meta Marker
-- 0x07: Meta Cue
"Text","Copyright","TrkName","InstrName","Lyric","Marker","Cue":
texttypes = ["Text","Copyright","TrkName","InstrName","Lyric","Marker","Cue"]
byte = chr(texttypes.getPos(type))
start = offset(QUOTE,lin)+1
ende = start+ offset(QUOTE,lin.char[start..length(lin)])-2
txt = lin.char[start..ende]
len = chr(length(txt))
return chr(255)&byte&len&txt --"xFF"
"TrkEnd": --0x2F
return chr(255)&chr(47)&chr(0) --"xFFx2Fx00"
"0x20": -- 0x20 = ChannelPrefix
v = chr(msg[4])
return chr(255)&chr(32)&chr(1)&v --"xFFx20x01"&v
"0x21": -- 0x21 = ChannelPrefixOrPort
v = chr(msg[4])
return chr(255)&chr(33)&chr(01)&v --"xFFx21x01"&v
otherwise:
me._err(">>> unknown meta event:" && type)
halt()
end case
"Tempo": -- 0x51
tempo = me._getBytes(integer(msg[3]),3)
return chr(255)&chr(81)&chr(3)&tempo --"xFFx51x03"&tempo
"SMPTE": -- 0x54 = SMPTE offset
h = chr(msg[3])
m = chr(msg[4])
s = chr(msg[5])
f = chr(msg[6])
fh = chr(msg[7])
return chr(255)&chr(84)&chr(5) &h&m&s&f&fh --"xFFx54x05"
"TimeSig": -- 0x58
zt = explode("/",msg[3])
z = chr(zt[1])
t = chr(log(integer(zt[2]))/log(2))
mc = chr(msg[4])
c = chr(msg[5])
return chr(255)&chr(88)&chr(4) &z&t&mc&c --"xFFx58x04"
"KeySig": -- 0x59
vz = chr(msg[3])
g = chr(integer(msg[4]<>"major"))
return chr(255)&chr(89)&chr(2) &vz&g --"xFFx59x02"
"SeqSpec": -- 0x7F = Sequencer specific data (eg: 0 SeqSpec 00 00 41)
cnt = count(msg)-2
data = ""
repeat with i = 1 to cnt
data=data& me._hex2bin(msg[i+2])
end repeat
len = chr(length(data))
return chr(255)&chr(127) &len&data --"xFFx7F"
"SysEx": -- 0xF0 = SysEx
start = offset("f0",lin)+3
ende = start+offset("f7",lin.char[start..length(lin)-1])
data = lin.char[start..ende]
data = me._hex2bin(str_replace(" ","",data))
len = chr(length(data))
return chr(240) &len&data --"xF0"
otherwise:
me._err(">>> unknown event: "&msg[2])
halt()
end case
end
-----------------------------------------------------------------
-- converts binary track string to track (list of msg strings)
-----------------------------------------------------------------
on _parseTrack (me,binStr, tn)
trackLen = length(binStr)
p=4 +1
time = 0
track = []
last=""
repeat while (p
-- timedelta
a=[p]
dt = me._readVarLen(binStr,a)
p=a[1]
time=time+ dt
byte = ord(binStr.char[p])
--high = byte >> 4
high = byte/16
low = byte - high*16
case (high) of
8: --0x08: --Off
chan = low+1
note = ord(binStr.char[p+1])
vel = ord(binStr.char[p+2])
last = "Off"
track.add(time && "Off ch="&chan&" n="¬e&" v="&vel)
p=p+3
9: --0x09: --On
chan = low+1
note = ord(binStr.char[p+1])
vel = ord(binStr.char[p+2])
last = "On"
track.add(time && "On ch="&chan&" n="¬e&" v="&vel)
p=p+3
10: --0x0A: --PoPr = PolyPressure
chan = low+1
note = ord(binStr.char[p+1])
val = ord(binStr.char[p+2])
last = "PoPr"
track.add(time && "PoPr ch="&chan&" n="¬e&" v="&val)
p=p+3
11: --0x0B: --Par = ControllerChange
chan = low+1
c = ord(binStr.char[p+1])
val = ord(binStr.char[p+2])
last = "Par"
track.add(time && "Par ch="&chan&" c="&c&" v="&val)
p=p+3
12: --0x0C: --PrCh = ProgramChange
chan = low+1
prog = ord(binStr.char[p+1])
last = "PrCh"
track.add(time && "PrCh ch="&chan&" p="&prog)
p=p+2
13: --0x0D: --ChPr = ChannelPressure
chan = low+1
val = ord(binStr.char[p+1])
last = "ChPr"
track.add(time && "ChPr ch="&chan&" v="&val)
p=p+2
14: --0x0E: --Pb = PitchBend
chan = low+1
val = ord(binStr.char[p+1]) + (ord(binStr.char[p+2])-64)*128
last = "Pb"
track.add(time &&"Pb ch="&chan&" v="&val)
p=p+3
otherwise:
case (byte) of
255: --0xFF: -- Meta
meta = ord(binStr.char[p+1])
case (meta) of
0: --0x00: -- sequence_number
num = ord(binStr.char[p+2])
track.add(time && "Seqnr "&num)
p=p+2
1,2,3,4,5,6,7:
texttypes = ["Text","Copyright","TrkName","InstrName","Lyric","Marker","Cue"]
type = texttypes[meta]
len = ord(binStr.char[p+2])
txt = binStr.char[p+3..p+3+len-1]
track.add(time && "Meta "&type &"E&txt"E)
p=p+len+3
32: --0x20: -- ChannelPrefix
chan = ord(binStr.char[p+3])
if (chan<10) then chan = "0"&chan--???
track.add(time && "Meta 0x20 "&chan)
p=p+4
33: --0x21: -- ChannelPrefixOrPort
chan = ord(binStr.char[p+3])
if (chan<10) then chan = "0"&chan--???
track.add(time && "Meta 0x21 "&chan)
p=p+4
47: --0x2F: -- Meta TrkEnd
track.add(time && "Meta TrkEnd")
return track--ignore rest
--p+=3
81: --0x51: -- Tempo
tempo = ord(binStr.char[p+3])*256*256 + ord(binStr.char[p+4])*256 + ord(binStr.char[p+5])
track.add(time && "Tempo "&tempo)
if (tn=0 AND time=0) then
me.pTempo = tempo-- ???
me.pTempoMsgNum = count(track) - 1
end if
p=p+6
84: --0x54: -- SMPTE offset
h = ord(binStr.char[p+3])
m = ord(binStr.char[p+4])
s = ord(binStr.char[p+5])
f = ord(binStr.char[p+6])
fh = ord(binStr.char[p+7])
track.add(time && "SMPTE"&&h&&m&&s&&f&&fh)
p=p+8
88: --0x58: -- TimeSig
z = ord(binStr.char[p+3])
t = integer(power(2,ord(binStr.char[p+4])))
mc = ord(binStr.char[p+5])
c = ord(binStr.char[p+6])
track.add(time && "TimeSig "&z&"/"&t&&mc&&c)
p=p+7
89: --0x59: -- KeySig
vz = ord(binStr.char[p+3])
g = ["major","minor"][2-(ord(binStr.char[p+4])=0)]
track.add(time && "KeySig" && vz && g)
p=p+5
127: --0x7F: -- Sequencer specific data (string or hexString???)
len = ord(binStr.char[p+2])
data=""
repeat with i = p+3 to p+3+len-1
data=data& " "&int2hex(ord(binStr.char[i]))
end repeat
track.add(time && "SeqSpec"& data)
p=p+len+3
otherwise:
me._err(">>> unknown meta event:" && time && byte && meta)
end case -- Ende Meta
240: --0xF0: -- SysEx
len = ord(binStr.char[p+1])
str = "f0"
repeat with i=1 to len
str=str && strtolower(int2hex(ord(binStr.char[p+2+i])))
end repeat
track.add(time && "SysEx "&str)
p=p+len+2
otherwise: --Repetition of last event?
case (last) of
"On","Off":
note = ord(binStr.char[p])
vel = ord(binStr.char[p+1])
track.add(time && last && "ch="&chan&" n="¬e&" v="&vel)
p=p+2
"PoPr":
note = ord(binStr.char[p+1])
val = ord(binStr.char[p+2])
track.add(time && "PoPr ch="&chan&" n="¬e&" v="&val)
p=p+2
"ChPr":
val = ord(binStr.char[p])
track.add(time && "ChPr ch="&chan&" v="&val)
p=p+1
"Par":
c = ord(binStr.char[p])
val = ord(binStr.char[p+1])
track.add(time && "Par ch="&chan&" c="&c&" v="&val)
p=p+2
"Pb":
val = ord(binStr.char[p])+ ord(binStr.char[p+1])*128
track.add(time && "Pb ch="&chan&" v="&val)
p=p+2
--test
"PrCh": --0x0C: --PrCh = ProgramChange
prog = ord(binStr.char[p])
track.add(time && "PrCh ch="&chan&" p="&prog)
p=p+1
otherwise:
me._err(">>> unknown repetition:" && last) --???
end case
end case
end case
end repeat
return track
end
-----------------------------------------------------------------
-- search track 0 for set tempo msg
-----------------------------------------------------------------
on _findTempo (me)
track = me.pTracks[1]
mc = count(track)
repeat with i=1 to mc
msg = explode(" ",track[i])
if (integer(msg[1])>0) then exit repeat
if (msg[2]="Tempo") then
me.pTempo = msg[3]
me.pTempoMsgNum = i
exit repeat
end if
end repeat
end
--***************************************************************
-- UTILITIES
--***************************************************************
-----------------------------------------------------------------
-- hexstr to binstr
-----------------------------------------------------------------
on _hex2bin (me,hex_str)
bin_str=""
l=length(hex_str)/2-1
repeat with i = 0 to l
bin_str=bin_str& chr(hexdec(hex_str.char[i*2+1..i*2+2]))
end repeat
return bin_str
end
-----------------------------------------------------------------
-- int to bytes (length len)
-----------------------------------------------------------------
on _getBytes (me,n,len)
str=""
repeat with i = len-1 down to 0
str=str& chr(floor(n/power(256,i)))
end repeat
return str
end
-----------------------------------------------------------------
-- variable length string to int (+repositioning)
-----------------------------------------------------------------
on _readVarLen (me,str,posArray) --&pos !!!
pos=posArray[1]
value=ord(str.char[pos])
pos=pos +1
if bitAnd(value,128) then
value=bitAnd(value,127)
repeat while TRUE
c = ord(str.char[pos])
pos=pos +1
value = value*128 + bitAnd(c,127)
if NOT bitAnd(c,128) then exit repeat
end repeat
end if
posArray[1]=pos
return (value)
end
-----------------------------------------------------------------
-- int to variable length string
-----------------------------------------------------------------
on _writeVarLen (me,value)
buf = bitAnd(value,127)
str=""
repeat while (value/128>0)
value=value/128
buf=buf*256
buf = bitOr(buf, bitOr(bitAnd(value,127),128))
end repeat
repeat while TRUE
str=str& chr(buf mod 256)
if bitAnd(buf,128) then buf=buf/256
else exit repeat
end repeat
return str
end
-----------------------------------------------------------------
-- converts all delta times in track to absolute times
-----------------------------------------------------------------
on _delta2Absolute (me,track)
mc = count(track)
last = 0
repeat with i=1 to mc
msg=track[i]
t=last+integer(msg.word[1])
delete word 1 of msg
track[i]=t && msg
last=t
end repeat
return track
end
-----------------------------------------------------------------
-- error message
-----------------------------------------------------------------
on _err (me,str)
--die(str)
cursor(-1)
alert(str)
abort()
end
|
|