03-11-2025, 08:52 PM
Actually the last answer wasn't fully complete, one of the routines was left empty with a comment "(MidiToText subroutine as provided previously)".
Here is the full code with the missing routine added back in:
Here is the full code with the missing routine added back in:
Code: (Select All)
' Requires file access permissions
DECLARE LIBRARY "winmm.dll"
' No winmm functions used, but keeping it in case you want to add MIDI playback
END DECLARE LIBRARY
TYPE MIDIHDR
MThd$
Length&
Format%
Tracks%
Division%
END TYPE
TYPE MIDITRACK
MTrk$
Length&
Events$
END TYPE
TYPE MIDIEVENT
DeltaTime&
Status%
Data1%
Data2%
END TYPE
FUNCTION ReadVariableLength& (data$, offset&)
DIM value&, byte%
value& = 0
DO
byte% = ASC(MID$(data$, offset&, 1))
value& = (value& * 128) + (byte% AND 127)
offset& = offset& + 1
LOOP WHILE (byte% AND 128) <> 0
ReadVariableLength& = value&
END FUNCTION
FUNCTION WriteVariableLength$ (value&)
DIM bytes$(1 TO 4), numBytes%, i%
IF value& = 0 THEN
WriteVariableLength$ = CHR$(0)
EXIT FUNCTION
END IF
numBytes% = 0
DO
numBytes% = numBytes% + 1
bytes$(numBytes%) = CHR$(value& AND 127)
value& = value& \ 128
LOOP WHILE value& > 0
FOR i% = numBytes% - 1 TO 1 STEP -1
bytes$(i%) = CHR$(ASC(bytes$(i%)) OR 128)
NEXT i%
FOR i% = 1 TO numBytes%
WriteVariableLength$ = WriteVariableLength$ + bytes$(i%)
NEXT i%
END FUNCTION
SUB MidiToText (midiFilePath$, textFilePath$)
DIM fileHandle&, fileSize&, midiData$, header AS MIDIHDR, tracks(1 TO 256) AS MIDITRACK, trackCount%, offset&, eventOffset&, event AS MIDIEVENT, textFileHandle&
DIM eventData$
fileHandle& = _OPEN(midiFilePath$, _OPENEXISTING, _OPENBINARY)
IF fileHandle& = 0 THEN
PRINT "Error opening MIDI file."
EXIT SUB
END IF
fileSize& = LOF(fileHandle&)
midiData$ = SPACE$(fileSize&)
_GET fileHandle&, midiData$
_CLOSE fileHandle&
header.MThd$ = MID$(midiData$, 1, 4)
header.Length& = (ASC(MID$(midiData$, 5, 1)) * 256 * 256 * 256) + (ASC(MID$(midiData$, 6, 1)) * 256 * 256) + (ASC(MID$(midiData$, 7, 1)) * 256) + ASC(MID$(midiData$, 8, 1))
header.Format% = (ASC(MID$(midiData$, 9, 1)) * 256) + ASC(MID$(midiData$, 10, 1))
header.Tracks% = (ASC(MID$(midiData$, 11, 1)) * 256) + ASC(MID$(midiData$, 12, 1))
header.Division% = (ASC(MID$(midiData$, 13, 1)) * 256) + ASC(MID$(midiData$, 14, 1))
offset& = 15
FOR trackCount% = 1 TO header.Tracks%
tracks(trackCount%).MTrk$ = MID$(midiData$, offset&, 4)
tracks(trackCount%).Length& = (ASC(MID$(midiData$, offset& + 4, 1)) * 256 * 256 * 256) + (ASC(MID$(midiData$, offset& + 5, 1)) * 256 * 256) + (ASC(MID$(midiData$, offset& + 6, 1)) * 256) + ASC(MID$(midiData$, offset& + 7, 1))
tracks(trackCount%).Events$ = MID$(midiData$, offset& + 8, tracks(trackCount%).Length&)
offset& = offset& + 8 + tracks(trackCount%).Length&
NEXT trackCount%
textFileHandle& = _OPEN(textFilePath$, _OPENCREATE, _OPENOUTPUT)
IF textFileHandle& = 0 THEN
PRINT "Error creating text file."
EXIT SUB
END IF
PRINT #textFileHandle&, "Track" + CHR$(9) + "DeltaTime" + CHR$(9) + "Status" + CHR$(9) + "Data1" + CHR$(9) + "Data2"
FOR trackCount% = 1 TO header.Tracks%
eventOffset& = 1
DO WHILE eventOffset& <= LEN(tracks(trackCount%).Events$)
event.DeltaTime& = ReadVariableLength&(tracks(trackCount%).Events$, eventOffset&)
eventOffset& = eventOffset& + LEN(WriteVariableLength$(event.DeltaTime&))
event.Status% = ASC(MID$(tracks(trackCount%).Events$, eventOffset&, 1))
eventOffset& = eventOffset& + 1
IF event.Status% < &HF0 THEN
event.Data1% = ASC(MID$(tracks(trackCount%).Events$, eventOffset&, 1))
event.Data2% = ASC(MID$(tracks(trackCount%).Events$, eventOffset& + 1, 1))
eventOffset& = eventOffset& + 2
ELSEIF event.Status% = &HFF THEN
'Meta event: handle as needed. This simple version skips metadata.
DIM metaType%, metaLength&
metaType% = ASC(MID$(tracks(trackCount%).Events$, eventOffset&, 1))
eventOffset& = eventOffset& +1
metaLength& = ReadVariableLength&(tracks(trackCount%).Events$, eventOffset&)
eventOffset& = eventOffset& + LEN(WriteVariableLength$(metaLength&)) + metaLength&
ELSE
event.Data1% = 0: event.Data2% = 0
eventOffset& = eventOffset& + 1
END IF
PRINT #textFileHandle&, trackCount%; CHR$(9); event.DeltaTime&; CHR$(9); event.Status%; CHR$(9); event.Data1%; CHR$(9); event.Data2%
LOOP
NEXT trackCount%
_CLOSE textFileHandle&
END SUB
SUB TextToMidi (textFilePath$, midiFilePath$)
DIM fileHandle&, textFileHandle&, line$, parts$(), header AS MIDIHDR, tracks(1 TO 256) AS MIDITRACK, trackCount%, offset&, deltaTime&, status%, data1%, data2%, midiData$, trackData$
DIM trackLength&
textFileHandle& = _OPEN(textFilePath$, _OPENEXISTING, _OPENINPUT)
IF textFileHandle& = 0 THEN
PRINT "Error opening text file."
EXIT SUB
END IF
header.MThd$ = "MThd"
header.Length& = 6
header.Format% = 0
header.Tracks% = 1
header.Division% = 480
midiData$ = header.MThd$ + CHR$(0) + CHR$(0) + CHR$(0) + CHR$(header.Length&) + CHR$(0) + CHR$(header.Format%) + CHR$(0) + CHR$(header.Tracks%) + CHR$(0) + CHR$(header.Division%)
tracks(1).MTrk$ = "MTrk"
trackData$ = ""
LINE INPUT #textFileHandle&, line$ ' Skip header line
DO WHILE NOT EOF(textFileHandle&)
LINE INPUT #textFileHandle&, line$
parts$() = SPLIT$(line$, CHR$(9))
deltaTime& = VAL(parts$(1))
status% = VAL(parts$(2))
data1% = VAL(parts$(3))
data2% = VAL(parts$(4))
trackData$ = trackData$ + WriteVariableLength$(deltaTime&) + CHR$(status%)
IF status% < &HF0 THEN
trackData$ = trackData$ + CHR$(data1%) + CHR$(data2%)
END IF
LOOP
trackData$ = trackData$ + CHR$(0) + CHR$(&HFF) + CHR$(&H2F) + CHR$(0) ' End of track meta event
trackLength& = LEN(trackData$)
midiData$ = midiData$ + tracks(1).MTrk$ + CHR$((trackLength& \ &H1000000) AND &HFF) + CHR$((trackLength& \ &H10000) AND &HFF) + CHR$((trackLength& \ &H100) AND &HFF) + CHR$(trackLength& AND &HFF) + trackData$
fileHandle& = _OPEN(midiFilePath$, _OPENCREATE, _OPENBINARY)
IF fileHandle& = 0 THEN
PRINT "Error creating MIDI file."
EXIT SUB
END IF
_PUT fileHandle&, midiData$
_CLOSE fileHandle&
_CLOSE textFileHandle&
END SUB
' Example Usage
DIM midiIn$, textOut$, midiOut$
midiIn$ = "C:\test.mid" ' Replace with your input MIDI file
textOut$ = "C:\test.txt" ' Replace with your output text file
midiOut$ = "C:\test_converted.mid" ' Replace with your output MIDI file
MidiToText midiIn$, textOut$
TextToMidi textOut$, midiOut$
PRINT "MIDI conversion complete."
END
