;ББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББ
;
; SHOCK! PLAY 32BIT VERSION BY TSC/SHOCK! [S3M]
;
;ББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББ
;
; SUPPORTED COMMANDS:   01 [A]  -       SET SPEED
;                       03 [C]  -       PATTERN BREAK
;                       04 [D]  -       VOLUME SLiDE
;                       04 [DF] -       FINE VOLUME SLIDE
;                       05 [E]  -       PORTAMENTO DOWN
;                       05 [EF] -       FINE PORTAMENTO DOWN
;                       05 [EE] -       EXTRA FINE PORTAMENTO DOWN
;                       06 [F]  -       PORTAMENTO UP
;                       06 [FF] -       FINE PORTAMENTO UP
;                       06 [FE] -       EXTRA FINE PORTAMENTO UP
;                       07 [G]  -       PORTA TO NOTE
;                       10 [J]  -       ARPEGGIO
;                       11 [K]  -       VIBRATO + VOLUME SLIDE
;                       12 [L]  -       PORTA TO NOTE + VOLUME SLIDE
;                       15 [O]  -       SAMPLE OFFSET
;                       17 [Q]  -       RETRIGGER NOTE
;                       19 [S8] -       SET PAN POSITION
;                       19 [SA] -       OLD STEREO EFFECT
;                       19 [SC] -       NOTE CUT
;                       19 [SD] -       NOTE DELAY
;                       20 [T]  -       SET TEMPO
;                       22 [V]  -       SET GLOBAL VOLUME
;                       24 [X]  -       SET DMP PAN
;
;ББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББ

.386
.MODEL FLAT,C
.CODE

;ББББББ COPYRIGHT LЂFASZ ББББББББББББББББББББББББББББББББББББББББББББББББББББББ

        COPYRiGHT       DB      10,13,10,13,' ******************************'
                        DB      '*******************************************'
                        DB      '*****',10,13,' ******************* PMODE GU'
                        DB      'S/S3M PLAYER 2.3 BY TSC/SHOCK! ************'
                        DB      '*******',10,13,' **************************'
                        DB      '*******************************************'
                        DB      '*********'

;ББББББ PUBLICS БББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББ

        PUBLIC          SP_NEWINT8
        PUBLIC          SP_START
        PUBLIC          SP_STOP
        PUBLIC          SP_SETCALLBACK
        PUBLIC          SP_ACTORDER
        PUBLIC          SP_ACTROW
        PUBLIC          SP_ACTCHANNEL
        PUBLIC          SP_SAMPLENUM
        PUBLIC          SP_EFFECTNUM
        PUBLIC          SP_EFFECTPAR
        PUBLIC          SP_SONGLENGTH
        PUBLIC          SP_SPEEDDEFAULT
        PUBLIC          SP_TEMPODEFAULT
        PUBLIC          SP_CHANNELS
        PUBLIC          SP_GUSBASE
        PUBLIC          SP_MASTERVOLUME
        PUBLIC          SP_NOTE
        PUBLIC          SP_SAMPLESSIZE
        PUBLIC          GUSVOLUMES
        PUBLIC          POLLMUSIC

;ББББББ VARIABLES БББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББ

        SP_OLDESP       DD      0
        SP_MODPLACE     DD      0
        SP_ROUTINE2CALL DD      0
        SP_ERRORCODE    DD      0
        SP_CHANNELS     DD      0
        SP_NEWBREAK     DB      0
        SP_NEWJUMP      DB      0
        SP_BREAKFLAG    DB      0
        SP_JUMPFLAG     DB      0
        SP_OLDINT8      DD      0
                        DW      0
        SP_TEMPODEFAULT DB      7DH
        SP_SPEEDDEFAULT DB      6
        SP_DEFAULTPAN   DB      0
        SP_TIMERNUM     DD      2982950
        SP_TICK         DB      0
        SP_ACTORDER     DB      255
        SP_OLDORDER     DB      0
        SP_DIVIDER      DD      44100
        SP_ACTROW       DB      64
        SP_ACTCHANNEL   DB      0
        SP_ACT4096      DD      0
        SP_RETRIGCOUNT  DB      32 DUP (0)
        SP_EFFECTNUM    DB      32 DUP (0)
        SP_EFFECTPAR    DB      32 DUP (0)
        SP_EFFECTVOL    DB      32 DUP (0)
        SP_NOTE         DW      32 DUP (0)
        SP_LASTNOTE     DW      32 DUP (0)
        SP_SAMPLENUM    DW      32 DUP (0)
        SP_SAMPLEOFFSET DD      32 DUP (0)
        SP_PORTASPEED   DB      32 DUP (0)
        SP_NOTE2PORTATO DW      32 DUP (0)
        SP_DEFAULTPANS  DB      32 DUP (0)
        SP_LASTVOLSLIDE DB      32 DUP (0)
        SP_LASTPORTA    DB      32 DUP (0)
        SP_LASTARPEGGIO DB      32 DUP (0)

;ББББББ ULTRASOUND VARIABLES ББББББББББББББББББББББББББББББББББББББББББББББББББ

        SP_GUSBASE      DW      0
        SP_GUSIRQ       DW      0
        SP_GUSDMA       DW      0
        SP_GUSMEMSIZE   DD      0
        SP_SIGN         DB      128
        SP_INCER        DB      0
        SP_SMPADDRESS   DD      0
        SP_UPLOADLENGTH DW      0
        SP_GUSLOCATION  DD      0
        SP_NUMVOICES    DB      14
        SP_MASTERVOLUME DB      64

;ББББББ ULTRASOUND PORTS ББББББББББББББББББББББББББББББББББББББББББББББББББББББ

        SP_STATUSPORT   EQU     6
        SP_SELECTVOICE  EQU     102H
        SP_COMMANDPORT  EQU     103H
        SP_DATALOWPORT  EQU     104H
        SP_DATAHIGHPORT EQU     105H
        SP_DRAMIOPORT   EQU     107H

;ББББББ ULTRASOUND COMMANDS БББББББББББББББББББББББББББББББББББББББББББББББББББ

        SP_SETVOICEFREQ EQU     1
        SP_VOLRAMPRATE  EQU     6
        SP_VOLRAMPSTART EQU     7
        SP_VOLRAMPEND   EQU     8
        SP_SETVOLUME    EQU     9
        SP_SMPSTARTLO   EQU     10
        SP_SMPSTARTHI   EQU     11
        SP_VOICEBALANCE EQU     12
        SP_VOICESACTIVE EQU     14
        SP_DMACONTROL   EQU     41H
        SP_DRAMALO      EQU     43H
        SP_DRAMAHI      EQU     44H
        SP_TIMERCONTROL EQU     45H
        SP_SMPCONTROL   EQU     49H
        SP_INITIALIZE   EQU     4CH


;ББББББ MESSAGES ББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББ

        SP_MSG0         DB      'SP_ERROR: MODULE FORMAT UNKNOWN!$'
        SP_MSG1         DB      'SP_ERROR: SELECTED SOUNDCARD NOT DETECTED!$'
        SP_MSG2         DB      'SP_ERROR: INCORRECT SAMPLE TYPE!$'
        SP_INI0         DB      'SP_INIT: INITIALIZING GUS',10,13,'$'
        SP_INI1         DB      'SP_INIT: DUMPING SAMPLES TO GUS: $'
        SP_INI2         DB      10,13,'SP_INIT: HOOKING INT 8H',10,13,'$'
        SP_INI3         DB      'SP_INIT: PLAYING',10,13,'$'
        SP_INI4         DB      'SP_DEINIT: STOPPING',10,13,'$'
        SP_INI5         DB      'SP_DEINIT: UN-HOOKING INT 8H',10,13,'$'
        SP_INI6         DB      'SP_INIT: 256K MEMORY ON BOARD',10,13,'$'
        SP_INI7         DB      'SP_INIT: 512K MEMORY ON BOARD',10,13,'$'
        SP_INI8         DB      'SP_INIT: 768K MEMORY ON BOARD',10,13,'$'
        SP_INI9         DB      'SP_INIT: 1024K MEMORY ON BOARD',10,13,'$'
        SP_INI10        DB      'SP_INIT: DOUBLING MEMORY',10,13,'$'
        SP_INI11        DB      'SP_INIT: QUADRING MEMORY',10,13,'$'

        SP_MSGTABLE     DD      SP_MSG0
                        DD      SP_MSG1
                        DD      SP_INI0
                        DD      SP_INI1
                        DD      SP_INI2
                        DD      SP_INI3
                        DD      SP_INI4
                        DD      SP_INI5
                        DD      SP_MSG2
                        DD      SP_INI6
                        DD      SP_INI7
                        DD      SP_INI8
                        DD      SP_INI9
                        DD      SP_INI10
                        DD      SP_INI11

;ББББББ SONG DATA БББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББ

        SP_SMPLENGTHS   DW      99      DUP (0)
        SP_SMPMODE      DB      99      DUP (0) ; 0: 1/1, 1: 1/2 , 2: 1/4 ...
        SP_C2SPEEDS     DW      99      DUP (0)
        SP_VOLUMES      DB      99      DUP (0)
        SP_LOOPSTARTS   DW      99      DUP (0)
        SP_LOOPLENGTHS  DW      99      DUP (0)
        SP_LOOPFLAGS    DB      99      DUP (0)
        SP_ORDERS       DB      256     DUP (0)
        SP_INSPARA      DW      99      DUP (0)
        SP_INSMEMSEGS   DD      99      DUP (0)
        SP_PATTERNPARA  DW      256     DUP (0)
        SP_LASTSAMPLE   DB      32      DUP (0)
        SP_FREQS        DW      32      DUP (0)
        GUSMUTE         DB      32      DUP (0)
        GUSVOLUMES      DB      32      DUP (0)
        GUSPLACES       DD      31      DUP (0)
        SP_VSTART       DD      99      DUP (0)
        SP_VBEGIN       DD      99      DUP (0)
        SP_VEND         DD      99      DUP (0)
        SP_MODE         DB      99      DUP (0)
        SP_NUMOFPATTRNS DW      0
        SP_SONGLENGTH   DB      0
        SP_SONGL        DW      0
        SP_NUMOFINST    DW      0
        SP_RESTARTPOS   DB      0
        SP_SAMPLESSIZE  DD      0

