'===========================================================================
' Subject: SIMPLE MIDI PLAYER                 Date: 09-11-98 (10:32)       
'  Author: Cleber de Mattos Casali            Code: QB, QBasic, PDS        
'  Origin: landale@usa.net                  Packet: SOUND.ABC
'===========================================================================
'Simple MIDI player for BC7 (for QB45 or QBasic, change SSEG to VARSEG and a few other things)
' 
'by Cleber de Mattos Casali (landale@usa.net, http://members.tripod.com/~Casali/)
'ASM code by Jesse Dorland (jessedorland@hotmail.com, http://members.tripod.com/~jdorland/qmidi/)
'
'Load the SBMIDI driver before using
'
'Usage:
'LoadMIDI "midfile.mid"
' loads the midi file in the MIDI%() array
'PlayMIDI
' play it
'StopMIDI
' guess what
'variable& = TimeMIDI&
' shows for how much time the midi file is playing (in seconds*18)
'SetMIDIloop howmuchtime&
' sets after how much time the song file will loop
'KeepMIDI
' loops the song
'DisableMIDI
' guess again
'
'$DYNAMIC
DEFINT A-Z
DECLARE SUB PlayMIDI ()
DECLARE SUB KeepMIDI ()
DECLARE FUNCTION TimeMIDI& ()
DECLARE SUB LoadMIDI (Filename$)
DECLARE SUB SetMIDIloop (index&)
DECLARE SUB StopMIDI ()
DECLARE SUB DisableMIDI ()
DECLARE FUNCTION FileBytes& (Filename$)
DIM SHARED MIDIplaytime&, MIDIlooptime&
DIM SHARED MIDIisOn%, MIDI%(1)

REM $STATIC
SUB DisableMIDI
MIDIisOn% = 0
END SUB

FUNCTION FileBytes& (Filename$)
FF% = FREEFILE
OPEN Filename$ FOR BINARY AS #FF%
FileLen& = LOF(FF%)
CLOSE FF%
IF FileLen& = 0 THEN KILL Filename$
FileBytes& = FileLen&
END FUNCTION

SUB KeepMIDI
IF MIDIisOn% = 0 THEN EXIT SUB
IF TimeMIDI& > MIDIlooptime& THEN PlayMIDI
END SUB

SUB LoadMIDI (MIDIfile$) STATIC
IF LEN(ENVIRON$("BLASTER")) = 0 THEN MIDIisOn% = 0: EXIT SUB
IF DIR$(MIDIfile$) = "" THEN MIDIisOn% = 0: EXIT SUB
MIDIisOn% = -1
REDIM MIDI%(FileBytes&(MIDIfile$) \ 2)
DIM Filename AS STRING * 256
MIDISegment% = VARSEG(MIDI%(0))
MIDIOffset% = VARPTR(MIDI%(0))
OPEN MIDIfile$ FOR BINARY AS #1
FileLen& = LOF(1)
CLOSE #1
Filename = MIDIfile$ + CHR$(0)
asm$ = asm$ + CHR$(&H1E)
asm$ = asm$ + CHR$(&H55)
asm$ = asm$ + CHR$(&H89) + CHR$(&HE5)
asm$ = asm$ + CHR$(&HB8) + CHR$(&H0) + CHR$(&H3D)
asm$ = asm$ + CHR$(&H8B) + CHR$(&H5E) + CHR$(&HE)
asm$ = asm$ + CHR$(&H8B) + CHR$(&H17)
asm$ = asm$ + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H10)
asm$ = asm$ + CHR$(&H8E) + CHR$(&H1F)
asm$ = asm$ + CHR$(&HCD) + CHR$(&H21)
asm$ = asm$ + CHR$(&H89) + CHR$(&HC6)
asm$ = asm$ + CHR$(&HB4) + CHR$(&H3F)
asm$ = asm$ + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H8)
asm$ = asm$ + CHR$(&H8B) + CHR$(&HF)
asm$ = asm$ + CHR$(&H8B) + CHR$(&H5E) + CHR$(&HA)
asm$ = asm$ + CHR$(&H8B) + CHR$(&H17)
asm$ = asm$ + CHR$(&H8B) + CHR$(&H5E) + CHR$(&HC)
asm$ = asm$ + CHR$(&H8E) + CHR$(&H1F)
asm$ = asm$ + CHR$(&H89) + CHR$(&HF3)
asm$ = asm$ + CHR$(&HCD) + CHR$(&H21)
asm$ = asm$ + CHR$(&HB4) + CHR$(&H3E)
asm$ = asm$ + CHR$(&HCD) + CHR$(&H21)
asm$ = asm$ + CHR$(&H5D)
asm$ = asm$ + CHR$(&H1F)
asm$ = asm$ + CHR$(&HCA) + CHR$(&HA) + CHR$(&H0)
DEF SEG = SSEG(asm$)
CALL ABSOLUTE(VARSEG(Filename), VARPTR(Filename), MIDISegment%, MIDIOffset%, &HFFFF, SADD(asm$))
DEF SEG
END SUB

SUB PlayMIDI STATIC
IF MIDIisOn% = 0 THEN EXIT SUB
MIDISegment% = VARSEG(MIDI%(0))
MIDIOffset% = VARPTR(MIDI%(0))
asm$ = asm$ + CHR$(&H55)
asm$ = asm$ + CHR$(&H89) + CHR$(&HE5)
asm$ = asm$ + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H8)
asm$ = asm$ + CHR$(&H8B) + CHR$(&H17)
asm$ = asm$ + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H6)
asm$ = asm$ + CHR$(&H8B) + CHR$(&H7)
asm$ = asm$ + CHR$(&HBB) + CHR$(&H4) + CHR$(&H0)
asm$ = asm$ + CHR$(&HCD) + CHR$(&H80)
asm$ = asm$ + CHR$(&HBB) + CHR$(&H5) + CHR$(&H0)
asm$ = asm$ + CHR$(&HCD) + CHR$(&H80)
asm$ = asm$ + CHR$(&H5D)
asm$ = asm$ + CHR$(&HCA) + CHR$(&H4) + CHR$(&H0)
DEF SEG = SSEG(asm$)
Offset% = SADD(asm$)
CALL ABSOLUTE(MIDISegment%, MIDIOffset%, Offset%)
DEF SEG = 0
MIDIplaytime& = PEEK(&H46C) + 256& * PEEK(&H46D)
DEF SEG
END SUB

SUB SetMIDIloop (index&)
MIDIlooptime& = index&
END SUB

SUB StopMIDI
IF MIDIisOn% = 0 THEN EXIT SUB
asm$ = asm$ + CHR$(&HBB) + CHR$(&H4) + CHR$(&H0)
asm$ = asm$ + CHR$(&HCD) + CHR$(&H80)
asm$ = asm$ + CHR$(&HCB)
DEF SEG = SSEG(asm$)
Offset% = SADD(asm$)
CALL ABSOLUTE(Offset%)
DEF SEG
MIDI.PLAYTIME = 0
END SUB

FUNCTION TimeMIDI&
DEF SEG = 0
 CurrentTime& = PEEK(&H46C) + 256& * PEEK(&H46D)
DEF SEG
IF MIDIplaytime& THEN
 IF CurrentTime& - MIDIplaytime& < 0 THEN
  CurrentTime& = 1555200 + CurrentTime&
 END IF
 TimeMIDI& = CurrentTime& - MIDIplaytime&
END IF
END FUNCTION
