VERY messy BlitzBasic code, uncleaned before posting. I didn't know what I was doing when I coded this, the fact it worked for my purpose was a miracle
It may be good enough for you to make a start with :-)
the includes are my sound system,
Graphics 640,480,16,2
Global chans=50
Global maxlength=10240*2
Global Notes=512
Dim Frst(chans)
Dim started(chans,Notes)
Dim status(chans,Notes)
Dim con(Notes)
Dim counter(Notes)
Global add
Global Mididelta[4]
; The header chunk appears at the beginning of the file, And describes the
;file in three ways. The header chunk always looks like:
;
;4D 54 68 64 00 00 00 06 ff ff nn nn dd dd
;
;The ascii equivalent of the First 4 bytes is MThd. After MThd comes the 4-byte
;size of the header. This will always be 00 00 00 06, because the actual header
;information will always be 6 bytes.
;
;ff ff is the file format. There are 3 formats:
;
;0 - single-track
;1 - multiple tracks, synchronous
;2 - multiple tracks, asynchronous
;
;Single track is fairly self-explanatory - one track only. Synchronous multiple
;tracks means that the tracks will all be vertically synchronous, Or in other
;words, they all start at the same time, And so can represent different parts
;in one song. Asynchronous multiple tracks do Not necessarily start at the same
;time, And can be completely asynchronous.
;
;nn nn is the number of tracks in the midi file.
;
;dd dd is the number of delta-time ticks per quarter note. (More about this
;later)
fs=OpenFile("potc2.mid")
head$=Readhead(fs)
Print head$
head2=ReadmInt(fs)
Format=ReadmShort(fs)
tracks=Readmshort(fs)
timeticks=Readmshort(fs)
Print "File is of format "+Format
Print tracks+" tracks in file..."
;3. Track Chunks
;
;The remainder of the file After the header chunk consists of track chunks.
;Each track has one header And may contain as many midi commands as you like.
;The header For a track is very similar To the one For the file:
;
;4D 54 72 6B xx xx xx xx
;
;As with the header, the First 4 bytes has an ascii equivalent. This one is
;MTrk. The 4 bytes After MTrk give the length of the track (Not including the
;track header) in bytes.
;Following the header are midi events. These events are identical To the
;actual Data sent And received by MIDI ports on a synth with one addition. A
;midi event is preceded by a delta-time. A delta time is the number of ticks
;After which the midi event is To be executed. The number of ticks per quarter
;note was defined previously in the file header chunk. This delta-time is a
;variable-length encoded value. This format, While confusing, allows large
;numbers To use as many bytes as they need, without requiring small numbers To
;waste bytes by filling with zeros. The number is converted into 7-bit bytes,
;And the most-significant bit of Each byte is 1 except For the Last byte of the
;number, which has a msb of 0. This allows the number To be Read one byte at a
;time, And when you see a msb of 0, you know that it was the Last (least
;significant) byte of the number. According To the MIDI spec, the entire delta-
;time should be at most 4 bytes long.
; Following the delta-time is a midi event. Each midi event (except a
;running midi event) has a command byte which will always have a msb of 1 (the
;value will be >= 128). A list of most of these commands is in appendix A. Each
;command has different parameters And lengths, but the Data that follows the
;command will have a msb of 0 (less than 128). The exception To this is a meta-
;event, which may contain Data with a msb of 1. However, meta-events require a
;length parameter which alleviates confusion.
;One subtlety which can cause confusion is running mode. This is where
;the actual midi command is omitted, And the Last midi command issued is
;assumed. This means that the midi event will consist of a delta-time And the
;parameters that would go To the command If it were included.
Global fs2=WriteFile("mariomusic.bb")
chantime=0
std=0
Cls
For n=0 To chans
frst(n)=1
Next
For Midchan=1 To tracks
fst=1
counter(Midchan)=0
t2=counter(Midchan)
addc=0
head$=Readhead$(fs)
Print head$
Length=ReadmInt(fs)
add=0
ldt=0
Timer=0
fintrack=0
Repeat
;byte=readbyte2(fs)
;Repeat
;byte=readbyte2(fs)
;Until byte<128 Or KeyDown(1)
ldt=dt
dt=getdeltatime(fs)
;If dt>timeticks*64 Then dt=0
adt=dt
;If dt>1500 Then dt=dt/4.0
;If dt<>0 Then Print dt
ocmd=cmd
cmd=readbyte2(fs)
If cmd<128 Then ;running mode
cmd=ocmd
add=add-1
SeekFile(fs,FilePos(fs)-1)
;counter(channel)=counter(channel)+adt
EndIf
command=getcommand(cmd)
If cmd=255 Then ;meta command
xx=ReadByte2(fs)
;Print "Meta command! type: "+xx
nn=ReadByte2(fs)
If xx=47 And nn=00 Then fintrack=1
For nvt=1 To nn:n2=ReadByte2(fs):Next
EndIf
channel=(getchannel(cmd))+Midchan*3
channel=getchannel(cmd)
;'channel=Midchan
;channel=Midchan
cn=channel;Midchan
t2=counter(cn)
fst=frst(channel)
cmdn=0
ac=0
If command>127 Then ac=1
;och=channel
;channel=channel+addc
If (command=128 Or command=128+16) And (dt>-1 Or fst=1) Then
note=ReadByte2(fs)
vl=ReadByte2(fs)
;Print Note+" "+vl+" "+chanel
Note2=16
DN=0
If Note>0 And Note<Notes Then;dt=0:t2=0
If command=128+16 And vl>0 And status(channel,Note2)=0 Then
cmdn=1
DN=1
addnote channel,Note,((t2+adt)-started(channel,Note2))*timeticks,status(channel,Note2):addc=addc+1
;If status(channel,note)=0 Then
started(channel,Note2)=t2+adt
status(channel,Note2)=1
EndIf
If ((((command=128+16 And vl=0) Or command=128) And dn=0) And status(channel,Note2)=1) Or fintrack=1 Then ;note off routine
DN=2
cmdn=1
;If channel=3 Then
Line STARTED(CHANNEL,NotE2)*.05,200-NotE,(T2+(t2+adt)-started(channel,Note2))*.05,200-NotE
addnote channel,Note,((t2+adt)-started(channel,Note2))*timeticks,status(channel,Note2):addc=addc-1
started(channel,Note2)=(t2+adt)
status(channel,Note2)=0
EndIf
;och=channel
;channel=och
If adt>0 And fst=1 Then fst=0
;If dn>0 And fst=1 Then fst=0
frst(channel)=fst
;If ac=1 Then
;updatesnd
;If command=128+16 Then grid(t2+dt,channel,1)=note
;If command=128+16 And vl=0 Then grid(t2+dt,channel,1)=-Note
;If command=128 Then grid(t2+dt,channel,1)=-Note
;Repeat
;sk=SeekFile(fs,FilePos(fs)-1)
;bt=ReadByte(fs)
;sk=SeekFile(fs,FilePos(fs)-1)
;If KeyDown(1) Then End
;Until bt>127
EndIf
;WriteLine fs2,"Data "+channel+","+Str$(Float(vl)/Float(64.0))+","+Note*4+","+ln1
; Print command+" "+channel+" "+cmd
EndIf
If fst=0 Then counter(cn)=counter(cn)+adt
;If command=
;Print add+"!"
If KeyDown(1) Then End
;timer=timer+timeticks
Until add>=Length Or Eof(fs) Or Ed=1
If add>length Then sk=SeekFile(fs,FilePos(fs)-(add-Length))
Next
Print "done!"
Repeat
Until KeyDown(1)
End
Cls
Function getchannel(byte)
Return byte And 15
End Function
Function getcommand(byte)
Return byte And (16+32+64+128)
End Function
Function Readmshort(fs)
Return (readbyte2(fs)*256)+readbyte2(fs)
End Function
Function Readmint(fs)
Return (readbyte2(fs)*256*256*256)+(readbyte2(fs)*256*256)+(readbyte2(fs)*256)+(readbyte2(fs))
End Function
Function getdeltatime(fs)
Local ok=0,bt,n
;SeekFile(fs,FilePos(fs)-1):add=add-1
;Repeat:bt=ReadByte2(fs):Until bt>127 Or KeyDown(1) Or Eof(fs)
;SeekFile(fs,FilePos(fs)-1):add=add-1
;bt=ReadByte2(fs)
;Print "---"
For n=1 To 4
mididelta[n]=0
Next
For n=1 To 4
n2%=readbyte2(fs)
n3=n2 And 128
Mididelta[n]=n2:If n2>128 Then n2=n2-128
If n3<128 Then ct=n:n=50
;Print n2+" "+n3+" !!!"
;Print Hex$(n2)
Next
;If n3>127 Then n2=n2-128
;time=(Mididelta[4]*256*256*256)+(Mididelta[3]*256*256)+(Mididelta[2]*256)+(Mididelta[1])
time=(Mididelta[4]*128*128*128)+(Mididelta[3]*128*128)+(Mididelta[2]*128)+(Mididelta[1])
;If time<>0 Then Print time:WaitKey
Return time
End
n=1
Repeat
mididelta[n]=readbyte2(fs)
ok=Abs(Sgn(Mididelta[n] And 128))
If ok=0 Then Mididelta[n]=Mididelta[n]-128;If mididelta[n]>127 Then ok=1:Mididelta[n]=Mididelta[n] And 127
;Print n
n=n+1
Until KeyDown(1) Or Eof(fs) Or ok=1 Or n>4
n=n-1
time=(Mididelta[4]*256*256*256)+(Mididelta[3]*256*256)+(Mididelta[2]*256)+(Mididelta[1])
;time=(Mididelta[1]*256*256*256)+(Mididelta[2]*256*256)+(Mididelta[3]*256)+(Mididelta[4])
Return time
End Function
Function Readhead$(fs)
Local m$="",n,o
For n=1 To 4
o=readbyte2(fs)
m$=m$+Chr$(o)
Next
Return m$
End Function
Function ReadByte2(fs)
add=add+1
Return ReadByte(fs)
End Function
Function HexToDec (h$)
If Left (h$, 1) = "%" Then h$ = Right (h$, Len (h$) - 1)
h$ = Upper (h$)
For r=1 To Len (h$)
d = d Shl 4: a$ = Mid (h$, r, 1)
If Asc (a$) > 60
d = d + Asc (a$) - 55
Else
d = d + Asc (a$) - 48
EndIf
Next
Return d
End Function
Function addnote(channel,Note,Length#,vol#)
;Length=Int(Length/5.0)*5.0
Note=Note-12*2
;If Length>30000 Then Length=0
;Length=Length*.25
If Length>0 Then
If vol>0 Then WriteLine fs2,"Data "+channel+","+vol+","+Note*4+","+Length;+","+time
If vol=0 Then WriteLine fs2,"Data "+channel+","+vol+","+Note*4+","+Length;+","+time
EndIf
End Function
|