;ББББББ TABLES ББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББ

        GUSVOL          DW      01500H,0A0DEH,0AB52H,0B2BDH,0B87EH,0BD31H
                        DW      0C12BH,0C49CH,0C7A5H,0CA5DH,0CCD2H,0CF10H
                        DW      0D120H,0D309H,0D4D1H,0D67BH,0D80BH,0D984H
                        DW      0DAE9H,0DC3BH,0DD7DH,0DEB0H,0DFD6H,0E0EFH
                        DW      0E1FCH,0E2FFH,0E3F8H,0E4E8H,0E5D0H,0E6AFH
                        DW      0E788H,0E859H,0E924H,0E9E9H,0EAA9H,0EB63H
                        DW      0EC18H,0ECC8H,0ED73H,0EE1AH,0EEBDH,0EF5CH
                        DW      0EFF7H,0F08FH,0F123H,0F1B5H,0F242H,0F2CDH
                        DW      0F356H,0F3DBH,0F45EH,0F4DEH,0F55BH,0F5D7H
                        DW      0F650H,0F6C7H,0F73CH,0F7AEH,0F81FH,0F88EH
                        DW      0F8FBH,0F967H,0F9D0H,0FA38H,0FA9EH,0F00CH

        PERIODTABLE     DW      27392,25856,24384,23040,21696,20480,19328
                        DW      18240,17216,16256,15360,14496,13696,12928
                        DW      12192,11520,10848,10240, 9664, 9120, 8608
                        DW      8128, 7680, 7248, 6848, 6464, 6096, 5760
                        DW      5424, 5120, 4832, 4560, 4304, 4064, 3840
                        DW      3624, 3424, 3232, 3048, 2880, 2712, 2560
                        DW      2416, 2280, 2152, 2032, 1920, 1812, 1712
                        DW      1616, 1524, 1440, 1356, 1280, 1208, 1140
                        DW      1076, 1016,  960,  906, 856,  808,  762
                        DW      720,  678,  640,  604,  570,  538,  508
                        DW      480,  453,  428,  404,  381,  360,  339
                        DW      320,  302,  285,  269,  254,  240,  226
                        DW      214,  202,  190,  180,  170,  160,  151
                        DW      143,  135,  127,  120,  113,  107,  101
                        DW      95,   90,   85,   80,   75,   71,   67
                        DW      63,   60,   56

        SP_DIVIDERS     DD      44100,41160,38587,36317,34300,32494,30870
                        DD      29400,28063,26843,25725,24696,23746,22866
                        DD      22050,21289,20580,19916,19293

;ББББББ MAIN CODE БББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББ

SP_START:
        MOV     EAX,[ESP+4]             ; GETTING ADDRESS OF THE MODULE
        MOV     SP_MODPLACE,EAX         ; STORING IT
        CALL    DETECTTYPE              ; MOD, S3M, OR.. JPG?
        CALL    INITVARIABLES           ; FILLING UP RUNTIME VARIABLES
        CALL    INITDIVIDERS            ; 44100... OR?
        CALL    INITSAMPLES             ; READING IN SAMPLEDATA
        MOV     SP_ERRORCODE,2
        CALL    DEBUGMESSAGE
        CALL    DETECTGUS
        CALL    GUSRESET
        CALL    DETECTGUSMEM
        CALL    DETECTS3M2RAMSIZE
        CALL    GUSSILENCER
        MOV     SP_ERRORCODE,3
        CALL    DEBUGMESSAGE
        CALL    UPLOADSAMPLES
        MOV     SP_ERRORCODE,4
        CALL    DEBUGMESSAGE
        CALL    INIT_IRQ8
        CALL    INIT_BALANCE
        MOV     SP_ERRORCODE,5
        CALL    DEBUGMESSAGE
        RET

SP_STOP:
        MOV     SP_ERRORCODE,6
        CALL    DEBUGMESSAGE
        CALL    DEINIT_IRQ8
        MOV     SP_ERRORCODE,7
        CALL    DEBUGMESSAGE
        CALL    GUSRESET
        RET

SP_SETCALLBACK:
        MOV     EAX,[ESP+4]
        MOV     SP_ROUTINE2CALL,EAX
        RET

;ББББББ SUBCODE БББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББ

INITVARIABLES:
        PUSHAD
        MOV     EAX,SP_MODPLACE
        MOV     BX,[EAX+32]
        MOV     SP_SONGL,BX             ; SONG LENGTH
        MOV     BX,[EAX+34]
        MOV     SP_NUMOFINST,BX         ; NUM OF INSTRUMENTS
        MOV     BX,[EAX+36]
        MOV     SP_NUMOFPATTRNS,BX      ; NUM OF PATTERNS
        MOV     BL,[EAX+48]
        MOV     SP_MASTERVOLUME,BL      ; GLOBAL VOLUME
        MOV     BL,[EAX+49]
        MOV     SP_SPEEDDEFAULT,BL      ; INITIAL SPEED
        MOV     BL,[EAX+50]
        MOV     SP_TEMPODEFAULT,BL      ; INITIAL BPM
        MOV     BL,[EAX+53]
        MOV     SP_DEFAULTPAN,BL        ; DEFAULT PANNING
        MOV     SP_CHANNELS,0
        MOV     ECX,64
RE_CHS: MOV     BL,[EAX+ECX]
        CMP     BL,16
        JNB     NOTENABLED
        INC     SP_CHANNELS             ; NUMBER OF CHANNELS
NOTENABLED:
        INC     ECX
        CMP     ECX,64+32
        JNE     RE_CHS
        MOV     EDX,0
        MOV     ECX,96
RE_ORD: MOV     BL,[ECX+EAX]
        CMP     BL,254
        JAE     MARKER
        MOV     SP_ORDERS[EDX],BL       ; CORRECT ORDERLIST
        INC     EDX
MARKER: MOVZX   EBP,WORD PTR SP_SONGL
        ADD     EBP,96
        INC     ECX
        CMP     EBP,ECX
        JNE     RE_ORD
        DEC     DL
        MOV     SP_SONGLENGTH,DL        ; REAL SONGLENGTH!
        MOVZX   EBP,WORD PTR SP_NUMOFINST
        MOV     EDX,0
RE_INSP:MOV     BX,[ECX+EAX]
        MOV     SP_INSPARA[EDX*2],BX    ; STORING INSTRUMENT PARAPOINTERS
        ADD     ECX,2
        INC     EDX
        DEC     EBP
        JNZ     RE_INSP
        MOVZX   EBP,WORD PTR SP_NUMOFPATTRNS
        MOV     EDX,0
RE_PASP:MOV     BX,[ECX+EAX]
        MOV     SP_PATTERNPARA[EDX*2],BX ; STORING PATTERN PARAPOINTERS
        ADD     ECX,2
        INC     EDX
        DEC     EBP
        JNZ     RE_PASP
        CMP     SP_DEFAULTPAN,252
        JNE     DONTREADPAN
        MOV     EBP,32
        MOV     EDX,0
RE_PANS:MOV     BL,[ECX+EAX]
        AND     BL,0FH
        MOV     SP_DEFAULTPANS[EDX],BL  ; STORING DEFAULT PANNINGS
        INC     ECX
        INC     EDX
        DEC     EBP
        JNZ     RE_PANS
        JMP     PANSREAD
DONTREADPAN:
        ADD     ECX,32                  ; WE MUST INCREMENT THIS
PANSREAD:
        MOV     SP_ACTORDER,255
        MOV     SP_ACTROW,64
        MOV     SP_ACTCHANNEL,0
        MOV     SP_ACT4096,0
        POPAD
        RET

INITDIVIDERS:
        PUSHAD
        MOV     EAX,SP_CHANNELS
        CMP     EAX,14
        JB      ONLY_44100
        SUB     EAX,14
        MOV     EAX,SP_DIVIDERS[EAX*4]
        MOV     SP_DIVIDER,EAX
        JMP     HIGHERDIV
ONLY_44100:
        MOV     SP_DIVIDER,44100
HIGHERDIV:
        POPAD
        RET

INITSAMPLES:
        PUSHAD
        MOV     ECX,0
RESAMPLES:
        MOVZX   EBX,WORD PTR SP_INSPARA[ECX*2]
        SHL     EBX,4
        ADD     EBX,SP_MODPLACE
        MOV     AL,[EBX]
        CMP     AL,1
        JBE     SAMPLETYPEOK
        MOV     SP_ERRORCODE,8
        CALL    ERROREXIT
SAMPLETYPEOK:
        MOVZX   EAX,WORD PTR [EBX+14]
        MOV     SP_INSMEMSEGS[ECX*4],EAX        ; WHERE IS THE SAMPLE
        CMP     EAX,0
        JE      ZEROBYTESAMPLE                  ; CHECK FOR 0 BYTE SAMPLES
        MOV     AX,WORD PTR [EBX+16]
ZEROBYTESAMPLE:
        MOV     SP_SMPLENGTHS[ECX*2],AX         ; SAMPLE LENGTH
        MOV     BYTE PTR SP_SMPMODE[ECX],0      ; SAMPLE MODE
        MOV     AX,WORD PTR [EBX+20]
        MOV     SP_LOOPSTARTS[ECX*2],AX         ; LOOP START
        MOV     AX,WORD PTR [EBX+24]
        MOV     SP_LOOPLENGTHS[ECX*2],AX        ; LOOP END
        MOV     AL,[EBX+28]
        MOV     SP_VOLUMES[ECX],AL              ; VOLUME
        MOV     AL,[EBX+31]
        AND     AL,1
        MOV     SP_LOOPFLAGS[ECX],AL            ; LOOP FLAG
        MOV     AX,WORD PTR [EBX+32]
        MOV     SP_C2SPEEDS[ECX*2],AX           ; C-2 SPEED
        INC     ECX
        CMP     CX,SP_NUMOFINST
        JNE     RESAMPLES
        POPAD
        RET

DETECTTYPE:
        MOV     EAX,SP_MODPLACE
        ADD     EAX,44
        MOV     EAX,[EAX]
        CMP     EAX,'MRCS'
        JE      TYPE_OK
        MOV     SP_ERRORCODE,0
        JMP     ERROREXIT
TYPE_OK:RET

UPLOADSAMPLES:
        PUSHAD
        MOV     SP_GUSLOCATION,0
        MOV     ECX,0
UPLOOP: MOV     EAX,DWORD PTR SP_INSMEMSEGS[ECX*4]
        SHL     EAX,4
        ADD     EAX,SP_MODPLACE
        MOV     SP_SMPADDRESS,EAX
        MOVZX   EAX,WORD PTR SP_SMPLENGTHS[ECX*2]
        MOV     SP_UPLOADLENGTH,AX
        MOV     AL,BYTE PTR SP_SMPMODE[ECX]
        MOV     SP_INCER,AL
        MOV     EAX,SP_GUSLOCATION
        MOV     SP_VBEGIN[ECX*4],EAX            ; STORING VOICE START
        MOVZX   EBX,WORD PTR SP_LOOPSTARTS[ECX*2]
        ADD     EAX,EBX
        MOV     SP_VSTART[ECX*4],EAX            ; STORING LOOPSTART
        CMP     SP_LOOPFLAGS[ECX],1
        JNE     NOLOOP
        MOVZX   EAX,WORD PTR SP_LOOPLENGTHS[ECX*2]
        ADD     EAX,SP_GUSLOCATION
        MOV     BYTE PTR SP_MODE[ECX],01000B
        JMP     STOREIT
NOLOOP: MOV     EAX,SP_GUSLOCATION
        MOVZX   EBX,SP_UPLOADLENGTH
        ADD     EAX,EBX
STOREIT:MOV     SP_VEND[ECX*4],EAX              ; STORING VOICE END
        CALL    GUSUPLOAD
        MOVZX   EAX,SP_UPLOADLENGTH
        ADD     SP_GUSLOCATION,EAX
        INC     ECX
        MOV     AX,SP_NUMOFINST
        CMP     CX,SP_NUMOFINST
        JNE     UPLOOP
        POPAD
        RET

INIT_IRQ8:
        PUSH    ES
        MOV     AH,35H
        MOV     AL,8
        INT     21H
        MOV     DWORD PTR [SP_OLDINT8],EBX
        MOV     WORD PTR [SP_OLDINT8+4],ES      ; SAVING OLD VECTOR
        POP     ES
        PUSH    DS
        MOV     AX,CS
        MOV     DS,AX
        MOV     AH,25H
        MOV     AL,8
        LEA     EDX,SP_NEWINT8                  ; SETTING THE NEW ONE
        INT     21H
        POP     DS
        CALL    SETTIMERSPEED
        CALL    SETTEMPODEFAULT
        RET

