[Back to SOUND SWAG index] [Back to Main SWAG index] [Original]

    {
    Here is the PASCAL version of a portion of the Assembler code I used in my
    game to get General Midi sound.  I've compiled the program, and it works fine
    on my GM device, MEGA-EM a TSR for the Gravis Ultrasound.

    No checking is performed, make sure you have the correct hardware, but
    it should run due to the timeout checking.

    If you don't get sound, then it's probably because no instrument was
    defined.  Send a program change midi sequence.

    Feel free to toss this in SWAG.  Sound code is always requested,
    and General Midi is so simple compared to everything else.
    }
    Program GMTest;

    (*
    Take from Colin Buckley's cheezy shareware game Tubes, written in BP.
    The actual GM code is a converted assembler file, thus the obvious macro
    like sequences, register passing, and semi-colon comments.  Sorry for any
    typos/bugs introduced during the quick conversion.

    This is completely public domain.  Which means no restrictions whatsoever.

    {$DEFINE EducateTheMasses}
    To the uninformed, you can not say something is public domain, then paste a
    copyright on it and say it's required for you to be acknowledged or
    get a post card or something.  You give up all rights when you give something
    to the public domain.  What you want, is called freeware.
    {$ENDIF}
    *)

    Const
      GMPort        = $331;
      Send          = $80;
      Receive       = $40;

    { 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;

    { ;Returns Data }
    Function ReadGM: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;

    Procedure ResetGM; Assembler;
    ASM
        { ;Reset GM }
        MOV   DX,GMPort
        MOV   AL,0FFh
        OUT   DX,AL
        {; Get ACK }
        CALL  ReadGM
        {; UART Mode }
        MOV   AL,03Fh
        CALL  WriteGMCommand
    End;

    Procedure SetNoteOn(Channel,Note,Volume:Byte); Assembler;
    ASM
        MOV   AL,[Channel]
        ADD   AL,90h
        Call  WriteGM
        MOV   AL,[Note]
        CALL  WriteGM
        MOV   AL,[Volume]
        CALL  WriteGM
    End;

    Procedure SetNoteOff(Channel,Note,Volume:Byte); Assembler;
    ASM
        MOV   AL,[Channel]
        ADD   AL,80h
        Call  WriteGM
        MOV   AL,[Note]
        CALL  WriteGM
        MOV   AL,[Volume]
        CALL  WriteGM
    End;

    Begin
      ResetGM;
      SetNoteOn(0,64,127);
      ASM
        { ;Wait for Key }
        XOR   AX,AX
        INT   16h
      End;
      SetNoteOff(0,64,127);
      ResetGM;
    End.

[Back to SOUND SWAG index] [Back to Main SWAG index] [Original]