OPTIONS "C_CALL LABELCHECK NOSOURCE"
LIBRARY rexxgui, rxmidi
midierr = "ERROR"
guierr = "SYNTAX"
guiheading = 1
guicreatewindow('NORMAL')
tofilename = ""
fromfilename = ARG(1)
IF fromfilename \== "" THEN convertmidi()
again:
DO FOREVER
guigetmsg()
CATCH NOTREADY
CONDITION('M')
SIGNAL again
CATCH ERROR
CONDITION('M')
SIGNAL again
CATCH SYNTAX
CONDITION('M')
SIGNAL again
FINALLY
guidestroywindow()
END
RETURN
wm_click_pickbutton:
IF tofilename \== "" THEN DO
tofilename = ""
guiaddctltext("PickButton", "Aborting...")
RETURN
END
DO
guifile('FromFilename', 'EXISTING', 'Select a text file to convert to MIDI', 'Text files (*.txt) | *.txt | All files (*.*) | *.*')
CATCH SYNTAX
IF CONDITION('D') \== "CANCEL" THEN guisay(CONDITION('D'))
RETURN
END
convertmidi:
tofilename = EDITNAME(fromfilename, "*.mid", "U")
linenum = 0
DO
guiaddctltext("PickButton", "Loading...")
STREAM(fromfilename, 'C', 'OPEN READ')
DO UNTIL POS("MThd |", line) \== 0 | POS("MThd|", line) \== 0
linenum = linenum + 1
line = LINEIN(fromfilename)
CATCH NOTREADY
guisay("No MThd line!")
RETURN
END
PARSE VAR line . "Format=" FORMAT "|" "# of Tracks=" tracks "|" "Division=" division
IF DATATYPE(format) \== 'NUM' THEN DO
guisay("MThd Format must be numeric!")
RETURN
END
IF DATATYPE(tracks) \== 'NUM' THEN DO
guisay("# of Tracks must be numeric!")
RETURN
END
IF DATATYPE(division) \== 'NUM' THEN DO
guisay("MThd Division must be numeric!")
RETURN
END
IF tracks > 1 & FORMAT == 0 THEN DO
guisay("Format 0 can't have more than 1 track!")
RETURN
END
MIDIOpenFile(, division)
DO tracknum = 1 TO tracks
DO UNTIL POS("Track #", line) \== 0
linenum = linenum + 1
line = LINEIN(fromfilename)
CATCH NOTREADY
guisay('Contains less than' tracks 'tracks!')
RETURN
END
measure = ""
beat = ""
clock = ""
pitch = 60
velocity = 0
midievent.!channel = 0
press = 0
ctlnum = 0
hour = 0
MIN = 0
frame = 0
sec = 0
subs = 0
PARSE = 1
guigetmsg('CLEAR')
IF tofilename == "" THEN RETURN
DO UNTIL midievent.!type == 47
IF PARSE == 1 THEN DO
DO UNTIL POS("|", line) \== 0
linenum = linenum + 1
line = LINEIN(fromfilename)
END
CATCH NOTREADY
guisay('Missing End of Track event at line' linenum)
RETURN
END
PARSE = 1
line = TRANSLATE(line, ' ', '09'x)
PARSE VAR line data '|' type '|' remaining
PARSE VAR data midievent.!measure ':' midievent.!beat ':' midievent.!clock
midievent.!measure = STRIP(midievent.!measure)
midievent.!beat = STRIP(midievent.!beat)
midievent.!clock = STRIP(midievent.!clock)
IF midievent.!clock == "" THEN DO
midievent.!clock = midievent.!beat
midievent.!beat = midievent.!measure
midievent.!measure = measure
END
IF midievent.!clock == "" THEN DO
midievent.!clock = midievent.!beat
midievent.!beat = beat
END
IF midievent.!clock == "" THEN midievent.!clock = clock
clock = midievent.!clock
beat = midievent.!beat
measure = midievent.!measure
IF clock == "" | beat == "" | measure == "" THEN
RAISE ERROR 100 DESCRIPTION 'Missing time component'
IF type = "" THEN
RAISE ERROR 100 DESCRIPTION 'Missing event type'
IF DATATYPE(type) \== 'NUM' THEN midievent.!type = MIDIEventProp(, type)
ELSE midievent.!type = type
IF MIDIEventProp('CHAN', midievent.!type) == "YES" THEN DO
IF POS("chan=", remaining) \= 0 THEN PARSE VAR remaining 'chan=' midievent.!channel .
IF MIDIEventProp('FREQ', midievent.!type) == "YES" THEN DO
offset = POS("pitch=", remaining)
IF offset \== 0 THEN DO
pitch = SUBSTR(remaining, offset + 6)
offset = POS("|", pitch)
IF offset > 1 THEN pitch = LEFT(pitch, offset - 1)
IF DATATYPE(pitch) \== 'NUM' THEN pitch = MIDINoteNum(pitch)
END
midievent.!data1 = pitch
IF MIDIEventProp('NOTE', midievent.!type) == "YES" THEN DO
IF POS("vol=", remaining) \= 0 THEN DO
PARSE VAR remaining 'vol=' velocity .
midievent.!data2 = velocity
END
ELSE DO
IF LEFT(type, 4) == "(Off" THEN midievent.!data2 = 0
ELSE midievent.!data2 = velocity
END
END
ELSE DO
IF POS("press=", remaining) \== 0 THEN
PARSE VAR remaining 'press=' press .
midievent.!data2 = press
END
END
ELSE SELECT midievent.!type
WHEN 176 THEN DO
IF POS("value=", remaining) == 0 THEN RAISE ERROR 100 DESCRIPTION 'Missing value'
PARSE VAR remaining 'value=' midievent.!data2 '|' .
offset = POS("contr=", remaining)
IF offset \== 0 THEN DO
ctlnum = SUBSTR(remaining, offset + 6)
offset = POS("|", ctlnum)
IF offset > 1 THEN ctlnum = LEFT(ctlnum, offset - 1)
IF DATATYPE(ctlnum) \== 'NUM' THEN ctlnum = MIDICtlNum(ctlnum)
END
midievent.!data1 = ctlnum
END
WHEN 192 THEN DO
offset = POS("pgm #=", remaining)
IF offset == 0 THEN RAISE ERROR 100 DESCRIPTION 'Missing program number'
midievent.!data1 = SUBSTR(remaining, offset + 6)
offset = POS("|", midievent.!data1)
IF offset > 1 THEN midievent.!data1 = LEFT(midievent.!data1, offset - 1)
IF DATATYPE(midievent.!data1) \== 'NUM' THEN midievent.!data1 = MIDIGetGMPgm(STRIP(midievent.!data1))
ELSE midievent.!data1 = midievent.!data1 - 1
END
WHEN 208 THEN DO
IF POS("press=", remaining) \== 0 THEN
PARSE VAR remaining 'press=' press .
midievent.!data1 = press
END
WHEN 224 THEN DO
IF POS("bend=", remaining) = 0 THEN RAISE ERROR 100 DESCRIPTION 'Missing bend value'
PARSE VAR remaining 'bend=' midievent.!data3 .
END
END
END
ELSE DO
IF midievent.!type >= 240 THEN DO
IF (midievent.!type < 248 & midievent.!type \= 246) | midievent.!type = 255 | midievent.!type = 257 THEN DO
IF midievent.!type <= 243 & midievent.!type \= 240 THEN DO
PARSE VAR remaining midievent.!data1 .
END
ELSE parsetext()
END
END
ELSE SELECT midievent.!type
WHEN 0 THEN
PARSE VAR remaining midievent.!data1 .
WHEN 32 THEN
PARSE VAR remaining midievent.!data1 .
WHEN 33 THEN
PARSE VAR remaining midievent.!data1 .
WHEN 47 THEN NOP
WHEN 81 THEN DO
PARSE VAR remaining 'micros\quarter=' midievent.!data1 .
IF midievent.!data1 = "" THEN DO
PARSE VAR remaining 'BPM=' midievent.!data2 .
IF midievent.!data2 = "" THEN RAISE ERROR 100 DESCRIPTION 'Missing tempo'
END
END
WHEN 84 THEN DO
PARSE VAR remaining 'hour=' midievent.!data1 .
IF midievent.!data1 = "" THEN midievent.!data1 = hour
PARSE VAR remaining 'min=' midievent.!data2 .
IF midievent.!data2 = "" THEN midievent.!data2 = MIN
PARSE VAR remaining 'sec=' midievent.!data3 .
IF midievent.!data3 = "" THEN midievent.!data3 = sec
PARSE VAR remaining 'frame=' midievent.!data4 .
IF midievent.!data4 = "" THEN midievent.!data4 = frame
PARSE VAR remaining 'subs=' midievent.!data5 .
IF midievent.!data5 = "" THEN midievent.!data5 = subs
END
WHEN 88 THEN DO
PARSE VAR remaining midievent.!data1 '/' midievent.!data2 .
DO UNTIL offset = 0
offset = POS("|", midievent.!data1)
IF offset \= 0 THEN PARSE VAR midievent.!data1 '|' midievent.!data1
END
IF DATATYPE(midievent.!data1) \= "NUM" | DATATYPE(midievent.!data2) \== "NUM" THEN RAISE ERROR 100 DESCRIPTION 'Missing time signature'
PARSE VAR remaining 'MIDI-clocks\click=' midievent.!data3 .
PARSE VAR remaining '32nds\quarter=' midievent.!data4 .
END
WHEN 89 THEN DO
offset = POS("|", remaining)
IF offset \= 0 THEN PARSE VAR remaining remaining '|' .
midievent.!data3 = remaining
END
OTHERWISE parsetext()
END
END
MIDISetEvent('INS|TIME|CHAN|DATA', tracknum)
END
CATCH ERROR
guisay("MIDI ERROR at line" linenum || ':' CONDITION('D'))
RETURN
END
FINALLY
STREAM(fromfilename, 'C', 'CLOSE')
MIDISaveFile(tofilename)
guiaddctltext("PickButton", "Pick file")
guiaddctltext('Message', 'Done converting' TRANSLATE(tofilename, "/", "\"))
tofilename = ""
END
RETURN
parsetext:
PARSE = 0
origlinenum = linenum
midievent.!data1 = ""
DO FOREVER
linenum = linenum + 1
line = STRIP(LINEIN(fromfilename))
offset2 = POS("<", line)
offset = POS("|", line)
IF offset \== 0 THEN DO
IF offset2 == 0 | offset2 > offset THEN
RETURN
END
IF offset2 == 1 THEN DO
offset = LASTPOS(">", line)
IF offset == 0 THEN offset = LENGTH(line)
IF offset < 2 THEN offset = 2
midievent.!data1 = midievent.!data1 || SUBSTR(line, 2, offset - 2)
END
ELSE DO
PARSE VAR line data line
data = STRIP(data)
DO WHILE data \== "" & LEFT(data, 1) \== '<'
IF LEFT(data, 2) == '0x' THEN
midievent.!data1 = midievent.!data1 || X2C(DELSTR(data, 1, 2))
ELSE midievent.!data1 = midievent.!data1 || D2C(data)
PARSE VAR line data line
data = STRIP(data)
END
END
CATCH NOTREADY
linenum = origlinenum
RAISE ERROR 100 DESCRIPTION 'Possible run-on event'
END
RETURN |
|