DEINIT_IRQ8:
        PUSH    DS
        MOV     AH,25H
        MOV     AL,8
        MOV     EDX,DWORD PTR [SP_OLDINT8]
        MOV     DS,WORD PTR [SP_OLDINT8+4]      ; RESTORING OLD VECTOR
        INT     21H
        MOV     AL,54
        OUT     43H,AL
        MOV     AX,0                            ; RESTORING OLD TIMERRATE
        OUT     40H,AL
        MOV     AL,AH
        OUT     40H,AL
        MOV     AL,0B6H
        OUT     43H,AL
        MOV     AX,533H
        OUT     42H,AL
        MOV     AL,AH
        OUT     42H,AL
        iN      AL,61H
        AND     AL,0FCH
        OUT     61H,AL
        POP     DS
        RET

INIT_BALANCE:
        PUSHAD
        MOV     EBP,0
REBALA: MOV     ECX,64
        CALL    GUSSETBALANCE
        INC     EBP
        MOV     ECX,192
        CALL    GUSSETBALANCE
        INC     EBP
        CMP     EBP,32
        JNE     REBALA
        POPAD
        RET

GUSSILENCER:
        PUSHAD
        MOV     EBP,0
RESILE: CALL    GUSSETVOLUME
        INC     EBP
        CMP     EBP,32
        JNE     RESILE
        POPAD
        RET

SETTIMERSPEED:
        PUSHAD
        MOV     DX,043H
        MOV     AL,036H
        OUT     DX,AL
        MOV     DX,040H
        MOV     AX,23863 ;TIMERRATE
        OUT     DX,AL
        SHR     AX,8
        OUT     DX,AL
        POPAD
        RET

;БББББББББББББББББББББББББББ THIS ROUTINE WILL BE POLLED ББББББББББББББББББББББ

SP_NEWINT8:
        PUSHFD
        PUSHAD
        MOV     EAX,0
        MOV     EBX,0
        MOV     ECX,0
        MOV     EDX,0
        MOV     EBP,0
        MOV     ESI,0
        MOV     EDI,0
        CALL    POLLMUSIC
        CMP     SP_ROUTINE2CALL,0
        JE      NOTHINGTOCALL
        MOV     SP_OLDESP,ESP
        CALL    [SP_ROUTINE2CALL]
        MOV     ESP,SP_OLDESP

NOTHINGTOCALL:
        MOV     AL,20H
        OUT     20H,AL
        POPAD
        POPFD
        iRET

;БББББББББББББББББББББББББББ THE MAIN ROUTINE БББББББББББББББББББББББББББББББББ

POLLMUSIC:
        INC     SP_TICK
        MOV     AL,SP_TICK
        CMP     AL,SP_SPEEDDEFAULT
        JNB     PROCESSNEWROW
        MOV     EBP,0
RE_TICK:
        MOV     AL,BYTE PTR SP_EFFECTNUM[EBP]
        CMP     AL,4
        JE      VOLSLIDE
        CMP     AL,5
        JE      PORTADOWN
        CMP     AL,6
        JE      PORTAUP
        CMP     AL,7
        JE      PORTATONOTE2
        CMP     AL,10
        JE      ARPEGGIO
        CMP     AL,11
        JE      VIBRATOANDVOLUMESLIDE
        CMP     AL,12
        JE      PORTAANDVOLUMESLIDE
        CMP     AL,17
        JE      RETRIGGERNOTE
        CMP     AL,19
        JNE     NOSPECIAL1
        MOV     AH,BYTE PTR SP_EFFECTPAR[EBP]
        SHR     AH,4
        CMP     AH,0CH
        JE      NOTECUT
        CMP     AH,0DH
        JE      NOTEDELAY2

NOSPECIAL1:
        ;
        ;
        ;
SKIP_EFFECTS2:
        INC     EBP
        CMP     EBP,SP_CHANNELS
        JNE     RE_TICK
        RET

PROCESSNEWROW:
        PUSHAD
        MOV     SP_TICK,0
        MOV     EBP,0                           ; ACTUAL CHANNEL
        CALL    CLEARNOTEANDSAMPLES
        CMP     SP_BREAKFLAG,1
        JE      FINDNEWROW
        CMP     SP_ACTROW,64
        JNE     RE_ROW                          ; NO NEED TO CALC NEW OFFSET
        MOV     SP_ACTROW,0                     ; AND WE GOTTA RESET THE ROWCNT
        INC     SP_ACTORDER
        MOV     AL,SP_ACTORDER
        CMP     AL,SP_SONGLENGTH
        JBE     OKLENGTH
        MOV     SP_ACTORDER,0                   ; AT THE END OF THE SONG
OKLENGTH:
        MOV     AL,SP_ACTORDER                  ; SAVE THE ORDERPOINTER
        MOV     SP_OLDORDER,AL                  ; FOR LATER CHECKING
        CALL    CALCOFFSET                      ; BUT NOW, WE MUST!

RE_ROW: MOV     ESI,SP_ACT4096
        LODSB                                   ; GET A BYTE
        MOV     CH,AL                           ; SAVE IT FOR LATER USE
        CMP     AL,0
        JNE     MOREBYTES                       ; NOT THE END
        MOV     AL,SP_OLDORDER
        CMP     AL,SP_ACTORDER                  ; CHECKING FOR ORDER CHANGES
        JE      NOORDERCHANGE                   ; [PAGE UP/DOWN IN THE PLAYER]
        MOV     AL,SP_ACTORDER
        MOV     SP_OLDORDER,AL
        CALL    CALCOFFSET
        MOV     ESI,SP_ACT4096
        MOV     SP_ACTROW,255
NOORDERCHANGE:
        INC     SP_ACTROW
        MOV     SP_ACT4096,ESI
        POPAD
        CMP     SP_BREAKFLAG,2
        JNE     RETTENE
        MOV     SP_BREAKFLAG,0
        JMP     PROCESSNEWROW
RETTENE:RET

MOREBYTES:
        AND     AL,31
        MOVZX   EBP,AL                          ; GET CHANNEL
        MOV     AL,CH
        AND     AL,32                           ; CHECK THAT IF THERE IS A NOTE
        CMP     AL,0
        JE      NOREALNOTE
        LODSB
        CMP     AL,254
        JNB     LAMENOTE
        MOVZX   EAX,AL
        MOV     WORD PTR SP_NOTE[EBP*2],AX      ; WE GOT THE NOTE
        CMP     AX,0
        JE      LAMENOTE
        MOV     SP_LASTNOTE[EBP*2],AX
LAMENOTE:
        LODSB
        MOVZX   EAX,AL
        MOV     WORD PTR SP_SAMPLENUM[EBP*2],AX ; WE GOT THE SAMPLE NUMBER
        CMP     AX,0
        JE      NEW0SAM
        MOV     BYTE PTR SP_LASTSAMPLE[EBP],AL  ; WE STORE THIS AS THE LAST INS
        MOVZX   EBX,WORD PTR SP_SAMPLENUM[EBP*2]; SETTING THE VOLUME
        MOVZX   EAX,BYTE PTR SP_VOLUMES[EBX-1]
        MOV     BYTE PTR GUSVOLUMES[EBP],AL     ; IN CASE WE MIGHT NOT GET A VOL
NEW0SAM:
        JMP     NONOTEHERE
NOREALNOTE:
        MOV     WORD PTR SP_NOTE[EBP*2],0       ; 254 - KEYOFF, 255 - FUCK OFF
        MOV     WORD PTR SP_SAMPLENUM[EBP*2],0
NONOTEHERE:
        MOV     AL,CH
        AND     AL,64
        CMP     AL,0
        JE      GOTNOVOL
        LODSB                                   ; WE GOT SOME VOLUME HERE
        MOV     SP_EFFECTVOL[EBP],AL
        MOV     GUSVOLUMES[EBP],AL              ; AND WE MUST STORE IT
        CALL    GUSSETVOLUME                    ; AND SET IT IMMEDIATELY ;)
        JE      GOTVOL
GOTNOVOL:
        MOV     SP_EFFECTVOL[EBP],255           ; ???

GOTVOL: MOV     AL,CH
        AND     AL,128
        CMP     AL,0
        JE      GOTNOEFFECT
        LODSB
        MOV     SP_EFFECTNUM[EBP],AL
        LODSB
        MOV     SP_EFFECTPAR[EBP],AL
        JMP     GOTEFFECT
