{But, if you're set on MIDI, then the following is a unit I made. It's
very crude, however, as it has a few serious limitations:
1. To change the port setting you must recompile the unit.
2. In no way does it support SMF (general midi) files...sorry.
3. The procedures I made are just simple note on and note off procedures.
4. I don't know if it will work with anything other than an external MIDI
device...I think, if you want FM synthesis, you need another unit.
If it does work, and you need more MIDI procedures for doing different
things to the MIDI device (more than note on and off), then feel free to
ask me, as I have a big reference for all functions.
Anyway, here is the unit:
Converted into unit format from a general midi program included in SWAG
edition November 1994 --- feel free to put this into SWAG as
well.
New (simple) functions and procedures were added.
Freeware. Unit conversion and new procedures made 1995 (converted into
unit form by Sam McGrath)
}
unit gMidi;
{---------==========---------} Interface {---------==========---------}
var GMPort:word; {Status Port of the GM Device: default is 331h
The data port is the statusPort-1}
{
GetByte returns a byte being output from the general MIDI device
writeByte outputs a byte TO the GM device
writeByteS outputs a byte to the GM device, but outputs it to the status
port as opposed to the data port
}
function getByte:byte;
function getByteS:byte;
procedure writeByte(b:byte);
procedure writeByteS(b:byte);
{ResetGM initializes the GM device
setNoteOn plays a note on the specified channel, with a specified note
and
velocity (velocity is how hard the key on the GM device is pressed. It
is similar to volume but different, since some synths will change, for
example, the attack time as well as the volume if different velocities
are input into the device)
setNoteOff stops playing the specified note on the specified channel.
The value you give velocity has no effect.
}
procedure resetGM;
procedure setNoteOn(channel,note,velocity:byte);
procedure setNoteOff(channel,note,velocity:byte);
{--------========----------} Implementation {--------========---------}
Const
Send = $80;
Receive = $40;
{
Routines from SWAG:
}
{ AL:=Command; }
Procedure WriteGMCommand; Assembler;
ASM
MOV DX,GMPort {;DX:=GMStatusPort;
}
PUSH AX {;Save AX
}
XOR AX,AX {;AH:=TimeOutValue;
}
@@WaitLoop:
{ ;Prevent Infinite Loop with Timeout }
DEC AH {; |If TimeOutCount=0 then
}
JZ @@TimeOut {;/ TimeOut;
}
{; Wait until GM is ready }
IN AL,DX {; |If Not Ready then
}
AND AL,Receive {; | WaitLoop;
}
JNZ @@WaitLoop {;/
}
@@TimeOut:
POP AX {;Restore AX
}
OUT DX,AL {;Send Data
}
End;
{ ; AL:=Data }
Procedure WriteGM; Assembler;
ASM
MOV DX,GMPort {;DX:=GMStatusPort;
}
PUSH AX {;Save AX
}
XOR AX,AX {;AH:=TimeOutValue;
}
@@WaitLoop:
{ ; Prevent Infinite Loop with Timeout }
DEC AH {; |If TimeOutCount=0 then
}
JZ @@TimeOut {;/ TimeOut;
}
{ ; Wait until GM is ready }
IN AL,DX {; |If Not Ready then
}
AND AL,Receive {; | WaitLoop;
}
JNZ @@WaitLoop {;/
}
@@TimeOut:
POP AX {;Restore AX
}
DEC DX {;DX:=DataPort }
OUT DX,AL {;Send Data }
End;
{ Recieve a byte from the GM device }
Function getByte:Byte; Assembler;
ASM
MOV DX,GMPort {;DX:=GMStatusPort;
}
PUSH AX {;Save AX
}
XOR AX,AX {;AH:=TimeOutValue;
}
@@WaitLoop:
{ ; Prevent Infinite Loop with Timeout }
DEC AH {; |If TimeOutCount=0 then
}
JZ @@TimeOut {;/ TimeOut;
}
{ ; Wait until GM is ready }
IN AL,DX {; |If Not Ready then
}
AND AL,Send {; | WaitLoop;
}
JNZ @@WaitLoop {;/
}
@@TimeOut:
POP AX {;Restore AX
}
DEC DX {;DX:=DataPort
}
IN AL,DX {;Receive Data
}
End;
Function getByteS:Byte; Assembler;
ASM
MOV DX,GMPort {;DX:=GMStatusPort;
}
PUSH AX {;Save AX
}
XOR AX,AX {;AH:=TimeOutValue;
}
@@WaitLoop:
{ ; Prevent Infinite Loop with Timeout }
DEC AH {; |If TimeOutCount=0 then
}
JZ @@TimeOut {;/ TimeOut;
}
{ ; Wait until GM is ready }
IN AL,DX {; |If Not Ready then
}
AND AL,Send {; | WaitLoop;
}
JNZ @@WaitLoop {;/
}
@@TimeOut:
POP AX {;Restore AX
}
IN AL,DX {;Receive Data
}
End;
{Initialize the GM device}
Procedure ResetGM; Assembler;
ASM
{ ;Reset GM }
MOV DX,GMPort
MOV AL,0FFh
OUT DX,AL
{; Get ACK }
CALL getByte
{; UART Mode }
MOV AL,03Fh
CALL WriteGMCommand
End;
{Turn on specified note on specified channel}
Procedure SetNoteOn(Channel,Note,velocity:Byte); Assembler;
ASM
MOV AL,[Channel]
ADD AL,90h
Call WriteGM
MOV AL,[Note]
CALL WriteGM
MOV AL,[velocity]
CALL WriteGM
End;
{Turn off specified note on specified channel}
Procedure SetNoteOff(Channel,Note,velocity:Byte); Assembler;
ASM
MOV AL,[Channel]
ADD AL,80h
Call WriteGM
MOV AL,[Note]
CALL WriteGM
MOV AL,[velocity]
CALL WriteGM
End;
{Write a single byte to the data port}
procedure writeByte(b:byte); assembler;
asm
mov al, [b]
call writeGM
end;
{Write a single byte to the status port}
procedure writeByteS(b:byte);assembler;
asm
mov al, [b]
call writeGMCommand
end;
begin {initialization}
GMPort:=$331
end.
               (
geocities.com/~franzglaser)