GOTNOEFFECT:
        MOV     SP_EFFECTNUM[EBP],0             ; NO, HERE WAS NO EFFECT ;(
        MOV     SP_EFFECTPAR[EBP],0             ; NOR EFFECTPARAMETER
GOTEFFECT:
        MOV     SP_ACT4096,ESI
        CMP     SP_BREAKFLAG,2
        JE      RE_ROW

        MOV     BYTE PTR SP_RETRIGCOUNT[EBP],0
        MOV     DWORD PTR SP_SAMPLEOFFSET[EBP*4],0 ; KILL PREV. SAMPLE OFFSETS
        MOV     AX,WORD PTR SP_SAMPLENUM[EBP*2]
        CMP     AL,0
        JE      NOSAMPLEHERE
        CALL    GUSSETVOLUME

NOSAMPLEHERE:
        CMP     WORD PTR SP_NOTE[EBP*2],0
        JE      NONOTE
        ;
        ;
NONOTE:
        MOV     AH,BYTE PTR SP_EFFECTNUM[EBP]
        MOV     AL,BYTE PTR SP_EFFECTPAR[EBP]
        CMP     AX,0
        JE      SKIP_EFFECTS

        MOV     AL,BYTE PTR SP_EFFECTNUM[EBP]
        CMP     AL,01
        JE      SETSPEED
        CMP     AL,03
        JE      PATTERNBREAK
        CMP     AL,7
        JE      PORTATONOTE1
        CMP     AL,15
        JE      SAMPLEOFFSET
        CMP     AL,20
        JE      SETTEMPO
        CMP     AL,19
        JNE     NOSPECIAL2
        MOV     AH,BYTE PTR SP_EFFECTPAR[EBP]
        SHR     AH,4
        CMP     AH,8
        JE      SETPANPOS
        CMP     AH,0AH
        JE      OLDSTEREOEFFECT
        CMP     AH,0DH
        JE      NOTEDELAY1
NOSPECIAL2:
        CMP     AL,22
        JE      SETGLOBALVOLUME
        CMP     AL,24
        JE      SETDMPPAN

SKIP_EFFECTS:
        CMP     WORD PTR SP_NOTE[EBP*2],0
        JE      NONOTE2
        CMP     WORD PTR SP_SAMPLENUM[EBP*2],0
        JE      NONOTE2
        CALL    CALCFREQ
        MOVZX   EBX,WORD PTR SP_SAMPLENUM[EBP*2]
        DEC     EBX
        CMP     EBX,-1
        JNE     GOTSAMPLE
        MOVZX   EBX,BYTE PTR SP_LASTSAMPLE[EBP]
        DEC     EBX
GOTSAMPLE:
        CALL    GUSPLAYVOICE
NONOTE2:JMP     RE_ROW

FINDNEWROW:
        INC     SP_ACTORDER
        MOV     AL,SP_ACTORDER
        CMP     AL,SP_SONGLENGTH
        JBE     OKLENGTH2
        MOV     SP_ACTORDER,0                   ; AT THE END OF THE SONG
OKLENGTH2:
        CALL    CALCOFFSET
        MOV     ESI,SP_ACT4096
        MOV     SP_ACTROW,0
        MOV     SP_BREAKFLAG,2
        MOV     AL,SP_ACTROW
        CMP     AL,SP_NEWBREAK
        JNE     RE_ROW2
        MOV     SP_ACT4096,ESI
        JMP     RE_ROW
RE_ROW2:
        LODSB                                   ; GET A BYTE
        MOV     CH,AL                           ; SAVE IT FOR LATER USE
        CMP     AL,0
        JNE     MOREBYTES2                      ; NOT THE END
        INC     SP_ACTROW
        MOV     AL,SP_ACTROW
        CMP     AL,SP_NEWBREAK
        JNE     RE_ROW2
        MOV     SP_ACT4096,ESI
        JMP     RE_ROW
MOREBYTES2:
        AND     AL,31
        MOVZX   EBP,AL                          ; GET CHANNEL
        MOV     AL,CH
        AND     AL,32                           ; CHECK THAT IF THERE IS A NOTE
        CMP     AL,0
        JE      NOREALNOTE2
        LODSB
        LODSB
NOREALNOTE2:
        MOV     AL,CH
        AND     AL,64
        CMP     AL,0
        JE      GOTNOVOL2
        LODSB                                   ; WE GOT SOME VOLUME HERE
GOTNOVOL2:
        MOV     AL,CH
        AND     AL,128
        CMP     AL,0
        JE      GOTNOEFFECT2
        LODSB
        LODSB
GOTNOEFFECT2:
        MOV     SP_ACT4096,ESI
        JMP     RE_ROW2

CALCOFFSET:
        PUSHAD
        MOVZX   EAX,BYTE PTR SP_ACTORDER
        MOVZX   EAX,BYTE PTR SP_ORDERS[EAX]
        MOVZX   EAX,WORD PTR SP_PATTERNPARA[EAX*2]
        SHL     EAX,4
        ADD     EAX,SP_MODPLACE
        ADD     EAX,2                           ; STORED THE LENGTH OF PATTERN
        MOV     SP_ACT4096,EAX
        POPAD
        RET

CLEARNOTEANDSAMPLES:
        PUSHAD
        MOV     AL,0
        LEA     EDI,SP_NOTE
        MOV     ECX,64
        REP     STOSB
        LEA     EDI,SP_EFFECTNUM
        MOV     ECX,32
        REP     STOSB
        LEA     EDI,SP_EFFECTPAR
        MOV     ECX,32
        REP     STOSB
        LEA     EDI,SP_EFFECTVOL
        MOV     ECX,32
        REP     STOSB
        LEA     EDI,SP_RETRIGCOUNT
        MOV     ECX,32
        REP     STOSB
        LEA     EDI,SP_SAMPLENUM
        MOV     ECX,64
        REP     STOSB
        POPAD
        RET
;ББББББББББББББББББББББББ CALCULATING FREQUENCIES БББББББББББББББББББББББББББББ

CALCFREQ:
        PUSHAD
        MOVZX   EBX,WORD PTR SP_NOTE[EBP*2]
        CMP     EBX,0
        JE      NOCALCF
        MOV     ECX,EBX
        SHR     CL,4                    ; GET OCTAVE
        SHL     BL,4
        SHR     BL,4                    ; GET NOTE
        MOV     EAX,12
        MUL     ECX                     ; OCTAVE*12
        ADD     EAX,EBX
        MOVZX   EAX,WORD PTR PERIODTABLE[EAX*2]
        MOV     EBX,8363
        MUL     EBX
        MOVZX   EBX,WORD PTR SP_SAMPLENUM[EBP*2]
        DEC     EBX
        CMP     EBX,-1
        JNE     NOWRS
        MOVZX   EBX,BYTE PTR SP_LASTSAMPLE[EBP]
        DEC     EBX
NOWRS:  MOVZX   EBX,WORD PTR SP_C2SPEEDS[EBX*2]
        MOV     EDX,0
        DIV     EBX
        MOV     EBX,EAX
        MOV     WORD PTR SP_FREQS[EBP*2],BX
        CMP     EBX,0
        JNE     OKFREQ
        MOV     EBX,856                 ; SOMETHING MUST BE BUGGY IF THIS RUNS
OKFREQ: MOV     EDX,0
        MOV     EAX,7159090*2
        DIV     EBX
        SHL     EAX,9
        MOV     EBX,SP_DIVIDER
        SHR     EBX,1
        ADD     EAX,EBX
        MOV     EDX,EAX
        MOVZX   EAX,AX
        SHR     EDX,16
        MOV     EBX,SP_DIVIDER
        DIV     BX
        SHL     EAX,1
        MOV     CX,AX
        CALL    GUSSETFREQ
NOCALCF:POPAD
        RET

;ББББББББББББББББББББББББ COMMAND 01: SET SPEED БББББББББББББББББББББББББББББББ

SETSPEED:
        PUSHAD
        MOV     AL,BYTE PTR SP_EFFECTPAR[EBP]
        CMP     AL,0
        JE      BADSPEED
        MOV     SP_SPEEDDEFAULT,AL
BADSPEED:
        POPAD
        JMP     SKIP_EFFECTS

;ББББББББББББББББББББББББ COMMAND 03: PATTERN BREAK БББББББББББББББББББББББББББ

PATTERNBREAK:
        PUSHAD
        CMP     SP_BREAKFLAG,1
        JE      SKIPBREAK
        CMP     SP_JUMPFLAG,1
        JE      SKIPBREAK
        MOVZX   AX,BYTE PTR SP_EFFECTPAR[EBP]
        SHR     AX,4
        MOV     BX,10
        MUL     BX
        MOV     BX,AX
        MOVZX   AX,BYTE PTR SP_EFFECTPAR[EBP]
        SHL     AL,4
        SHR     AL,4
        ADD     AX,BX
        MOV     SP_NEWBREAK,AL
        MOV     SP_BREAKFLAG,1
SKIPBREAK:
        POPAD
        JMP     SKIP_EFFECTS

;ББББББББББББББББББББББББ COMMAND 4: VOLUME SLIDE ББББББББББББББББББББББББББББББ

VOLSLIDE:
        MOV     AL,SP_EFFECTPAR[EBP]
        OR      AL,AL
        JNE     NEWVLS
        MOV     AL,SP_LASTVOLSLIDE[EBP]
NEWVLS: MOV     SP_LASTVOLSLIDE[EBP],AL
        CMP     AL,0F0H
        JE      VOLSLIDEUP
        SHR     AL,4
        OR      AL,AL
        JE      VOLSLIDEDOWN
        CMP     AL,0FH
        JE      FINEVOLDOWN
VOLSLIDEUP:
        MOV     AL,SP_LASTVOLSLIDE[EBP]
        TEST    AL,0FH
        JNE     FINEVOLUP
VOLSLIDEUP2:
        SHR     AL,4
        ADD     GUSVOLUMES[EBP],AL
        CMP     GUSVOLUMES[EBP],40H
        JB      VSUSKIP
        MOV     GUSVOLUMES[EBP],40H
VSUSKIP:MOV     AL,GUSVOLUMES[EBP]
        CALL    GUSSETVOLUME
        JMP     SKIP_EFFECTS2
VOLSLIDEDOWN:
        MOV     AL,SP_LASTVOLSLIDE[EBP]
        AND     AL,0FH
        SUB     GUSVOLUMES[EBP],AL
        CMP     GUSVOLUMES[EBP],0FFH
        JG      VSDSKIP
        MOV     GUSVOLUMES[EBP],0
VSDSKIP:MOV     AL,GUSVOLUMES[EBP]
        CALL    GUSSETVOLUME
        JMP     SKIP_EFFECTS2

FINEVOLDOWN:
        MOV     SP_EFFECTNUM[EBP],0
        JMP     VOLSLIDEDOWN
FINEVOLUP:
        MOV     SP_EFFECTNUM[EBP],0
        JMP     VOLSLIDEUP2

;ББББББББББББББББББББББББ COMMAND 5: PORTAMENTO DOWN БББББББББББББББББББББББББББ

PORTADOWN:
        PUSHAD
        MOVZX   AX,BYTE PTR SP_EFFECTPAR[EBP]
        MOV     BL,AL
        SHR     BL,04H
        CMP     BL,0FH
        JE      PD01
        CMP     BL,0EH
        JE      PD02
        OR      AL,AL
        JNE     PD03
        MOV     AL,SP_LASTPORTA[EBP]
PD03:   MOV     SP_LASTPORTA[EBP],AL
        SHL     AX,02H
PD04:   ADD     SP_FREQS[EBP*2],AX
        JMP     ENDPOR2N
PD01:   AND     AL,0FH
        SHL     AX,02H
        MOV     BYTE PTR SP_LASTPORTA[EBP],00H
        MOV     BYTE PTR SP_EFFECTNUM[EBP],00H
        JMP     PD04
PD02:   AND     AL,0FH
        MOV     BYTE PTR SP_LASTPORTA[EBP],00H
        MOV     BYTE PTR SP_EFFECTNUM[EBP],00H
        JMP     PD04

;ББББББББББББББББББББББББ COMMAND 6: PORTAMENTO UP ББББББББББББББББББББББББББББ

PORTAUP:
        PUSHAD
        MOVZX   AX,BYTE PTR SP_EFFECTPAR[EBP]
        MOV     BL,AL
        SHR     BL,04H
        CMP     BL,0FH
        JE      PU01
        CMP     BL,0EH
        JE      PU02
        OR      AL,AL
        JNE     PU03
        MOV     AL,SP_LASTPORTA[EBP]
PU03:   MOV     SP_LASTPORTA[EBP],AL
        SHL     AX,02H
PU04:   SUB     SP_FREQS[EBP*2],AX
        JMP     ENDPOR2N
PU01:   AND     AL,0FH
        SHL     AX,02H
        MOV     BYTE PTR SP_LASTPORTA[EBP],00H
        MOV     BYTE PTR SP_EFFECTNUM[EBP],00H
        JMP     PU04
PU02:   AND     AL,0FH
        MOV     BYTE PTR SP_LASTPORTA[EBP],00H
        MOV     BYTE PTR SP_EFFECTNUM[EBP],00H
        JMP     PU04

;ББББББББББББББББББББББББ COMMAND 07: PORTA TO NOTE БББББББББББББББББББББББББББ

PORTATONOTE1:
        PUSHAD
        CMP     WORD PTR SP_NOTE[EBP*2],0
        JE      NONOTEP
        CMP     BYTE PTR SP_EFFECTPAR[EBP],0
        JE      NOPARM
        MOV     AL,BYTE PTR SP_EFFECTPAR[EBP]
        MOV     SP_PORTASPEED[EBP],AL
NOPARM: MOVZX   EBX,WORD PTR SP_NOTE[EBP*2]
        MOVZX   ECX,BX
        SHR     CL,4                    ; GET OCTAVE
        SHL     BL,4
        SHR     BL,4                    ; GET NOTE
        MOV     EAX,12
        MUL     ECX                     ; OCTAVE*12
        ADD     EAX,EBX
        MOVZX   EAX,WORD PTR PERIODTABLE[EAX*2]
        MOV     EBX,8363
        MUL     EBX
        MOVZX   EBX,WORD PTR SP_SAMPLENUM[EBP*2]
        CMP     EBX,0
        JNE     SAMPPO
        MOVZX   EBX,BYTE PTR SP_LASTSAMPLE[EBP]
SAMPPO: DEC     EBX
        MOVZX   EBX,WORD PTR SP_C2SPEEDS[EBX*2]
        MOV     EDX,0
        DIV     EBX
        MOV     WORD PTR SP_NOTE2PORTATO[EBP*2],AX
NONOTEP:POPAD
        JMP     NONOTE2

PORTATONOTE2:
        PUSHAD
        MOVZX   EBX,BYTE PTR SP_PORTASPEED[EBP]
        SHL     EBX,2
        MOV     AX,WORD PTR SP_NOTE2PORTATO[EBP*2]
        CMP     AX,WORD PTR SP_FREQS[EBP*2]
        JA      ADDNOTE
        CMP     WORD PTR SP_FREQS[EBP*2],BX
        JAE     P001
        MOV     BX,WORD PTR SP_NOTE2PORTATO[EBP*2]
        MOV     WORD PTR SP_FREQS[EBP*2],BX
P001:   SUB     WORD PTR SP_FREQS[EBP*2],BX
        MOV     BX,WORD PTR SP_FREQS[EBP*2]
        CMP     BX,WORD PTR SP_NOTE2PORTATO[EBP*2]
        JA      ENDPOR2N
        MOV     BX,WORD PTR SP_NOTE2PORTATO[EBP*2]
        MOV     WORD PTR SP_FREQS[EBP*2],BX
        JMP     ENDPOR2N
ADDNOTE:ADD     WORD PTR SP_FREQS[EBP*2],BX
        MOV     BX,WORD PTR SP_FREQS[EBP*2]
        CMP     BX,WORD PTR SP_NOTE2PORTATO[EBP*2]
        JB      ENDPOR2N
        MOV     BX,WORD PTR SP_NOTE2PORTATO[EBP*2]
        MOV     WORD PTR SP_FREQS[EBP*2],BX
ENDPOR2N:
        MOVZX   EBX,WORD PTR SP_FREQS[EBP*2]
        CMP     EBX,0
        JNE     OKFREQ2
        MOV     EBX,856                 ; SOMETHING MUST BE BUGGY IF THIS RUNS
OKFREQ2:MOV     EDX,0
        MOV     EAX,7159090*2
        DIV     EBX
        SHL     EAX,9
        MOV     EBX,SP_DIVIDER
        SHR     EBX,1
        ADD     EAX,EBX
        MOV     EDX,EAX
        MOVZX   EAX,AX
        SHR     EDX,16
        MOV     EBX,SP_DIVIDER
        DIV     BX
        SHL     EAX,1
        MOV     CX,AX
        CALL    GUSSETFREQ
        POPAD
        JMP     SKIP_EFFECTS2

;ББББББББББББББББББББББББ COMMAND 11: VIRATO AND VOLUME SLIDE БББББББББББББББББ

VIBRATOANDVOLUMESLIDE:
        MOV     AL,SP_EFFECTPAR[EBP]
        OR      AL,AL
        JNE     MEWVLS2
        MOV     AL,SP_LASTVOLSLIDE[EBP]
MEWVLS2:MOV     SP_LASTVOLSLIDE[EBP],AL
        CMP     AL,0F0H
        JE      MOLSLIDEUP23
        SHR     AL,4
        OR      AL,AL
        JE      MOLSLIDEDOWN2
        CMP     AL,0FH
        JE      MINEVOLDOWN2
MOLSLIDEUP23:
        MOV     AL,SP_LASTVOLSLIDE[EBP]
        TEST    AL,0FH
        JNE     MINEVOLUP2
MOLSLIDEUP22:
        SHR     AL,4
        ADD     GUSVOLUMES[EBP],AL
        CMP     GUSVOLUMES[EBP],40H
        JB      MSUSKIP2
        MOV     GUSVOLUMES[EBP],40H
MSUSKIP2:
        MOV     AL,GUSVOLUMES[EBP]
        CALL    GUSSETVOLUME
        JMP     SKIP_EFFECTS2
MOLSLIDEDOWN2:
        MOV     AL,SP_LASTVOLSLIDE[EBP]
        AND     AL,0FH
        SUB     GUSVOLUMES[EBP],AL
        CMP     GUSVOLUMES[EBP],0FFH
        JG      MSDSKIP2
        MOV     GUSVOLUMES[EBP],0
MSDSKIP2:
        MOV     AL,GUSVOLUMES[EBP]
        CALL    GUSSETVOLUME
        JMP     SKIP_EFFECTS2
MINEVOLDOWN2:
        MOV     SP_EFFECTNUM[EBP],0
        JMP     MOLSLIDEDOWN2
MINEVOLUP2:
        MOV     SP_EFFECTNUM[EBP],0
        JMP     MOLSLIDEUP22

;ББББББББББББББББББББББББ COMMAND 12: PORTA TO NOTE AND VOLUME SLIDE ББББББББББ

PORTAANDVOLUMESLIDE:
        MOV     AL,SP_EFFECTPAR[EBP]
        OR      AL,AL
        JNE     NEWVLS2
        MOV     AL,SP_LASTVOLSLIDE[EBP]
NEWVLS2:MOV     SP_LASTVOLSLIDE[EBP],AL
        CMP     AL,0F0H
        JE      VOLSLIDEUP23
        SHR     AL,4
        OR      AL,AL
        JE      VOLSLIDEDOWN2
        CMP     AL,0FH
        JE      FINEVOLDOWN2
VOLSLIDEUP23:
        MOV     AL,SP_LASTVOLSLIDE[EBP]
        TEST    AL,0FH
        JNE     FINEVOLUP2
VOLSLIDEUP22:
        SHR     AL,4
        ADD     GUSVOLUMES[EBP],AL
        CMP     GUSVOLUMES[EBP],40H
        JB      VSUSKIP2
        MOV     GUSVOLUMES[EBP],40H
VSUSKIP2:
        MOV     AL,GUSVOLUMES[EBP]
        CALL    GUSSETVOLUME
        JMP     PORTATONOTE2
VOLSLIDEDOWN2:
        MOV     AL,SP_LASTVOLSLIDE[EBP]
        AND     AL,0FH
        SUB     GUSVOLUMES[EBP],AL
        CMP     GUSVOLUMES[EBP],0FFH
        JG      VSDSKIP2
        MOV     GUSVOLUMES[EBP],0
VSDSKIP2:
        MOV     AL,GUSVOLUMES[EBP]
        CALL    GUSSETVOLUME
        JMP     PORTATONOTE2

FINEVOLDOWN2:
        MOV     SP_EFFECTNUM[EBP],0
        JMP     VOLSLIDEDOWN2
FINEVOLUP2:
        MOV     SP_EFFECTNUM[EBP],0
        JMP     VOLSLIDEUP22

;ББББББББББББББББББББББББ COMMAND 15: ARPEGGIO ББББББББББББББББББББББББББББББББ

ARPEGGIO:
        PUSHAD
        MOVZX   EAX,BYTE PTR SP_EFFECTPAR[EBP]
        CMP     EAX,0
        JNE     ARP01
        MOV     AL,SP_LASTARPEGGIO[EBP]
ARP01:  MOV     SP_LASTARPEGGIO[EBP],AL
        MOV     AL,SP_TICK
ARP03:  CMP     AL,03H
        JBE     ARP02
        SUB     AL,03H
        JMP     ARP03
ARP02:  MOV     BL,03H
        DIV     BL
        MOV     CL,AH
        MOV     AL,SP_LASTARPEGGIO[EBP]
        XOR     AH,AH
        CMP     CL,00H
        JE      ARP04
        CMP     CL,01H
        JE      ARP05
        SHL     AL,04H
ARP05:  SHR     AL,04H
        MOV     BX,WORD PTR SP_NOTE[EBP*2]
        CMP     BX,0000H
        JNE     ARP06
        MOV     CX,SP_LASTNOTE[EBP*2]
        MOV     CH,CL
        SHL     CH,04H
        SHR     CH,04H
        ADD     CH,AL
        CMP     CH,0CH
        JBE     ARP07
        ADD     AL,04H
ARP07:  ADD     AX,SP_LASTNOTE[EBP*2]
        MOV     WORD PTR SP_NOTE[EBP*2],AX
        JMP     ARP08
ARP06:  MOV     CX,BX
        MOV     CH,CL
        SHL     CH,04H
        SHR     CH,04H
        ADD     CH,AL
        CMP     CH,0CH
        JBE     ARP09
        ADD     AL,04H
ARP09:  ADD     WORD PTR SP_NOTE[EBP*2],AX
ARP08:  CALL    CALCFREQ
        MOV     WORD PTR SP_NOTE[EBP*2],BX
        JMP     ARP10
ARP04:  MOV     BX,WORD PTR SP_NOTE[EBP*2]
        MOV     AX,SP_LASTNOTE[EBP*2]
        CMP     AX,0000H
        JE      ARP10
        MOV     WORD PTR SP_NOTE[EBP*2],AX
        CALL    CALCFREQ
        MOV     WORD PTR SP_NOTE[EBP*2],BX
ARP10:  POPAD
        JMP     SKIP_EFFECTS2

;ББББББББББББББББББББББББ COMMAND 15: SAMPLE OFFSET БББББББББББББББББББББББББББ

SAMPLEOFFSET:
        PUSHAD
        MOVZX   EAX,BYTE PTR SP_EFFECTPAR[EBP]
        SHL     EAX,8
        MOVZX   EBX,SP_SAMPLENUM[EBP]
        MOVZX   EBX,BYTE PTR SP_SMPMODE[EBX]
        CMP     EBX,0
        JE      WASNOTDOUBLED
        SHR     EAX,1
        CMP     EBX,2
        JNE     WASNOTDOUBLED
        SHR     EAX,1
WASNOTDOUBLED:
        MOV     DWORD PTR SP_SAMPLEOFFSET[EBP*4],EAX
        POPAD
        JMP     SKIP_EFFECTS

;ББББББББББББББББББББББББ COMMAND 17: RETRIGGER NOTE ББББББББББББББББББББББББББ

RETRIGGERNOTE:
        PUSHAD
        MOV     AL,SP_EFFECTPAR[EBP]
        SHL     AL,04H
        SHR     AL,04H
        INC     BYTE PTR SP_RETRIGCOUNT[EBP]
        CMP     SP_RETRIGCOUNT[EBP],AL
        JNE     NORETRIGYET
        MOV     AL,SP_EFFECTPAR[EBP]
        SHR     AL,04H
        SHL     AL,04H
        CMP     AL,00H
        JE      RNOTE0
        CMP     AL,08H
        JE      RNOTE0
        CMP     AL,05H
        JA      RNOTE1
        MOV     CL,AL
        MOV     AL,01H
        DEC     CL
        SHL     AL,CL
        MOV     CL,GUSVOLUMES[EBP]
        CMP     CL,AL
        JB      RNOTE2
        SUB     GUSVOLUMES[EBP],AL
        JMP     RNOTE0
RNOTE2: MOV     BYTE PTR GUSVOLUMES[EBP],00H
        JMP     RNOTE0
RNOTE1: CMP     AL,07H
        JNE     RNOTE5
        SHR     BYTE PTR GUSVOLUMES[EBP],1
        JMP     RNOTE0
RNOTE5: CMP     AL,0FH
        JNE     RNOTE3
        CMP     BYTE PTR GUSVOLUMES[EBP],20H
        JBE     RNOTE4
        MOV     BYTE PTR GUSVOLUMES[EBP],40H
        JMP     RNOTE0
RNOTE4: SHL     BYTE PTR GUSVOLUMES[EBP],1
        JMP     RNOTE0
RNOTE3: CMP     AL,09H
        JB      RNOTE0
        CMP     AL,0DH
        JA      RNOTE0
        SUB     AL,09H
        MOV     CL,AL
        MOV     AL,01H
        SHL     AL,CL
        ADD     GUSVOLUMES[EBP],AL
        CMP     BYTE PTR GUSVOLUMES[EBP],40H
        JBE     RNOTE0
        MOV     BYTE PTR GUSVOLUMES[EBP],40H
RNOTE0: CALL    GUSSETVOLUME
        MOV     BYTE PTR SP_RETRIGCOUNT[EBP],0
        MOVZX   EBX,BYTE PTR SP_LASTSAMPLE[EBP]
        DEC     EBX
        CALL    GUSPLAYVOICE
NORETRIGYET:
        POPAD
        JMP     SKIP_EFFECTS2

;ББББББББББББББББББББББББ COMMAND 198: SET PAN POSITION БББББББББББББББББББББББ

SETPANPOS:
        PUSHAD
        MOVZX   EAX,BYTE PTR SP_EFFECTPAR[EBP]
        SHL     AL,4
        MOV     ECX,EAX
        CALL    GUSSETBALANCE
        POPAD
        JMP     SKIP_EFFECTS

;ББББББББББББББББББББББББ COMMAND 19A: OLD STEREO EFFECT ББББББББББББББББББББББ

OLDSTEREOEFFECT:
        PUSHAD
        MOVZX   EAX,BYTE PTR SP_EFFECTPAR[EBP]
        SHL     AL,4
        SHR     AL,4
        CMP     AL,0
        JNE     NOO0
        MOV     ECX,8*16
        JMP     OLDSS
NOO0:   CMP     AL,7
        JNE     NOO7
        MOV     ECX,15*16
        JMP     OLDSS
NOO7:   CMP     AL,8
        JNE     NOO8
        MOV     ECX,0
        JMP     OLDSS
NOO8:   MOV     ECX,7*16
OLDSS:  CALL    GUSSETBALANCE
        POPAD
        JMP     SKIP_EFFECTS

;ББББББББББББББББББББББББ COMMAND 19C: NOTE CUT БББББББББББББББББББББББББББББББ

NOTECUT:PUSHAD
        MOV     AL,SP_EFFECTPAR[EBP]
        SHL     AL,04H
        SHR     AL,04H
        CMP     AL,SP_TICK
        JNE     NOCUTYET
        MOV     BYTE PTR GUSVOLUMES[EBP],00H
        CALL    GUSSETVOLUME
NOCUTYET:
        POPAD
        JMP     SKIP_EFFECTS2

;ББББББББББББББББББББББББ COMMAND 19D: NOTE DELAY БББББББББББББББББББББББББББББ

NOTEDELAY2:
        PUSHAD
        MOV     AL,SP_EFFECTPAR[EBP]
        SHL     AL,04H
        SHR     AL,04H
        CMP     AL,SP_TICK
        JNE     NOTYETDELAY
        MOV     BYTE PTR SP_EFFECTNUM[EBP],00H
        MOV     BYTE PTR SP_EFFECTPAR[EBP],00H
        CALL    CALCFREQ
        MOVZX   EBX,WORD PTR SP_SAMPLENUM[EBP*2]
        DEC     EBX
        CMP     EBX,-1
        JNE     NDJMP1
        MOVZX   EBX,BYTE PTR SP_LASTSAMPLE[EBP]
        DEC     EBX
NDJMP1: CALL    GUSPLAYVOICE
NOTYETDELAY:
        POPAD
        JMP     SKIP_EFFECTS2

NOTEDELAY1:
        PUSHAD
        MOV     AL,SP_EFFECTPAR[EBP]
        SHL     AL,04
        SHR     AL,04
        CMP     AL,SP_SPEEDDEFAULT
        JBE     NND1
        MOV     BYTE PTR SP_EFFECTNUM[EBP],00H
        MOV     BYTE PTR SP_EFFECTPAR[EBP],00H
        MOV     WORD PTR SP_SAMPLENUM[EBP*2],0000H
        MOV     WORD PTR SP_NOTE[EBP*2],0000H
NND1:   POPAD
        JMP     NONOTE2

;ББББББББББББББББББББББББ COMMAND 20: SET TEMPO БББББББББББББББББББББББББББББББ

SETTEMPO:
        PUSHAD
        MOV     AL,BYTE PTR SP_EFFECTPAR[EBP]
        CMP     AL,1FH
        JA      SETBPM
        JMP     SKIP_EFFECTS
SETBPM: MOV     AH,0
        MOV     BX,AX
        MOV     DX,WORD PTR [SP_TIMERNUM+2]
        MOV     AX,WORD PTR [SP_TIMERNUM]
        DiV     BX
        MOV     BX,AX
        CLi
        MOV     AL,00110100B
        OUT     43H,AL
        MOV     AL,BL
        OUT     40H,AL
        MOV     AL,BH
        OUT     40H,AL
        STi
END20:  POPAD
        JMP     SKIP_EFFECTS

SETTEMPODEFAULT:
        PUSHAD
        MOV     AL,SP_TEMPODEFAULT
        MOV     AH,0
        MOV     BX,AX
        MOV     DX,WORD PTR [SP_TIMERNUM+2]
        MOV     AX,WORD PTR [SP_TIMERNUM]
        DiV     BX
        MOV     BX,AX
        CLi
        MOV     AL,00110100B
        OUT     43H,AL
        MOV     AL,BL
        OUT     40H,AL
        MOV     AL,BH
        OUT     40H,AL
        STi
        POPAD
        RET

;ББББББББББББББББББББББББ COMMAND 22: SET GLOBAL VOLUME БББББББББББББББББББББББ

SETGLOBALVOLUME:
        PUSHAD
        MOV     AL,SP_EFFECTPAR[EBP]
        CMP     AL,40H
        JA      NOSETGV
        MOV     SP_MASTERVOLUME,AL
        MOV     EBP,0
SGVOLLOOP:
        CALL    GUSSETVOLUME
        INC     EBP
        CMP     EBP,20H
        JNE     SGVOLLOOP
NOSETGV:POPAD
        JMP     SKIP_EFFECTS

;ББББББББББББББББББББББББ COMMAND 24: SET DMP PAN БББББББББББББББББББББББББББББ

SETDMPPAN:
        PUSHAD
        MOVZX   EAX,BYTE PTR SP_EFFECTPAR[EBP]
        MOV     ECX,EAX
        CALL    GUSSETBALANCE
        POPAD
        JMP     SKIP_EFFECTS

;БББББББББББББББББББББББББББ EXIT ROUTINES ББББББББББББББББББББББББББББББББББББ

ERROREXIT:
        MOV     EBX,SP_ERRORCODE
        SHL     EBX,2
        MOV     EDX,SP_MSGTABLE[EBX]
        MOV     EAX,0900H
        INT     21H
        MOV     EAX,4C00H
        INT     21H
        RET

DEBUGMESSAGE:
        PUSHAD
        MOV     EBX,SP_ERRORCODE
        SHL     EBX,2
        MOV     EDX,SP_MSGTABLE[EBX]
        MOV     EAX,0900H
        INT     21H
        POPAD
        RET

;ББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББ
;
; Shock! Play 32bit version by Tsc/Shock!
;
; Gravis UltraSound Routines
;
;ББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББ

;ББББББ ULTRASOUND DELAY ББББББББББББББББББББББББББББББББББББББББББББББББББББББ

GUSDELAY:
        PUSH    DX AX
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_DRAMIOPORT
        IN      AL,DX
        IN      AL,DX
        IN      AL,DX
        IN      AL,DX
        IN      AL,DX
        IN      AL,DX
        IN      AL,DX
        IN      AL,DX
        POP     AX DX
        RET

;ББББББ GUSPEEK - FROM SP_GUSLOCATION - TO AL БББББББББББББББББББББББББББББББББ

GUSPEEK:MOV     DX,SP_GUSBASE
        ADD     DX,SP_COMMANDPORT
        MOV     AL,SP_DRAMALO
        OUT     DX,AL
        INC     DX
        MOV     AX,WORD PTR [SP_GUSLOCATION]
        OUT     DX,AX
        DEC     DX
        MOV     AL,SP_DRAMAHI
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,BYTE PTR [SP_GUSLOCATION+2]
        OUT     DX,AL
        ADD     DX,2
        IN      AL,DX
        RET

;ББББББ GUSPOKE - FROM AL - TO SP_GUSLOCATION БББББББББББББББББББББББББББББББББ

GUSPOKE:PUSHAD
        MOV     CL,AL
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_COMMANDPORT
        MOV     AL,SP_DRAMALO
        OUT     DX,AL
        INC     DX
        MOV     AX,WORD PTR [SP_GUSLOCATION]
        OUT     DX,AX
        DEC     DX
        MOV     AL,SP_DRAMAHI
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,BYTE PTR [SP_GUSLOCATION+2]
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,CL
        OUT     DX,AL
        POPAD
        RET

;ББББББ GUSUPLOAD - UPLOADS SAMPLES TO GUS RAM ББББББББББББББББББББББББББББББББ
;
;       FROM:   SP_SMPADDRESS
;       TO:     SP_GUSLOCATION
;       AMOUNT: SP_UPLOADLENGTH
;       SIGN:   SP_SIGN
;       INCER:  SP_INCER
;
;ББББББ GUSUPLOAD - UPLOADS SAMPLES TO GUS RAM ББББББББББББББББББББББББББББББББ

GUSUPLOAD:
        PUSHAD
        MOV     AH,2
        MOV     DL,254
        INT     21H
        POPAD
        PUSHAD
        CLI
        MOV     CX,SP_UPLOADLENGTH
        CMP     CX,0
        JE      SKIPIT
        MOV     DI,WORD PTR [SP_GUSLOCATION]
        MOV     SI,WORD PTR [SP_GUSLOCATION+2]
        MOV     EBX,SP_SMPADDRESS
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_COMMANDPORT
        MOV     AL,SP_DRAMAHI
        OUT     DX,AL
        ADD     DX,2
        MOV     AX,SI
        OUT     DX,AL
        SUB     DX,2
GUSUPLOADLOOP:
        MOV     AL,SP_DRAMALO
        OUT     DX,AL
        INC     DX
        MOV     AX,DI
        OUT     DX,AX
        DEC     DX
DUMPBYTE:
        ADD     DX,4
        MOV     AL,[EBX]
        XOR     AL,SP_SIGN
        INC     EBX
        CMP     SP_INCER,0
        JE      NODOUBLEDSAMPLE
        INC     EBX
        CMP     SP_INCER,1
        JE      NOQUADREDSAMPLE
        ADD     EBX,2
NOQUADREDSAMPLE:
NODOUBLEDSAMPLE:
        OUT     DX,AL
        SUB     DX,4
        ADD     DI,1
        JNC     DUMPDOL
        INC     SI
        MOV     AL,SP_DRAMAHI
        OUT     DX,AL
        ADD     DX,2
        MOV     AX,SI
        OUT     DX,AL
        SUB     DX,2
DUMPDOL:LOOP    GUSUPLOADLOOP
SKIPIT: STI
        POPAD
        RET

;ББББББ GUSRESET - RESETS THE SOUNDCARD AT THE BEGINNING ББББББББББББББББББББББ

GUSRESET:
        PUSHAD
        CMP     SP_CHANNELS,14
        JG      NOT14
        MOV     SP_NUMVOICES,14
        JMP     ONLY14
NOT14:  MOV     EAX,SP_CHANNELS
        MOV     SP_NUMVOICES,AL
ONLY14: MOV     DX,SP_GUSBASE
        MOV     AL,2
        OUT     DX,AL
        XOR     AX,AX
        MOV     SP_GUSLOCATION,0
        CALL    GUSPOKE
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_COMMANDPORT
        MOV     AL,SP_INITIALIZE
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,0
        OUT     DX,AL
        MOV     ECX,10
DELAYLOOP1:
        CALL    GUSDELAY
        LOOP    DELAYLOOP1
        SUB     DX,2
        MOV     AL,SP_INITIALIZE
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,1
        OUT     DX,AL
        SUB     DX,5
        MOV     AL,3
        MOV     ECX,10
DELAYLOOP2:
        CALL    GUSDELAY
        LOOP    DELAYLOOP2
        MOV     AL,0
        OUT     DX,AL
        ADD     DX,3
        MOV     AL,SP_DMACONTROL
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,0
        OUT     DX,AL
        SUB     DX,2
        MOV     AL,SP_TIMERCONTROL
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,0
        OUT     DX,AL
        SUB     DX,2
        MOV     AL,SP_SMPCONTROL
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,0
        OUT     DX,AL
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_COMMANDPORT
        MOV     AL,SP_VOICESACTIVE
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,SP_NUMVOICES
        DEC     AL
        OR      AL,0C0H
        OUT     DX,AL
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_STATUSPORT
        IN      AL,DX
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_COMMANDPORT
        MOV     AL,SP_DMACONTROL
        OUT     DX,AL
        ADD     DX,2
        IN      AL,DX
        SUB     DX,2
        MOV     AL,49H
        OUT     DX,AL
        ADD     DX,2
        IN      AL,DX
        SUB     DX,22
        MOV     AL,8FH
        OUT     DX,AL
        ADD     DX,2
        IN      AL,DX
        MOV     ECX,32
VOICECLEARLOOP:
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_SELECTVOICE
        MOV     AL,CL
        DEC     AL
        OUT     DX,AL
        INC     DX
        MOV     AL,0
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,3
        OUT     DX,AL
        SUB     DX,2
        MOV     AL,0DH
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,3
        OUT     DX,AL
        CALL    GUSDELAY
        LOOP    VOICECLEARLOOP
        MOV     DX,SP_GUSBASE
        ADD     DX,6
        IN      AL,DX
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_COMMANDPORT
        MOV     AL,SP_DMACONTROL
        OUT     DX,AL
        ADD     DX,2
        IN      AL,DX
        SUB     DX,2
        MOV     AL,SP_SMPCONTROL
        OUT     DX,AL
        ADD     DX,2
        IN      AL,DX
        SUB     DX,2
        MOV     AL,8FH
        OUT     DX,AL
        ADD     DX,2
        IN      AL,DX
        SUB     DX,2
        MOV     AL,SP_INITIALIZE
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,7
        OUT     DX,AL
        MOV     DX,SP_GUSBASE
        MOV     AL,0
        OUT     DX,AL
        POPAD
        RET

;ББББББ GUSSETVOLUME - SETS A VOICE TO THE GIVEN VOLUME БББББББББББББББББББББББ
;
;       EBP - VOICE TO CHANGE
;       ECX - VOLUME
;
;ББББББ GUSSETVOLUME - SETS A VOICE TO THE GIVEN VOLUME БББББББББББББББББББББББ

GUSSETVOLUME:
        PUSHAD
        MOVZX   ECX,BYTE PTR GUSVOLUMES[EBP]
        MOVZX   EAX,BYTE PTR SP_MASTERVOLUME
        MUL     CX
        SHR     EAX,06H
        MOV     ECX,EAX
        MOV     AL,GUSMUTE[EBP]
        CMP     AL,0
        JE      NOMUTE
        MOV     ECX,0
NOMUTE: MOV     DX,SP_GUSBASE
        ADD     DX,SP_SELECTVOICE
        MOV     EAX,EBP
        OUT     DX,AL
        INC     DX
        MOV     AL,SP_SETVOLUME
        OUT     DX,AL
        INC     DX
        SHL     ECX,1
        MOV     AX,GUSVOL[ECX]
        OUT     DX,AX
        CALL    GUSDELAY
        OUT     DX,AX
        POPAD
        RET

;ББББББ GUSSETBALANCE - SETS A VOICE TO THE GIVEN BALANCE БББББББББББББББББББББ
;
;       EBP - VOICE TO CHANGE
;       ECX - BALANCE
;
;ББББББ GUSSETBALANCE - SETS A VOICE TO THE GIVEN BALANCE БББББББББББББББББББББ

GUSSETBALANCE:
        PUSHAD
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_SELECTVOICE
        MOV     EAX,EBP
        OUT     DX,AL
        INC     DX
        MOV     AL,SP_VOICEBALANCE
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,CL
        SHR     AL,4
        OUT     DX,AL
        POPAD
        RET

;ББББББ GUSSETFREQ - SETS A VOICE TO THE GIVEN FREQUENCY ББББББББББББББББББББББ
;
;       EBP - VOICE TO CHANGE
;       ECX - FREQUENCY
;
;ББББББ GUSSETFREQ - SETS A VOICE TO THE GIVEN FREQUENCY ББББББББББББББББББББББ

GUSSETFREQ:
        PUSHAD
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_SELECTVOICE
        MOV     EAX,EBP
        OUT     DX,AL
        INC     DX
        MOV     AL,SP_SETVOICEFREQ
        OUT     DX,AL
        INC     DX
        MOV     AX,CX
        OUT     DX,AX
        POPAD
        RET

;ББББББ GUSSTOPVOICE - STOPS A VOICE ББББББББББББББББББББББББББББББББББББББББББ
;
;       EBP - VOICE TO STOP
;
;ББББББ GUSSTOPVOICE - STOPS A VOICE ББББББББББББББББББББББББББББББББББББББББББ

GUSSTOPVOICE2:
        PUSHAD
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_SELECTVOICE
        MOV     EAX,EBP
        OUT     DX,AL
        INC     DX
        MOV     AL,0
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,3
        OUT     DX,AL
        SUB     DX,2
        MOV     AL,0DH
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,3
        OUT     DX,AL
        CALL    GUSDELAY
        POPAD
        RET

;ББББББ GUSPLAYVOICE - PLAYS A VOICE ББББББББББББББББББББББББББББББББББББББББББ
;
;       EBX - VOICE TO USE
;       EBP - SAMPLE TO PLAY
;
;ББББББ GUSPLAYVOICE - PLAYS A VOICE ББББББББББББББББББББББББББББББББББББББББББ

GUSPLAYVOICE:
        PUSHAD
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_SELECTVOICE
        MOV     EAX,EBP
        OUT     DX,AL
        MOV     AL,0
        CALL    DORAMP
        CALL    GUSSTOPVOICE2
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_SELECTVOICE
        MOV     EAX,EBP
        OUT     DX,AL
        MOV     DX,SP_GUSBASE
        ADD     DX,0103H
        MOV     AL,2
        OUT     DX,AL
        INC     DX
        MOV     AX,WORD PTR [SP_VSTART+EBX*4]
        MOV     CX,WORD PTR [SP_VSTART+2+EBX*4]
        CALL    RSHIFT
        OUT     DX,AX
        DEC     DX
        MOV     AL,3
        OUT     DX,AL
        INC     DX
        MOV     AX,WORD PTR [SP_VSTART+EBX*4]
        SHL     AX,9
        OUT     DX,AX
        DEC     DX
        MOV     AL,SP_SMPSTARTLO
        OUT     DX,AL
        INC     DX
        MOV     AX,WORD PTR [SP_VBEGIN+EBX*4]
        MOV     CX,WORD PTR [SP_VBEGIN+2+EBX*4]
        ADD     AX,WORD PTR [SP_SAMPLEOFFSET+EBP*4]
        ADC     CX,0
        CALL    RSHIFT
        OUT     DX,AX
        DEC     DX
        MOV     AL,SP_SMPSTARTHI
        OUT     DX,AL
        INC     DX
        MOV     AX,WORD PTR [SP_VBEGIN+EBX*4]
        ADD     AX,WORD PTR [SP_SAMPLEOFFSET+EBP*4]
        SHL     AX,9
        OUT     DX,AX
        DEC     DX
        MOV     AL,4
        OUT     DX,AL
        INC     DX
        MOV     AX,WORD PTR [SP_VEND+EBX*4]
        MOV     CX,WORD PTR [SP_VEND+2+EBX*4]
        CALL    RSHIFT
        OUT     DX,AX
        DEC     DX
        MOV     AL,5
        OUT     DX,AL
        INC     DX
        MOV     AX,WORD PTR [SP_VEND+EBX*4]
        SHL     AX,9
        OUT     DX,AX
        DEC     DX
        MOV     AL,0
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,SP_MODE[EBX]
        OUT     DX,AL
        POPAD
        RET

RSHIFT: PUSH    EBX
        MOV     BX,CX
        SHR     AX,7
        SHR     CX,7
        SHL     BX,9
        OR      AX,BX
        POP     EBX
        RET

;ББББББ GUSPORT DETECT ББББББББББББББББББББББББББББББББББББББББББББББББББББББББ
;
;       NO CARRY  - GUS AT SP_GUSBASE
;
;ББББББ GUSPORT DETECT ББББББББББББББББББББББББББББББББББББББББББББББББББББББББ

DETECTGUS:
        MOV     SP_GUSBASE,210H
TESTPRT:CALL    GUSPROBE
        JNB     FOUNDP
        ADD     SP_GUSBASE,10H
        CMP     SP_GUSBASE,270H
        JB      TESTPRT
        STC
        RET
FOUNDP: CLC
        RET

GUSPROBE:
        MOV     DX,SP_GUSBASE
        ADD     DX,0103H
        MOV     AL,4CH
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,0
        OUT     DX,AL
        CALL    GUSDELAY
        CALL    GUSDELAY
        SUB     DX,2
        MOV     AL,4CH
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,1
        OUT     DX,AL
        MOV     AX,0AAH
        MOV     BX,0
        MOV     CX,0
        PUSH    DX AX
        MOV     DX,SP_GUSBASE
        ADD     DX,103H
        MOV     AL,43H
        OUT     DX,AL
        iNC     DX
        MOV     AX,CX
        OUT     DX,AX
        DEC     DX
        MOV     AL,44H
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,BL
        OUT     DX,AL
        ADD     DX,2
        POP     AX
        OUT     DX,AL
        POP     DX
        MOV     AX,055H
        MOV     BX,1
        PUSH    DX AX
        MOV     DX,SP_GUSBASE
        ADD     DX,103H
        MOV     AL,43H
        OUT     DX,AL
        iNC     DX
        MOV     AX,CX
        OUT     DX,AX
        DEC     DX
        MOV     AL,44H
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,BL
        OUT     DX,AL
        ADD     DX,2
        POP     AX
        OUT     DX,AL
        POP     DX
        MOV     BX,0
        PUSH    DX
        MOV     DX,SP_GUSBASE
        ADD     DX,103H
        MOV     AL,43H
        OUT     DX,AL
        iNC     DX
        MOV     AX,CX
        OUT     DX,AX
        DEC     DX
        MOV     AL,44H
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,BL
        OUT     DX,AL
        ADD     DX,2
        iN      AL,DX
        POP     DX
        PUSH    AX
        MOV     AX,0
        PUSH    DX AX
        MOV     DX,SP_GUSBASE
        ADD     DX,103H
        MOV     AL,43H
        OUT     DX,AL
        iNC     DX
        MOV     AX,CX
        OUT     DX,AX
        DEC     DX
        MOV     AL,44H
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,BL
        OUT     DX,AL
        ADD     DX,2
        POP     AX
        OUT     DX,AL
        POP     DX
        SUB     DX,2
        MOV     AL,4CH
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,0
        OUT     DX,AL
        POP     AX
        CMP     AL,0AAH
        JNZ     NOFOUND
        CLC
        RET
NOFOUND:STC
        RET

;ББББББ GUS MEMORY SIZE DETECTION БББББББББББББББББББББББББББББББББББББББББББББ

DETECTGUSMEM:
        PUSHAD
        MOV     DWORD PTR SP_GUSLOCATION,800*1024
        MOV     AL,0FCH
        CALL    GUSPOKE
        CALL    GUSPEEK
        CMP     AL,0FCH
        JNE     NO1024K
        MOV     SP_ERRORCODE,12
        CALL    DEBUGMESSAGE
        MOV     SP_GUSMEMSIZE,1024*1024
        JMP     DETECTGUSMEMEND
NO1024K:
        MOV     DWORD PTR SP_GUSLOCATION,600*1024
        MOV     AL,0FCH
        CALL    GUSPOKE
        CALL    GUSPEEK
        CMP     AL,0FCH
        JNE     NO768K
        MOV     SP_ERRORCODE,11
        CALL    DEBUGMESSAGE
        MOV     SP_GUSMEMSIZE,768*1024
        JMP     DETECTGUSMEMEND
NO768K:
        MOV     DWORD PTR SP_GUSLOCATION,400*1024
        MOV     AL,0FCH
        CALL    GUSPOKE
        CALL    GUSPEEK
        CMP     AL,0FCH
        JNE     NO512K
        MOV     SP_ERRORCODE,10
        CALL    DEBUGMESSAGE
        MOV     SP_GUSMEMSIZE,512*1024
        JMP     DETECTGUSMEMEND
NO512K:
        MOV     SP_ERRORCODE,9
        CALL    DEBUGMESSAGE
        MOV     SP_GUSMEMSIZE,256*1024

DETECTGUSMEMEND:
        POPAD
        RET

;ББББББ THIS ROUTINE DECIDES WHETHER WE SHOULD DOUBLE THE DRAM OR NOT? ББББББББ

DETECTS3M2RAMSIZE:
        PUSHAD
        MOV     SP_SAMPLESSIZE,0
        MOV     ECX,0
UPLOOPTEST:
        MOVZX   EAX,WORD PTR SP_SMPLENGTHS[ECX*2]
        ADD     SP_SAMPLESSIZE,EAX
        INC     ECX                             ; COUNTING SIZE OF S3M
        MOV     AX,SP_NUMOFINST
        CMP     CX,SP_NUMOFINST
        JNE     UPLOOPTEST
        MOV     EAX,SP_SAMPLESSIZE
        CMP     EAX,SP_GUSMEMSIZE               ; IS DOUBLING NEEDED ?
        JBE     NODOUBLEMEMORY
        MOV     SP_ERRORCODE,13                 ; YES, YES YES
        CALL    DEBUGMESSAGE
        MOV     EBP,0
DOUBLINGLOOP1:
        CMP     BP,SP_NUMOFINST
        JA      ALLDOUBLED
        CMP     WORD PTR SP_SMPLENGTHS[EBP*2],10000
        JBE     NOBIGSAMPLE
        MOV     BYTE PTR SP_SMPMODE[EBP],1
        MOVZX   EAX,WORD PTR SP_SMPLENGTHS[EBP*2] ; HALVING SAMPLE LENGTH
        SHR     EAX,1
        MOV     WORD PTR SP_SMPLENGTHS[EBP*2],AX
        MOVZX   EAX,WORD PTR SP_LOOPSTARTS[EBP*2] ; HALVING SAMPLE LOOPSTART
        SHR     EAX,1
        MOV     WORD PTR SP_LOOPSTARTS[EBP*2],AX
        MOVZX   EAX,WORD PTR SP_LOOPLENGTHS[EBP*2] ; HALVING SAMPLE LOOPSTART
        SHR     EAX,1
        MOV     WORD PTR SP_LOOPLENGTHS[EBP*2],AX
        MOVZX   EAX,WORD PTR SP_C2SPEEDS[EBP*2] ; HALVING SAMPLE FREQUENCY
        SHR     EAX,1
        MOV     WORD PTR SP_C2SPEEDS[EBP*2],AX
        CALL    COUNTAGAIN
        MOV     EAX,SP_SAMPLESSIZE
        CMP     EAX,SP_GUSMEMSIZE               ; IS DOUBLING NEEDED ?
        JBE     NODOUBLEMEMORY
NOBIGSAMPLE:
        INC     EBP
        JMP     DOUBLINGLOOP1
ALLDOUBLED:
        MOV     EBP,0
DOUBLINGLOOP2:                                    ; SECOND LOOP FOR SMALL
        CMP     BP,SP_NUMOFINST                   ; SAMPLES TOO...
        JA      ALLDOUBLED2
        CMP     WORD PTR SP_SMPLENGTHS[EBP*2],10000
        JA      BIGSAMPLE
        MOV     BYTE PTR SP_SMPMODE[EBP],1
        MOVZX   EAX,WORD PTR SP_SMPLENGTHS[EBP*2] ; HALVING SAMPLE LENGTH
        SHR     EAX,1
        MOV     WORD PTR SP_SMPLENGTHS[EBP*2],AX
        MOVZX   EAX,WORD PTR SP_LOOPSTARTS[EBP*2] ; HALVING SAMPLE LOOPSTART
        SHR     EAX,1
        MOV     WORD PTR SP_LOOPSTARTS[EBP*2],AX
        MOVZX   EAX,WORD PTR SP_LOOPLENGTHS[EBP*2] ; HALVING SAMPLE LOOPSTART
        SHR     EAX,1
        MOV     WORD PTR SP_LOOPLENGTHS[EBP*2],AX
        MOVZX   EAX,WORD PTR SP_C2SPEEDS[EBP*2] ; HALVING SAMPLE FREQUENCY
        SHR     EAX,1
        MOV     WORD PTR SP_C2SPEEDS[EBP*2],AX
        CALL    COUNTAGAIN
        MOV     EAX,SP_SAMPLESSIZE
        CMP     EAX,SP_GUSMEMSIZE               ; IS DOUBLING NEEDED ?
        JBE     NODOUBLEMEMORY
BIGSAMPLE:
        INC     EBP
        JMP     DOUBLINGLOOP2
ALLDOUBLED2:
        MOV     SP_ERRORCODE,14                 ; QUADRINGMESSAGE
        CALL    DEBUGMESSAGE
        MOV     EBP,0
QUADRINGLOOP:
        CMP     BP,SP_NUMOFINST
        JA      ALLQUADRED                      ; KINDA WEIRD CASE...
        MOV     BYTE PTR SP_SMPMODE[EBP],2
        MOVZX   EAX,WORD PTR SP_SMPLENGTHS[EBP*2]
        SHR     EAX,1
        MOV     WORD PTR SP_SMPLENGTHS[EBP*2],AX
        MOVZX   EAX,WORD PTR SP_LOOPSTARTS[EBP*2] ; HALVING SAMPLE LOOPSTART
        SHR     EAX,1
        MOV     WORD PTR SP_LOOPSTARTS[EBP*2],AX
        MOVZX   EAX,WORD PTR SP_LOOPLENGTHS[EBP*2] ; HALVING SAMPLE LOOPSTART
        SHR     EAX,1
        MOV     WORD PTR SP_LOOPLENGTHS[EBP*2],AX
        MOVZX   EAX,WORD PTR SP_C2SPEEDS[EBP*2] ; HALVING SAMPLE FREQUENCY
        SHR     EAX,1
        MOV     WORD PTR SP_C2SPEEDS[EBP*2],AX
        CALL    COUNTAGAIN
        MOV     EAX,SP_SAMPLESSIZE
        CMP     EAX,SP_GUSMEMSIZE
        JBE     NODOUBLEMEMORY
        INC     EBP
        JMP     QUADRINGLOOP
ALLQUADRED:

NODOUBLEMEMORY:
        POPAD
        RET

COUNTAGAIN:
        PUSHAD
        MOV     SP_SAMPLESSIZE,0
        MOV     ECX,0
UPLOOPTESTAGAIN:
        MOVZX   EAX,WORD PTR SP_SMPLENGTHS[ECX*2]
        ADD     SP_SAMPLESSIZE,EAX
        INC     ECX                             ; COUNTING SIZE OF S3M
        MOV     AX,SP_NUMOFINST
        CMP     CX,SP_NUMOFINST
        JNE     UPLOOPTESTAGAIN
        POPAD
        RET

;ББББББ RAMP DOWN БББББББББББББББББББББББББББББББББББББББББББББББББББББББББББББ

RAMPDOWN:
        PUSHAD
        MOV     DX,SP_GUSBASE
        ADD     DX,103H
        MOV     EAX,EBP
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,01000011B
        OUT     DX,AL
        SUB     DX,2
        MOV     AL,89H
        OUT     DX,AL
        INC     DX
        IN      AX,DX
        MOV     BX,AX
        DEC     DX
        MOV     AL,8
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,BH
        OUT     DX,AL
        SUB     DX,2
        MOV     AL,7
        OUT     DX,AL
        ADD     DX,2
        MOV     AX,1
        OUT     DX,AL
        SUB     DX,2
        MOV     AL,6
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,00111111B
        OUT     DX,AL
        MOV     DX,SP_GUSBASE
        ADD     DX,103H
        MOV     AL,0DH
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,01000000B
        OUT     DX,AL
        POPAD
        RET

DORAMP: PUSH    BX Si
        MOV     AH,0
        CMP     SP_MASTERVOLUME,0
        JZ      @@ZEROVOL
        MUL     SP_MASTERVOLUME
        iNC     AH
@@ZEROVOL:
        MOV     BL,AH
        MOVZX   EBX,BL
        SHL     BX,1
        MOV     AX,WORD PTR GUSVOL[EBX*2]
        JMP     SLiDERAMP2
SLiDERAMP:
        PUSH    BX Si
SLiDERAMP2:
        MOV     Si,AX
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_COMMANDPORT
        MOV     AL,0DH
        OUT     DX,AL
        ADD     DL,2
        MOV     AL,3
        OUT     DX,AL
        SUB     DL,2
        MOV     AL,89H
        OUT     DX,AL
        iNC     DX
        iN      AX,DX
        PUSH    Si
        PUSH    AX
        SHR     AX,8
        SHR     Si,8
        CMP     AX,Si
        JZ      @@DONE2
        JB      @@OK
        XCHG    Si,AX
@@OK:   PUSH    AX
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_COMMANDPORT
        MOV     AL,7
        OUT     DX,AL
        ADD     DX,2
        POP     AX
        OUT     DX,AL
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_COMMANDPORT
        MOV     AL,8
        OUT     DX,AL
        ADD     DX,2
        MOV     AX,Si
        OUT     DX,AL
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_COMMANDPORT
        MOV     AL,6
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,00111111B
        OUT     DX,AL
        MOV     BL,00000000B
        POP     AX
        POP     Si
        CMP     AX,Si
        JB      @@OK2
        OR      BL,01000000B
@@OK2:
        MOV     DX,SP_GUSBASE
        ADD     DX,SP_COMMANDPORT
        MOV     AL,0DH
        OUT     DX,AL
        ADD     DX,2
        MOV     AL,BL
        OUT     DX,AL
        JMP     @@DONE
@@DONE2:POP     AX AX
@@DONE: POP     Si BX
        RET

        END
