Metropoli BBS
VIEWER: musgus.asm MODE: TEXT (CP437)
segment         GUSSound
assume          cs:GUSSound,ds:GUSSound

StartSoundSeg   = $

proc            MUS
                push    ax bx cx dx bp ds es
                push    ax
                mov     ax,cs
                mov     ds,ax
                mov     es,ax
                pop     ax
                cld
                cmp     bx,0fh
                ja      @@HigherThanWeCount
                cmp     bx,0
                jz      @@DoIt
                cmp     [cs:MUSOK],1
                jnz     @@HigherThanWeCount
@@DoIt:         shl     bx,1
                call    [Word bx+JumpTable]
@@HigherThanWeCount:
                pop     es ds bp dx cx bx ax
                retf
endp            MUS

                db      13,10,'Gravis UltraSound MOD Routines v2.1',0
                db      13,10,'By Joshua C. Jensen',0
JumpTable       dw      offset MUS_Init                 ; Function 00
                dw      offset MUS_Close                ; Function 01
                dw      offset MUS_SetVars              ; Function 02
                dw      offset MUS_Nothing              ; Function 03
                dw      offset MUS_PlayMusic            ; Function 04
                dw      offset MUS_StopMusic            ; Function 05
		dw	offset MUS_Nothing		; Function 06
                dw      offset MUS_SpeakerOn            ; Function 07
                dw      offset MUS_SpeakerOff           ; Function 08
                dw      offset MUS_ReturnInfo           ; Function 09
                dw      offset MUS_SetInfo              ; Function 0A
                dw      offset MUS_RetVoice             ; Function 0B
                dw      offset MUS_RetMusicStatus       ; Function 0C
                dw      offset MUS_DumpSampleDRAM       ; Function 0D

;include	 "ptable.inc"

MUSOK           db      0
PS16Header:
Sig		db	'PS16■'
SongName	db	75 dup (0)
SongLen 	db	0
numpatterns	db	0
commentofs	dd	0
Sequences	db	128 dup (0)
Samples 	db	31*size PS16Sample dup (0)
PS16Size	=	$-PS16Header

PatternLoc      dw      64 dup (0)
InsLoc          dd      32 dup (0)
NumPatterns     dw      0
Mus             SMus    <>
NumLines	db	0
MusBuf		dw	0
ChannelMap	db	32 dup (0)
ChannelPriority db	32 dup (0)

include         "vect.rt"

;▓────────────────────────────────────────────────────────────────────────────▓
; MUS_Nothing - Dead...
;▓────────────────────────────────────────────────────────────────────────────▓
proc            MUS_Nothing near
                ret
endp            MUS_Nothing

;▓────────────────────────────────────────────────────────────────────────────▓
; MUS_Init - Initialize the music routines.
;   AX - GF1 IRQ     (0 for detect)
;   CX - MIDI IRQ
;   DX - Base port   (0 for detect)
;   SI - DMA IN
;   DI - DMA OUT
;   Carry set - No Gravis Ultrasound
; Returns:
;   SI - IRQ
;   DI - Port
;▓────────────────────────────────────────────────────────────────────────────▓
proc            MUS_Init near
                call    u_DetectGUS
                jnb     @@FoundGUS
                xor     si,si
                xor     di,di
                ret
@@FoundGUS:     mov     bx,[cs:GUSIRQ]
                mov     si,cs
                mov     di,offset GUSInt
                call    SetVect
                mov     [Word cs:IntStore],di
                mov     [Word cs:IntStore+2],si
                call    u_Reset
                call    MUS_SetMaxVolume
		mov	[Word cs:Mus+(offset (SMus).HeaderLoc)],offset PS16Header
                mov     [Word cs:Mus+(offset (SMus).HeaderLoc)+2],cs
;		 mov	 [Word cs:Mus+(offset (SMus).AnalyzerLoc)],offset AnalyzerHeights
;		 mov	 [Word cs:Mus+(offset (SMus).AnalyzerLoc)+2],cs
                mov     [Word cs:Mus+(offset (SMus).PatternLoc)],offset PatternLoc
                mov     [Word cs:Mus+(offset (SMus).PatternLoc)+2],cs
                mov     [Word cs:Mus+(offset (SMus).InsLoc)],offset InsLoc
                mov     [Word cs:Mus+(offset (SMus).InsLoc)+2],cs
                mov     [Word cs:Mus+(offset (SMus).ChannelLoc)],offset Channel1
                mov     [Word cs:Mus+(offset (SMus).ChannelLoc)+2],cs
                mov     [Word cs:Mus+(offset (SMus).mt_PeriodTable)],offset mt_PeriodTable
                mov     [Word cs:Mus+(offset (SMus).mt_PeriodTable)+2],cs
                mov     [Byte cs:MUSOK],1
                mov     si,[cs:GUSIRQ]
                mov     di,[cs:u_Base]
                clc
                ret
endp            MUS_Init


;▓────────────────────────────────────────────────────────────────────────────▓
; MUS_Close - Kill all allocated segs, etc.
;▓────────────────────────────────────────────────────────────────────────────▓
proc            MUS_Close near
                call    MUS_StopMusic
                call    u_Reset
                mov     bx,[cs:GUSIRQ]
                mov     di,[Word cs:IntStore]
                mov     si,[Word cs:IntStore+2]
                call    RestoreVect
                mov     [Byte cs:MUSOK],0
                ret
endp            MUS_Close


;▓────────────────────────────────────────────────────────────────────────────▓
; MUS_SetVars - Sets various parameters for the card.
;   AX - Sampling Rate (on SB, ignored here...)
;   CL - Max Volume Setting
;   CH - IRQ = 0 if default
;   DX - GUS address
;▓────────────────────────────────────────────────────────────────────────────▓
proc            MUS_SetVars near
                mov     [cs:MaxVolume],cl
                or      ch,ch
                jz      @@NoIRQChange
                mov     [Byte cs:GUSIRQ],ch
@@NoIRQChange:  or      dx,dx
                jz      @@NoAddrChange
                mov     [cs:u_Base],dx
                add     dx,102h
                mov     [cs:u_Voice],dx
                inc     dx
                mov     [cs:u_Command],dx
                inc     dx
                mov     [cs:u_DataLo],dx
                inc     dx
                mov     [cs:u_DataHi],dx
                mov     dx,[cs:u_Base]
                add     dx,6
                mov     [cs:u_Status],dx
                add     dx,2
                mov     [cs:u_TimerControl],dx
                inc     dx
                mov     [cs:u_TimerData],dx
@@NoAddrChange: ret
endp            MUS_SetVars


;▓────────────────────────────────────────────────────────────────────────────▓
; MUS_PlayMusic - Make proper calls and interrupt sets for module playing.
; In: cx:si - PM Structure
;▓────────────────────────────────────────────────────────────────────────────▓

proc            MUS_PlayMusic near
                push    ds
                mov     ds,cx
		mov	ax,[si+(offset (PM).MusBuf)+2]
		mov	[cs:MusBuf],ax
		mov	ax,[si+PM.mt_speed]
                cmp     ax,-1
                jz      @@SkipSpeed
                mov     [Word cs:mt_speed],ax
@@SkipSpeed:    mov     ax,[si+PM.mt_counter]
                cmp     ax,-1
                jz      @@SkipCounter
                mov     [Word cs:mt_counter],ax
@@SkipCounter:  mov     ax,[si+PM.mt_SongPos]
                mov     [word cs:mt_SongPos],ax
                mov     ax,[si+PM.mt_PatternPos]
                mov     [Word cs:mt_PatternPos],ax
                mov     ax,cs
                mov     es,ax
		mov	di,offset PS16Header
                push    ds si
                lds     si,[si+PM.Header]
		mov	cx,PS16Size
                rep     movsb
                pop     si ds
                mov     di,offset PatternLoc
                push    ds si
                lds     si,[si+PM.PatternLoc]
                mov     cx,64*2
                rep     movsb
                pop     si ds
                mov     di,offset InsLoc
                push    ds si
                lds     si,[si+PM.InsLoc]
                mov     cx,32*4
                rep     movsb
                pop     si ds
                mov     [Byte cs:MStatus],0
		call	MUS_SetVoice
		call	u_Reset
                mov     bx,6
                call    u_TurnOnUserInt
                pop     ds
                ret
endp            MUS_PlayMusic


;▓────────────────────────────────────────────────────────────────────────────▓
; MUS_StopMusic - Shuts down the interrupts for generating music.
;▓────────────────────────────────────────────────────────────────────────────▓

proc            MUS_StopMusic near
                mov     [Byte cs:MStatus],1
                call    u_TurnOffUserInt
                call    u_Reset
                ret
endp            MUS_StopMusic


;▓────────────────────────────────────────────────────────────────────────────▓
; MUS_SpeakerOn - Turns output speaker on.
;▓────────────────────────────────────────────────────────────────────────────▓
proc            MUS_SpeakerOn near
                mov     dx,[cs:u_Base]
                mov     al,00000000b
                out     dx,al
                ret
endp            MUS_SpeakerOn


;▓────────────────────────────────────────────────────────────────────────────▓
; MUS_SpeakerOff - Turns output speaker off.
;▓────────────────────────────────────────────────────────────────────────────▓
proc            MUS_SpeakerOff near
                mov     dx,[cs:u_Base]
                mov     al,00000010b
                out     dx,al
                ret
endp            MUS_SpeakerOff

;▓────────────────────────────────────────────────────────────────────────────▓
; MUS_ReturnInfo - Returns the SMUS structure location in SI:DI.
; In:
;   CX - 1 = Copy info to SI:DI.
;        0 = Just return pointer.
;▓────────────────────────────────────────────────────────────────────────────▓
proc            MUS_ReturnInfo near
                mov     ax,[cs:NumPatterns]
                mov     [cs:offset Mus+(offset (SMus).NumPatterns)],ax
                mov     al,[cs:mt_speed]
                mov     [cs:offset Mus+(offset (SMus).mt_speed)],al
                mov     al,[cs:mt_counter]
                mov     [cs:offset Mus+(offset (SMus).mt_counter)],al
                mov     ax,[cs:mt_PatternPos]
                mov     [cs:offset Mus+(offset (SMus).mt_PatternPos)],ax
                mov     al,[cs:mt_SongPos]
                mov     [cs:offset Mus+(offset (SMus).mt_SongPos)],al
                mov     al,[cs:PlayStatus]
                mov     [cs:offset Mus+(offset (SMus).PlayStatus)],al
                mov     ax,[cs:EditSeg]
                mov     [cs:offset Mus+(offset (SMus).EditSeg)],ax
                mov     ax,[cs:EditPat]
                mov     [cs:offset Mus+(offset (SMus).EditPat)],ax
                mov     ax,[cs:EditOfs]
                mov     [cs:offset Mus+(offset (SMus).EditOfs)],ax
                mov     al,[cs:MaxVolume]
                mov     [cs:offset Mus+(offset (SMus).MaxVolume)],al
		mov	al,[cs:SongLen]
                mov     [cs:offset Mus+(offset (SMus).songlen)],al
                or      cx,cx
                jnz     @@CopyIt
                mov     si,cs
                mov     di,offset Mus
                ret
@@CopyIt:       push    ds es
                mov     es,si
                mov     ax,cs
                mov     ds,ax
                mov     si,offset Mus
                mov     cx,size Mus
                rep     movsb
                pop     es ds
                ret
endp            MUS_ReturnInfo

;▓────────────────────────────────────────────────────────────────────────────▓
; MUS_SetInfo - Sets the SMUS structure location to whatever is in SI:DI.
; In:
;   CX - 1 = Set Max Volume
;        2 = Set Pattern Info
;▓────────────────────────────────────────────────────────────────────────────▓
proc            MUS_SetInfo near
                push    cx ds es
                mov     ds,si
                mov     si,di
                mov     ax,cs
                mov     es,ax
                mov     di,offset Mus
                mov     cx,size Mus
                rep     movsb
                pop     es ds
                pop     cx
                cli
                mov     ax,[cs:offset Mus+(offset (SMus).NumPatterns)]
                mov     [cs:NumPatterns],ax
                test    cx,2
                jz      @@SkipSetPat
                mov     al,[cs:offset Mus+(offset (SMus).mt_speed)]
                mov     [cs:mt_speed],al
                mov     al,[cs:offset Mus+(offset (SMus).mt_counter)]
                mov     [cs:mt_counter],al
                mov     ax,[cs:offset Mus+(offset (SMus).mt_PatternPos)]
                mov     [cs:mt_PatternPos],ax
                mov     [cs:EditOfs],ax
                mov     al,[cs:offset Mus+(offset (SMus).mt_SongPos)]
                mov     [cs:mt_SongPos],al
                mov     [Byte PTr cs:EditPat],al
                mov     al,[cs:offset Mus+(offset (SMus).PlayStatus)]
                mov     [cs:PlayStatus],al
@@SkipSetPat:   mov     al,[cs:offset Mus+(offset (SMus).MaxVolume)]
                mov     [cs:MaxVolume],al
                mov     al,[cs:offset Mus+(offset (SMus).songlen)]
		mov	[cs:SongLen],al
                test    cx,1
                jz      @@Leave
                call    MUS_SetMaxVolume
@@Leave:        sti
                ret
endp            MUS_SetInfo

;▓────────────────────────────────────────────────────────────────────────────▓
; MUS_RetVoice
;   In: AX - Voice
;       ES:DX - Buffer from DRAM
;       CX - Length
;▓────────────────────────────────────────────────────────────────────────────▓
; Dump sample to DRAM
;   ES:BX - Max 64k sample to dump to RAM.
;   SI:DI - DRAM location to dump to.
;   CX    - Max bytes to dump.
;   AH    - Xor value.
proc            MUS_RetVoice near
                call    u_ReadPos
                call    u_Peek
                mov     si,ax
                ret
endp            MUS_RetVoice


;▓────────────────────────────────────────────────────────────────────────────▓
; MUS_RetMusicStatus
;  Out: SI - 1  Music Stopped
;       DI - 1  Scope Triggered
;▓────────────────────────────────────────────────────────────────────────────▓
proc            MUS_RetMusicStatus near
                mov     al,[cs:MStatus]
                xor     ah,ah
                mov     si,ax
                mov     al,[cs:Trigger]
                xor     ah,ah
                mov     di,ax
                mov     [Byte cs:Trigger],0
                ret
endp            MUS_RetMusicStatus


;▓────────────────────────────────────────────────────────────────────────────▓
; MUS_DumpSampleDRAM
; CX - Sample Size
; SI:DI - Place in DRAM
; AX - Handle
;▓────────────────────────────────────────────────────────────────────────────▓
proc            MUS_DumpSampleDRAM near
                mov     bx,ax
                call    LoadDumpSample
                ret
endp            MUS_DumpSampleDRAM

; CX - Sample Size
; SI:DI - Place in DRAM
; BX - Handle
; DX - Sample Seg to read
LDSeg           dw      0
proc            LoadDumpSample near
                push    cx bx
		mov	[cs:LDSeg],dx
                pop     bx
                push    ds
                mov     ah,3Fh
                mov     dx,0
                mov     ds,[cs:LDSeg]
                int     21h
                pop     ds

                pop     cx
                mov     es,[cs:LDSeg]
                mov     bx,0
                mov     ah,0
                call    u_DumpSampleToDRAM
                ret
endp            LoadDumpSample

;▓────────────────────────────────────────────────────────────────────────────▓
; MUS_SetMaxVolume - Set the Master volumes for the channels to the max value.
;▓────────────────────────────────────────────────────────────────────────────▓
proc            MUS_SetMaxVolume near
                mov     al,[Byte cs:MaxVolume]
                mov     [cs:offset Channel1+(offset (MS).MasterVolume)],al
                mov     [cs:offset Channel2+(offset (MS).MasterVolume)],al
                mov     [cs:offset Channel3+(offset (MS).MasterVolume)],al
                mov     [cs:offset Channel4+(offset (MS).MasterVolume)],al
                ret
endp            MUS_SetMaxVolume

;▓────────────────────────────────────────────────────────────────────────────▓
; MUS_SetVoice -
;▓────────────────────────────────────────────────────────────────────────────▓
proc		MUS_SetVoice near
		mov	cx,16
		mov	bx,offset Channel1
@@Looper:	mov	ax,0
		mov	[Word cs:bx+MS.start],ax
		mov	ax,0f000h
		mov	[Word cs:bx+(offset (MS).start)+2],ax
		add	bx,size MS
		loop	@@Looper
		ret
endp		MUS_SetVoice

; GUS card routines.

MaxVoices	= 31

IntStore        dd      0

MIDIIRQ         dw      0
GUSIRQ          dw      0
DMAIn           dw      0
DMAOut          dw      0
u_Base          dw      0

proc    UDelay
        push    dx ax
        mov     dx,300h
        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
endp    UDelay

; BX:CX Set to whatever.
proc    u_Peek
        pushf
        cli
        push    dx
        mov     dx,[cs:u_Command]
        mov     al,43h
        out     dx,al
        inc     dx                      ; 104h
        mov     ax,cx
        out     dx,ax
        dec     dx                      ; 103h
        mov     al,44h
        out     dx,al
        add     dx,2
        mov     al,bl
        out     dx,al
        add     dx,2
        in      al,dx
        pop     dx
        popf
        ret
endp    u_Peek

; BX:CX Set to whatever.
; AX Value to poke
proc    u_Poke
        pushf
        cli
        push    dx ax
        mov     dx,[cs:u_Command]
        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
        in      al,dx
        pop     dx
        popf
        ret
endp    u_Poke


; DX - u_Base.
proc    u_Probe
        pushf
        cli
        mov     dx,[cs:u_Command]
        mov     al,4Ch
        out     dx,al
        add     dx,2                    ; 105h
        mov     al,0
        out     dx,al
        call    UDelay
        call    UDelay
        sub     dx,2                    ; 103h
        mov     al,4Ch
        out     dx,al
        add     dx,2                    ; 105h
        mov     al,1
        out     dx,al
        call    UDelay
        call    UDelay
        mov     ax,0AAh
        mov     bx,0
        mov     cx,0
        call    u_Poke
        mov     ax,055h
        mov     bx,1
        call    u_Poke
        mov     bx,0
        call    u_Peek
        push    ax
        mov     ax,0
        call    u_Poke
        sub     dx,2                    ; 103h
        mov     al,4Ch
        out     dx,al
        add     dx,2                    ; 105h
        mov     al,0
        out     dx,al
        pop     ax
        popf
        cmp     al,0AAh
        jnz     @@Nope
        clc
        ret
@@Nope: stc
        ret
endp    u_Probe

GUSChangeIRQ    db      0,0,1,3,0,2,0,4,0,0,0,5,6,0,0,7
GUSChangeDMA    db      1,0,2,0,3,4,5
                       ;1       5
proc    u_SetInterface
        cmp     [Word cs:GUSIRQ],0
        jz      @@Exit
        cli
        mov     bx,[cs:MIDIIRQ]
        mov     cl,[cs:bx+GUSChangeIRQ]
        shl     cl,3
        mov     bx,[cs:GUSIRQ]
        or      cl,[cs:bx+GUSChangeIRQ]
        cmp     bx,[cs:MIDIIRQ]
        jnz     @@JustStore
        or      cl,40h
@@JustStore:
        push    cx
        mov     bx,[cs:DMAOut]
        dec     bx
        mov     cl,[cs:bx+GUSChangeDMA]
        mov     dx,cx
        shl     dl,3
        mov     bx,[cs:DMAIn]
        dec     bx
        mov     cl,[cs:bx+GUSChangeDMA]
        inc     bx
        cmp     bx,[cs:DMAOut]
        jnz     @@Fix
        or      cl,40h
        jmp     @@JustStore2
@@Fix:  or      cl,dl
@@JustStore2:
        mov     bl,cl
        pop     cx
        mov     dx,[cs:u_Base]
        mov     al,8
        out     dx,al
        add     dx,0Bh
        mov     al,bl
        or      al,80h
        out     dx,al
        mov     dx,[cs:u_Base]
        mov     al,48h
        out     dx,al
        add     dx,0Bh
        mov     al,cl
        out     dx,al
        mov     dx,[cs:u_Base]
        mov     al,8
        out     dx,al
        add     dx,0Bh
        mov     al,bl
        out     dx,al
        mov     dx,[cs:u_Base]
        mov     al,48h
        out     dx,al
        add     dx,0Bh
        mov     al,cl
        out     dx,al
        mov     dx,[cs:u_Base]
        add     dx,102h
        mov     al,0
        out     dx,al
        mov     dx,[cs:u_Base]
        mov     al,9
        out     dx,al
        mov     dx,[cs:u_Base]
        add     dx,102h
        mov     al,0
        out     dx,al
        sti
@@Exit: ret
endp    u_SetInterface

proc    u_Reset
        call    u_SetInterface
        cli
        mov     bx,[cs:u_Command]
        mov     cx,[cs:u_DataHi]
        mov     dx,bx
        mov     al,4Ch
        out     dx,al
        mov     dx,cx
        mov     al,0
        out     dx,al
        call    UDelay
        call    UDelay
        mov     dx,bx
        mov     al,4Ch
        out     dx,al
        mov     dx,cx
        mov     al,1
        out     dx,al
        call    UDelay
        call    UDelay

        mov     dx,[cs:u_Voice]
        add     dx,100h
        mov     al,3
        out     dx,al
        call    UDelay
        mov     dx,[cs:u_Voice]
        add     dx,100h
        mov     al,0
        out     dx,al


        mov     dx,bx
        mov     al,41h
        out     dx,al
        mov     dx,cx
        mov     al,0
        out     dx,al
        mov     dx,bx
        mov     al,45h
        out     dx,al
        mov     dx,cx
        mov     al,0
        out     dx,al
        mov     dx,bx
        mov     al,49h
        out     dx,al
        mov     dx,cx
        mov     al,0
        out     dx,al

        mov     dx,bx
        mov     al,0Eh
        out     dx,al
        add     dx,2
        mov     al,MaxVoices
        or      al,0C0h
        out     dx,al

        mov     dx,[cs:u_Status]
        in      al,dx
        mov     dx,bx
        mov     al,41h
        out     dx,al
        mov     dx,cx
        in      al,dx
        mov     dx,bx
        mov     al,49h
        out     dx,al
        mov     dx,cx
        in      al,dx
        mov     dx,bx
        mov     al,8Fh
        out     dx,al
        mov     dx,cx
        in      al,dx

        push    bx cx
        mov     cx,0
@@VoiceClearLoop:
        mov     dx,[cs:u_Voice]
        mov     al,cl
        out     dx,al
        inc     dx
        mov     al,9
        out     dx,al
        inc     dl
        mov     ax,0
        out     dx,ax
        dec     dl
        mov     al,0
        out     dx,al
        add     dx,2
        mov     al,3                    ; Turn voice off
        out     dx,al
        sub     dx,2
        mov     al,0Dh
        out     dx,al
        add     dx,2
        mov     al,3
        out     dx,al
        sub     dx,2
        inc     cx
        cmp     cx,32
        jnz     @@VoiceClearLoop
        pop     cx bx

        mov     dx,bx
        mov     al,41h
        out     dx,al
        mov     dx,cx
        in      al,dx
        mov     dx,bx
        mov     al,49h
        out     dx,al
        mov     dx,cx
        in      al,dx
        mov     dx,bx
        mov     al,8Fh
        out     dx,al
        mov     dx,cx
        in      al,dx

        mov     dx,bx
        mov     al,4Ch
        out     dx,al
        mov     dx,cx
        mov     al,7
        out     dx,al
        sti
        ret
endp    u_Reset

; CX:AX  - Number
proc    RShift
        mov     bx,cx
        shr     ax,7
        shr     cx,7
        shl     bx,9
        or      ax,bx
        ret
endp    RShift

; AX - Voice
; Returns:  DX:AX - Position
proc    u_ReadPos
        pushf
        cli
        mov     dx,[cs:u_Voice]
        out     dx,al
        inc     dx              ; 103h
        mov     al,8ah
        out     dx,al
        inc     dx              ; 104h
        in      ax,dx           ; TEMP0
        mov     cx,ax
        dec     dx              ; 103h
        mov     al,8bh
        out     dx,al
        inc     dx              ; 104h
        in      ax,dx           ; TEMP1
        xor     dx,dx
        mov     bx,cx
        shl     cx,7
        shl     dx,7
        shr     bx,9
        or      dx,bx
        shr     ax,9
        and     ax,7Fh
        or      cx,ax
        mov     ax,cx
        popf
        ret
endp    u_ReadPos

; Dump sample to DRAM
;   ES:BX - Max 64k sample to dump to RAM.
;   SI:DI - DRAM location to dump to.
;   CX    - Max bytes to dump.
;   AH    - Xor value.
proc    u_DumpSampleToDRAM
        cli
        push    cx
        mov     dx,[cs:u_Command]
        mov     al,44h          ; Dump upper byte, only do it on carry from now
        out     dx,al           ; on.
        add     dx,2
        push    ax
        mov     ax,si
        out     dx,al
        pop     ax
        sub     dx,2
@@MainLoop:
        mov     al,43h
        out     dx,al
        inc     dx
        push    ax
        mov     ax,di
        out     dx,ax
        pop     ax
        dec     dx
@@DumpByte:
        add     dx,4
        mov     al,[es:bx]
        xor     al,ah
        inc     bx
        out     dx,al
        sub     dx,4
        add     di,1
        jnc     @@DoLoop
        inc     si
        mov     al,44h
        out     dx,al
        add     dx,2
        push    ax
        mov     ax,si
        out     dx,al
        pop     ax
        sub     dx,2
@@DoLoop:
        loop    @@MainLoop
        pop     cx
        sti
        ret
endp    u_DumpSampleToDRAM

u_Voice         dw      0
u_Command       dw      0
u_DataLo        dw      0
u_DataHi        dw      0
u_Status        dw      0
u_TimerControl  dw      0
u_TimerData     dw      0
u_adlibcontrol  db      0
u_timermask     db      0
u_IRQs          db      2,3,5,7,11,12,15
u_IntStore      dd      0,0,0,0,0,0,0

proc    u_SetPorts
        mov     dx,[cs:u_Base]
        add     dx,102h
        mov     [cs:u_Voice],dx
        inc     dx
        mov     [cs:u_Command],dx
        inc     dx
        mov     [cs:u_DataLo],dx
        inc     dx
        mov     [cs:u_DataHi],dx
        mov     dx,[cs:u_Base]
        add     dx,6
        mov     [cs:u_Status],dx
        add     dx,2
        mov     [cs:u_TimerControl],dx
        inc     dx
        mov     [cs:u_TimerData],dx
        ret
endp    u_SetPorts

; In:
;   DX - Base   (0 for detect)
;   CX - MIDI IRQ
;   AX - IRQ    (0 for detect)
; Carry set - No GUS
; No carry  - GUS at u_Base
proc    u_DetectGUS
        mov     [cs:GUSIRQ],ax
        mov     [cs:MIDIIRQ],cx
        mov     [cs:DMAIn],si
        mov     [cs:DMAOut],di
        mov     [cs:u_Base],dx
        call    u_SetPorts
        clc
        ret
endp    u_DetectGUS

; bx - Speed (0-255)  (* 80 microseconds)
proc            u_TurnOnUserInt
                cli
                or      [Byte cs:u_adlibcontrol],4
                or      [Byte cs:u_timermask],1
                mov     dx,[cs:u_Command]
                mov     al,46h
                out     dx,al
                add     dx,2
                mov     al,bl
                out     dx,al
                sub     dx,2
                mov     al,45h
                out     dx,al
                add     dx,2
                mov     al,[cs:u_adlibcontrol]
                out     dx,al
                mov     dx,[cs:u_TimerControl]
                mov     al,4
                out     dx,al
                inc     dx
                mov     al,[cs:u_timermask]
                out     dx,al
                sti
                ret
endp            u_TurnOnUserInt

proc            u_TurnOffUserInt
                cli
                and     [Byte cs:u_adlibcontrol],0FBh
                and     [Byte cs:u_timermask],0FEh
                mov     dx,[cs:u_Command]
                mov     al,45h
                out     dx,al
                add     dx,2
                mov     al,[cs:u_adlibcontrol]
                out     dx,al
                call    u_Reset
                sti
                ret
endp            u_TurnOffUserInt

irqstatus       db      0

proc            GUSInt
                pusha
                push    ds es
		mov	dx,[cs:u_Status]
                in      al,dx
                mov     [cs:irqstatus],al
@@TopOfInt:     test    [Byte cs:irqstatus],4
                jz      @@CheckNext
                mov     dx,[cs:u_Command]
                mov     al,45h
                out     dx,al
                and     [Byte cs:u_adlibcontrol],0FBh
                add     dx,2
                mov     al,[cs:u_adlibcontrol]
                out     dx,al
                or      [Byte cs:u_adlibcontrol],4
                mov     al,[cs:u_adlibcontrol]
                out     dx,al
		call	sd_UpdateChannels
                cmp     [Byte cs:MStatus],1
                jnz     @@CheckNext
                call    u_TurnOffUserInt
                call    u_Reset
@@CheckNext:    mov     dx,[cs:u_Command]
                mov     al,8Fh
                out     dx,al
                add     dx,2
                in      al,dx
@@Finish:
                mov     al,20h
                out     0A0h,al
                mov     al,20h
                out     20h,al
                sti

                pop     es ds
                popa
                iret
endp            GUSInt


proc		FindOpenChannel
		mov	bx,0
@@Looper:	cmp	[cs:bx+ChannelMap],0
		jz	@@Open
		inc	bx
		cmp	bx,32
		jnz	@@Looper

		; If we made it this far, check the priorities to turn one off.
		mov	dx,0
		mov	cx,0FFh 	; Max Priority
		mov	bx,0
@@PLooper:	cmp	[cs:bx+ChannelPriority],cl
		jl	@@Change
		jmp	@@IncIt
@@Change:	mov	cl,[cs:bx+ChannelPriority]
		mov	dx,bx
@@IncIt:        inc     bx
		cmp	bx,32
		jnz	@@PLooper
		mov	bx,ax


@@Open: 	mov	ax,bx
		ret
endp            FindOpenChannel

;┌──────────────────────────────────────────────────────────────────────────┐
;│││──────────────────────── Protracker Stuff ────────────────────────────│││
;└──────────────────────────────────────────────────────────────────────────┘
;┌─┐ Protracker specific
;└─┘ variables.
mt_speed                db      6
mt_counter              db      0
mt_PatternPos           dw      0
mt_SongPos              db      0
mt_PattDelayTime2       db      0
mt_PattDelayTime        db      0
mt_PBreakFlag           db      0
mt_PBreakPos            db      0
mt_PosJumpFlag          db      0
mt_LowMask              db      0FFh
Trigger                 db      0

mt_VibratoTable:        db        0, 24, 49, 74, 97,120,141,161
                        db      180,197,212,224,235,244,250,253
                        db      255,253,250,244,235,224,212,197
                        db      180,161,141,120, 97, 74, 49, 24

Channel1  MS <0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4 , 0,0,0>
Channel2  MS <0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11, 1,0,0>
Channel3  MS <0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11, 2,0,0>
Channel4  MS <0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4 , 3,0,0>
Channel5  MS <0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4 , 4,0,0>
Channel6  MS <0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11, 5,0,0>
Channel7  MS <0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11, 6,0,0>
Channel8  MS <0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4 , 7,0,0>
Channel9  MS <0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4 , 8,0,0>
Channel10 MS <0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11, 9,0,0>
Channel11 MS <0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,10,0,0>
Channel12 MS <0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4 ,11,0,0>
Channel13 MS <0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4 ,12,0,0>
Channel14 MS <0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,13,0,0>
Channel15 MS <0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,14,0,0>
Channel16 MS <0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4 ,15,0,0>


PlayStatus      db      1
MStatus         db      0
EditPat         dw      0
EditSeg         dw      0
EditOfs         dw      0
ChangeIns       db      0
MaxVolume	db	200
EfxFlag         db      0

mt_VolTable	dw	00E00h,0B000h,0B800h,0BC00h,0BE00h,0C000h,0C400h,0C800h,0CC00h
		dw	0D000h,0D200h,0D400h,0D600h,0D800h,0DA00h,0DC00h,0DE00h
		dw	0E000h,0E100h,0E200h,0E300h,0E400h,0E500h,0E600h,0E700h
		dw	0E800h,0E900h,0EA00h,0EB00h,0EC00h,0ED00h,0EE00h,0EF00h
		dw	0F080h,0F100h,0F180h,0F200h,0F280h,0F300h,0F380h,0F400h
		dw	0F480h,0F500h,0F580h,0F600h,0F680h,0F700h,0F780h,0F800h
		dw	0F880h,0F900h,0F980h,0FA00h,0FA80h,0FB00h,0FB80h,0FC00h
                dw      0FC80h,0FD00h,0FD80h,0FE00h,0FE80h,0FF00h,0FF80h,0FFF0h

include "period.asm"

macro   SetVoice
        mov     [Byte cs:Voice],cl
        mov     dx,[cs:u_Voice]
        mov     al,[cs:si+MS.sc_Voice]
        out     dx,al
endm    SetVoice

Voice   db      0

macro   PlayVol
        local   Done
        mov     dx,[cs:u_Command]
        mov     al,89h
        out     dx,al
        inc     dl
        in      ax,dx
        cmp     ax,[cs:si+MS.sc_Vol]
        jz      Done
        mov     ax,[cs:si+MS.sc_Vol]
        call    slideramp
Done:
endm    PlayVol

macro   PlayNote
        local   Done
        mov     dx,[cs:u_Command]
        mov     al,81h
        out     dx,al
        inc     dl
        in      ax,dx
        cmp     ax,[cs:si+MS.sc_Note]
        jz      Done
        dec     dl
        mov     al,1
        out     dx,al
        inc     dl
        mov     ax,[cs:si+MS.sc_Note]
        out     dx,ax
Done:
endm    PlayNote

proc		DecompressPattern near
		push	di
		mov	ax,es
		mov	ds,ax
		mov	ax,[cs:MusBuf]
		mov	es,ax
		mov	di,0
		mov	cx,3072/2
		mov	ax,0
		rep	stosw
		mov	si,0
		mov	di,0
                mov     al,[si+2]
		mov	[cs:NumLines],al
		add	si,3
		mov	cx,0
@@ChannelLoop:	push	cx
		mov	di,cx
		shl	cx,1
		add	di,cx			; * 3
@@LineLoop:	xor	ah,ah
		lodsb
		cmp	al,-1
		jz	@@NextChannel
		push	di
		mov	bx,ax
		shl	ax,5			; * 32
		shl	bx,4			; * 16
		add	di,ax
		add	di,bx
		movsb
		movsw
		pop	di
		jmp	@@LineLoop
@@NextChannel:	pop	cx
		inc	cx
		cmp	cx,16
		jnz	@@ChannelLoop
		pop	di
		ret
endp            DecompressPattern

;╒═══════════════════════════════════════════════════════════════════════════╕
;│ NAME       : sd_UpdateChannels                                            │
;│              *** Original code: Amiga Protracker by Lars Hamre.           │
;│              *** Converted by Joshua C. Jensen.                           │
;╘═══════════════════════════════════════════════════════════════════════════╛
proc    DecProc near
        cmp     [cs:si+MS.DecVolume],0
        ja      @@AllRight
        mov     [Byte cs:si+MS.DecVolume],1
@@AllRight:
        dec     [Byte cs:si+MS.DecVolume]
        ret
endp    DecProc

proc    sd_UpdateChannels near
        mov     ax,cs
        mov     ds,ax
        mov     es,ax

mt_ContinueUpdate:
        inc     [Byte cs:mt_counter]
        mov     al,[cs:mt_counter]
        cmp     al,[cs:mt_speed]
        jb      mt_NoNewNote
        mov     [Byte cs:mt_counter],0
        cmp     [Byte cs:mt_PattDelayTime2],0
        jz      mt_GetNewNote
        call    mt_NoNewAllChannels
        jmp     mt_dskip

mt_NoNewNote:
        call    mt_NoNewAllChannels
        jmp     mt_NoNewPosYet

mt_NoNewAllChannels:
	mov	cx,16
        mov     si,offset Channel1
mt_NoNewLoop:
        push    cx si
        call    DecProc
        SetVoice
	call	mt_CheckEfx
        PlayNote
        PlayVol
        pop     si
        add     si,size MS
        pop     cx
        loop    mt_NoNewLoop
	ret

mt_GetNewNote:
        xor     ax,ax
        mov     al,[cs:mt_SongPos]
        mov     di,ax
        mov     [Word cs:EditPat],ax
	mov	al,[cs:di+Sequences]
        shl     al,1
        mov     di,offset PatternLoc
        add     di,ax
        mov     es,[cs:di]
        mov     di,[cs:mt_PatternPos]
	call	DecompressPattern
	mov	[Word cs:EditSeg],es
        mov     [Word cs:EditOfs],di

	mov	cx,16
        mov     si,offset Channel1
mt_GetNewLoop:
        push    cx si
        call    DecProc
        SetVoice
        call    mt_PlayVoice
        PlayNote
        PlayVol
        pop     si
        add     si,size MS
        pop     cx
        loop    mt_GetNewLoop
        jmp     mt_dskip

mt_PlayVoice:
        mov     [Byte cs:EfxFlag],0
        mov     [Byte cs:ChangeIns],0
	cmp	[Byte cs:si],0
        jnz     mt_plvskip
	cmp	[Word cs:si+1],0
        jnz     mt_plvskip
        call    mt_PerNop
mt_plvskip:
	mov	al,[es:di]
	mov	[cs:si+MS.note],al
	mov	ax,[es:di+1]
        mov     [Word cs:si+MS.cmd],ax
	add	di,3

        mov     al,[cs:si+MS.cmd]
        and     al,0F0h
        shr     al,4
        mov     ah,[Byte cs:si+MS.note]
	and	ah,11000000b
	shr	ah,2
        or      al,ah                   ; Is there an ins?
        jz      mt_SetRegisters
        mov     [Byte cs:ChangeIns],1
        mov     [cs:si+MS.sc_Mode],0
        dec     al
        mov     bl,al
        mov     [cs:si+MS.SampleNum],al
	mov	bh,size PS16Sample
	mul	bh
	mov	dx,ax

        xor     bh,bh
        shl     bx,2
        add     bx,offset InsLoc
        mov     ax,[cs:bx]
        mov     [Word cs:si+MS.start],ax
        mov     ax,[cs:bx+2]
        mov     [Word cs:si+(offset (MS).start)+2],ax
	mov	bx,dx
	add	bx,offset Samples
	mov	cx,[cs:bx+PS16Sample.length]
        mov     [Word cs:si+MS.length],cx
        mov     [Word cs:si+(offset (MS).length)+2],0
	mov	ax,[Word cs:bx+PS16Sample.volume]
        mov     [Word cs:si+MS.finetune],ax
        mov     al,ah
        call    volequ

	mov	cx,[cs:bx+PS16Sample.replen]; Get the Repeat length.
        cmp     cx,2
        jbe     mt_NoLoop
        or      [Byte cs:si+MS.sc_Mode],00001000b
	mov	cx,[cs:bx+PS16Sample.repeat]
        or      cx,cx
        je      mt_LoopNoFix
	dec	cx
mt_LoopNoFix:
        mov     ax,[Word cs:si+MS.start]
        mov     dx,[Word cs:si+(offset (MS).start)+2]
        add     ax,cx
        adc     dx,0
        mov     [Word cs:si+MS.loopstart],ax
        mov     [Word cs:si+(offset (MS).loopstart)+2],dx
        mov     [Word cs:si+MS.wavestart],ax
        mov     [Word cs:si+(offset (MS).wavestart)+2],dx
	mov	cx,[Word cs:bx+PS16Sample.replen]
;	 dec	 cx
	add	ax,cx
        adc     dx,0
        mov     [Word cs:si+MS.replen],ax
        mov     [Word cs:si+(offset (MS).replen)+2],dx
        jmp     mt_SetRegisters
mt_NoLoop:
        mov     ax,[Word cs:si+MS.start]
        mov     dx,[Word cs:si+(offset (MS).start)+2]
        mov     [Word cs:si+MS.loopstart],ax
        mov     [Word cs:si+(offset (MS).loopstart)+2],dx
        mov     [Word cs:si+MS.wavestart],ax
        mov     [Word cs:si+(offset (MS).wavestart)+2],dx
	mov	cx,[Word cs:bx+PS16Sample.length]
        dec     cx
        add     ax,cx
        adc     dx,0
        mov     [Word cs:si+MS.replen],ax
        mov     [Word cs:si+(offset (MS).replen)+2],dx
mt_SetRegisters:
	mov	al,[cs:si+MS.note]
	and	al,00111111b
        jnz     mt_ThereIsANote
        jmp     mt_CheckMoreEfx
mt_ThereIsANote:
        mov     ax,[Word cs:si+MS.cmd]
        xchg    ah,al
        and     ax,0FF0h
        cmp     ax,0E50h
        jz      mt_DoSetFineTune
        cmp     ah,3                    ; Is it a tone portamento?
        jz      mt_ChkTonePorta
        cmp     ah,5                    ; Is it a tone and volume slide?
        jz      mt_ChkTonePorta
        cmp     ah,9                    ; Is it a sample offset command?
        jnz     mt_SetPeriod
        call    mt_CheckMoreEfx
        jmp     mt_SetPeriod

mt_DoSetFineTune:
        call    mt_SetFineTune
        jmp     mt_SetPeriod

mt_ChkTonePorta:
        call    mt_SetTonePorta
        jmp     mt_CheckMoreEfx

mt_SetPeriod:
        mov     [Byte cs:ChangeIns],1
	mov	bl,[cs:si+MS.note]
	and	bx,00111111b
	dec	bx
	shl	bx,1
	mov	al,[cs:si+MS.finetune]
	mov	cl,61*2
        mul     cl
        add     bx,ax
	mov	ax,[Word cs:bx+mt_PeriodTable]
        mov     [cs:si+MS.period],ax

        mov     ax,[Word cs:si+MS.cmd]
        xchg    ah,al
        and     ax,0FF0h
        cmp     ax,0ED0h
        jnz     mt_NotANoteCut
        jmp     mt_CheckMoreEfx
mt_NotANoteCut:
        mov     al,[cs:si+MS.wavecontrol]  ; Get the wavecontrol.
        and     al,00000100b            ; Amiga: BTST #2,wavecontrol.
        jz      mt_vibnoc               ; If it is zero, then skip.
        mov     [Byte cs:si+MS.vibratopos],0
mt_vibnoc:
        mov     al,[cs:si+MS.wavecontrol]  ; Get it again.
        and     al,01000000b            ; Amiga: BTST #6,wavecontrol
        jz      mt_trenoc               ; If it is zero, then skip.
        mov     [Byte cs:si+MS.tremolopos],0 ; Zero the Tremolo offset.
mt_trenoc:
        cmp     [Byte cs:ChangeIns],1
        jnz     mt_SetGeneral
mt_DoIns:
        ; high byte of sample start == F000H, turn off the voice
        cmp     [Word cs:si+(offset (MS).start)+2],0f000h
        jz      @@NoVoice
        push    dx ax
        mov     al,0
        call    doramp
        mov     dx,[cs:u_Command]
        mov     al,0
        out     dx,al
        mov     al,3
        add     dl,2
        out     dx,al
	xor	[cs:si+MS.sc_Voice],16
        mov     dx,[cs:u_Voice]
        mov     al,[cs:si+MS.sc_Voice]
        out     dx,al
        pop     ax dx

        ; Send sample begin
@@DoBegin:
        mov     dx,[cs:u_Command]
        mov     al,0ah
        out     dx,al
        inc     dx              ; 104h
        mov     ax,[Word cs:si+MS.start]
        mov     cx,[Word cs:si+(offset (MS).start)+2]
        call    RShift
        out     dx,ax
        dec     dx              ; 103h
        mov     al,0bh
        out     dx,al
        inc     dx              ; 104h
        mov     ax,[Word cs:si+MS.start]
        shl     ax,9
        out     dx,ax

        mov     dx,[cs:u_Command]
        mov     al,2
        out     dx,al
        inc     dx              ; 104h
        mov     ax,[Word cs:si+MS.loopstart]
        mov     cx,[Word cs:si+(offset (MS).loopstart)+2]
        call    RShift
        out     dx,ax
        dec     dx              ; 103h
        mov     al,3
        out     dx,al
        inc     dx              ; 104h
        mov     ax,[Word cs:si+MS.loopstart]
        shl     ax,9
        out     dx,ax

        mov     dx,[cs:u_Command]
        mov     al,4
        out     dx,al
        inc     dx              ; 104h
        mov     ax,[Word cs:si+MS.replen]
        mov     cx,[Word cs:si+(offset (MS).replen)+2]
        call    RShift
        out     dx,ax
        dec     dx              ; 103h
        mov     al,5
        out     dx,al
        inc     dx              ; 104h
        mov     ax,[Word cs:si+MS.replen]
        shl     ax,9
        out     dx,ax
        dec     dx              ; 103h
        mov     al,0
        out     dx,al
        add     dx,2
        mov     al,[Byte cs:si+MS.sc_Mode]
        out     dx,al
mt_SetGeneral:
        call    mt_PerNop
        mov     dx,[cs:u_Command]
        mov     al,0ch
        out     dx,al
        add     dx,2
        mov     al,[cs:si+MS.sc_PanPosition]
        out     dx,al
        sub     dx,2
        jmp     @@Bottom

;       Shuts off the voice
@@NoVoice:
        mov     al,0
        call    doramp
        mov     al,0
        out     dx,al
        add     dl,2
        mov     al,3
        out     dx,al
@@Bottom:
@@Done:
        mov     ax,[cs:si+MS.period]
;	 call	 SpectrumAnalyzer
;        ST      n_trigger(A6)
        mov     [Byte cs:Trigger],1
        cmp     [Byte cs:EfxFlag],1
        jz      @@Skip
        call    mt_CheckMoreEfx
@@Skip: ret
endp    sd_UpdateChannels

proc    mt_dskip near
        mov     [Word cs:EditSeg],es
        mov     ax,[Word cs:mt_PatternPos]
        mov     [Word cs:EditOfs],ax
	add	[Word cs:mt_PatternPos],48
        mov     al,[cs:mt_PattDelayTime]
        or      al,al
        jz      mt_dskc
        mov     [cs:mt_PattDelayTime2],al
        mov     [Byte cs:mt_PattDelayTime],0
mt_dskc:
        cmp     [Byte cs:mt_PattDelayTime2],0
        jz      mt_dska
        dec     [Byte cs:mt_PattDelayTime2]
        jz      mt_dska
	sub	[Word cs:mt_PatternPos],48
mt_dska:
        cmp     [Byte cs:mt_PBreakFlag],0
        jz      mt_nnpysk
        mov     [Byte cs:mt_PBreakFlag],0
        xor     ax,ax
        mov     al,[cs:mt_PBreakPos]
        mov     [cs:mt_PBreakPos],ah
	mov	bx,48
        mul     bx
	mov	[cs:mt_PatternPos],ax
mt_nnpysk:
	cmp	[Word cs:mt_PatternPos],1024*3
        jb      mt_NoNewPosYet

mt_NextPosition:
        xor     ax,ax
        mov     al,[cs:mt_PBreakPos]
	mov	bx,48
	mul	bx
        mov     [cs:mt_PatternPos],ax
        mov     [Byte cs:mt_PBreakPos],0
        mov     [Byte cs:mt_PosJumpFlag],0
        inc     [Byte cs:mt_SongPos]
        and     [Byte cs:mt_SongPos],7Fh
        mov     al,[cs:mt_SongPos]
	cmp	al,[cs:SongLen]
        jnz     mt_NoNewPosYet
        mov     [Byte cs:mt_SongPos],0
        cmp     [Byte cs:PlayStatus],1
        jnz     @@Quit
        mov     [Byte cs:mt_SongPos],0
        ret
;---------------------------------------------------
@@Quit: mov     [Byte cs:MStatus],1
        mov     [Byte cs:mt_SongPos],0
        ret

mt_NoNewPosYet:
        cmp     [Byte cs:mt_PosJumpFlag],0
        jnz     mt_NextPosition
        ret
endp    mt_dskip

proc    mt_CheckEfx near
	mov	ax,[Word cs:si+MS.cmd]
        xchg    al,ah
        and     ax,0FFFh
        jz      mt_Return
        mov     bl,[cs:si+MS.cmd]
        and     bl,0Fh
        cmp     bl,0
        jz      mt_Arpeggio
        cmp     bl,1
        jz      mt_PortaUp
        cmp     bl,2
        jz      mt_PortaDown
        cmp     bl,3
        jz      mt_TonePortamento
        cmp     bl,4
        jz      mt_Vibrato
        cmp     bl,5
        jz      mt_TonePlusVolSlide
        cmp     bl,6
        jz      mt_VibratoPlusVolSlide
        cmp     bl,0Eh
        jz      mt_E_Commands
SetBack:call    mt_PerNop
        cmp     bl,7
        jz      mt_Tremolo
        cmp     bl,0Ah
        jz      mt_VolumeSlide
mt_Return:
        ret
endp    mt_CheckEfx

; Effect 0 -- Arpeggio
proc    mt_Arpeggio near
        xor     ax,ax
        mov     al,[cs:mt_counter]
        mov     bl,3
        div     bl
        xchg    al,ah
        cmp     al,1
        jz      mt_Arpeggio1
        cmp     al,2
        jz      mt_Arpeggio2
mt_Arpeggio0:
        mov     cx,[cs:si+MS.period]
        jmp     ArpeggioSet

mt_Arpeggio1:
        xor     ax,ax
        mov     al,[Byte cs:si+MS.cmdlo]
        shr     al,4
        jmp     ArpeggioFind

mt_Arpeggio2:
        xor     ax,ax
        mov     al,[cs:si+MS.cmdlo]
        and     al,15
ArpeggioFind:
        shl     ax,1
        mov     bx,ax
        mov     al,[cs:si+MS.finetune]
	mov	cl,61*2
        mul     cl
        mov     dx,[cs:si+MS.period]
        push    di
        mov     di,offset mt_PeriodTable
        add     di,ax
	mov	cx,60
mt_arploop:
        mov     ax,[cs:bx+di]
        cmp     dx,[cs:di]
        jnb     mt_arpafterloop
        add     di,2
        loop    mt_arploop
        pop     di
        ret
mt_arpafterloop:
        pop     di
        mov     cx,ax

ArpeggioSet:
        call    mt_PerNop2
        ret
endp    mt_Arpeggio

; Effect 1 -- Portamento Up
proc    mt_PortaUp near
        xor     ax,ax
        mov     al,[cs:si+MS.cmdlo]
        and     al,[cs:mt_LowMask]
        mov     [Byte cs:mt_LowMask],0FFh
        sub     [cs:si+MS.period],ax
        mov     cx,[cs:si+MS.period]
        and     cx,0FFFh
        cmp     cx,71h
        jnb     mt_PortaUSkip
        and     [cs:si+MS.period],0F000h
        or      [cs:si+MS.period],71h
mt_PortaUSkip:
        mov     cx,[cs:si+MS.period]
        and     cx,0FFFh
        call    mt_PerNop
        ret
endp    mt_PortaUp


; Effect 2 -- Portamento Down
proc    mt_PortaDown near
        xor     ax,ax
        mov     al,[cs:si+MS.cmdlo]
        and     al,[cs:mt_LowMask]
        mov     [Byte cs:mt_LowMask],0FFh
        add     [cs:si+MS.period],ax
        mov     cx,[cs:si+MS.period]
        and     cx,0FFFh
        cmp     cx,358h
        jb      mt_PortaDSkip
        and     [cs:si+MS.period],0F000h
        or      [cs:si+MS.period],856
mt_PortaDSkip:
        mov     cx,[cs:si+MS.period]
        and     cx,0FFFh
        call    mt_PerNop
        ret
endp    mt_PortaDown

proc    mt_SetTonePorta near
        push    di
	mov	di,offset mt_PeriodTable
        mov     bl,[cs:si+MS.note]
	and	bx,00111111b
	dec	bx
	shl	bx,1
	mov	dx,[Word cs:bx+di]
        xor     ax,ax
        mov     al,[cs:si+MS.finetune]
	mov	cl,61*2
        mul     cl
        add     di,ax
        mov     bx,0
mt_StpLoop:
        cmp     dx,[cs:bx+di]
        jnb     mt_StpFound
        add     bx,2
	cmp	bx,61*2
        jb      mt_StpLoop
	mov	bx,59*2
mt_StpFound:
        mov     dl,[cs:si+MS.finetune]
        and     dl,8
        jz      mt_StpGoss
        or      bx,bx
        jz      mt_StpGoss
        sub     bx,2
mt_StpGoss:
        mov     dx,[cs:bx+di]
        pop     di
        mov     [cs:si+MS.wantedperiod],dx
        mov     ax,[cs:si+MS.period]
        mov     [Byte cs:si+MS.toneportdirec],0
        cmp     dx,ax
        jz      mt_ClearTonePorta
        jnb     mt_Return
        mov     [Byte cs:si+MS.toneportdirec],1
        ret

mt_ClearTonePorta:
        mov     [Word cs:si+MS.wantedperiod],0
        ret
endp    mt_SetTonePorta


; Effect 3 -- Tone Portamento
proc    mt_TonePortamento near
        mov     al,[cs:si+MS.cmdlo]
        or      al,al
        jz      mt_TonePortNoChange
        mov     [cs:si+MS.toneportspeed],al
        mov     [Byte cs:si+MS.cmdlo],0
mt_TonePortNoChange:
        cmp     [Word cs:si+MS.wantedperiod],0
        jz      mt_Return
        xor     ax,ax
        mov     al,[cs:si+MS.toneportspeed]
        cmp     [Byte cs:si+MS.toneportdirec],0
        jnz     mt_TonePortaUp
mt_TonePortaDown:
        add     [cs:si+MS.period],ax
        mov     ax,[cs:si+MS.wantedperiod]
        cmp     ax,[cs:si+MS.period]
        jg      mt_TonePortaSetPer
        mov     [cs:si+MS.period],ax
        mov     [Word cs:si+MS.wantedperiod],0
        jmp     mt_TonePortaSetPer

mt_TonePortaUp:
        sub     [cs:si+MS.period],ax
        mov     ax,[cs:si+MS.wantedperiod]
        cmp     ax,[cs:si+MS.period]
        jl      mt_TonePortaSetPer
        mov     [cs:si+MS.period],ax
        mov     [Word cs:si+MS.wantedperiod],0

mt_TonePortaSetPer:
        mov     cx,[cs:si+MS.period]
        mov     al,[cs:si+MS.glissfunk]
        and     al,0Fh
        jz      mt_GlissSkip
        mov     al,[cs:si+MS.finetune]
	mov	bl,61*2
        mul     bl
        push    di
	mov	di,offset mt_PeriodTable
        add     di,ax
        mov     bx,0
mt_GlissLoop:
        cmp     cx,[cs:bx+di]
        jnb     mt_GlissFound
        add     bx,2
	cmp	bx,61*2
        jb      mt_GlissLoop
	mov	bx,59*2
mt_GlissFound:
        mov     cx,[cs:bx+di]
        pop     di
mt_GlissSkip:
        call    mt_PerNop2
        ret
endp    mt_TonePortamento


; Effect 4 -- Vibrato
proc    mt_Vibrato near
        mov     al,[cs:si+MS.cmdlo]
        or      al,al
        jz      mt_Vibrato2
        mov     cl,[cs:si+MS.vibratocmd]
        and     al,0fh
        jz      mt_vibskip
        and     cl,0F0h
        or      cl,al
mt_vibskip:
        mov     al,[cs:si+MS.cmdlo]
        and     al,0F0h
        jz      mt_vibskip2
        and     cl,0Fh
        or      cl,al
mt_vibskip2:
        mov     [cs:si+MS.vibratocmd],cl
mt_Vibrato2:
        mov     al,[cs:si+MS.vibratopos]
        mov     bx,offset mt_VibratoTable
        shr     ax,2
        and     ax,001Fh
        xor     cx,cx
        mov     cl,[cs:si+MS.wavecontrol]
        and     cl,03h
        jz      mt_vib_sine
        shl     al,3
        cmp     cl,1
        jz      mt_vib_rampdown
        mov     cl,255
        jmp     mt_vib_set
mt_vib_rampdown:
        cmp     [Byte cs:si+MS.vibratopos],0
        jnl     mt_vib_rampdown2
        mov     cl,255
        sub     cl,al
        jmp     mt_vib_set
mt_vib_rampdown2:
        mov     cl,al
        jmp     mt_vib_set
mt_vib_sine:
        add     bl,al
        mov     cl,[cs:bx]
mt_vib_set:
        mov     al,[cs:si+MS.vibratocmd]
        and     al,15
        mul     cl
        shr     ax,7
        mov     cx,ax
        mov     ax,[cs:si+MS.period]
        cmp     [Byte cs:si+MS.vibratopos],0
        jl      mt_VibratoNeg           ; BMI
        add     ax,cx
        jmp     mt_Vibrato3
mt_VibratoNeg:
        sub     ax,cx
mt_Vibrato3:
        mov     cx,ax
        call    mt_PerNop2
        mov     al,[cs:si+MS.vibratocmd]
        shr     ax,2
        and     ax,3Ch
        add     [cs:si+MS.vibratopos],al
        ret
endp    mt_Vibrato


; Effect 5 -- Tone and Volume Slide
proc    mt_TonePlusVolSlide near
        call    mt_TonePortNoChange
        jmp     mt_VolumeSlide
endp    mt_TonePlusVolSlide

; Effect 6 -- Vibrato and Volume Slide
proc    mt_VibratoPlusVolSlide near
        call    mt_Vibrato2
        jmp     mt_VolumeSlide
endp    mt_VibratoPlusVolSlide


; Effect 7 -- Tremolo
proc    mt_Tremolo near
        mov     al,[Byte cs:si+MS.cmdlo]
        or      al,al
        jz      mt_Tremolo2
        mov     cl,[cs:si+MS.tremolocmd]
        and     al,0Fh
        jz      mt_treskip
        and     cl,0F0h
        or      cl,al
mt_treskip:
        mov     al,[Byte cs:si+MS.cmdlo]
        and     al,0F0h
        jz      mt_treskip2
        and     cl,0Fh
        or      cl,al
mt_treskip2:
        mov     [cs:si+MS.tremolocmd],cl
mt_Tremolo2:
        mov     al,[cs:si+MS.tremolopos]
        shr     al,2
        and     ax,001Fh
        xor     cx,cx
        mov     cl,[cs:si+MS.wavecontrol]
        shr     cl,4
        and     cl,03h
        jz      mt_tre_sine
        shl     al,3
        cmp     cl,1
        jz      mt_tre_rampdown
        mov     cl,255
        jmp     mt_tre_set
mt_tre_rampdown:
        cmp     [Byte cs:si+MS.vibratopos],0
        jnb     mt_tre_rampdown2
        mov     cl,255
        sub     cl,al
        jmp     mt_tre_set
mt_tre_rampdown2:
        mov     cl,al
        jmp     mt_tre_set
mt_tre_sine:
        xor     bx,bx
        mov     bl,al
        mov     cl,[cs:bx+offset mt_VibratoTable]
mt_tre_set:
        mov     al,[cs:si+MS.tremolocmd]
        and     al,0Fh
        mul     cl
        mov     cx,ax
        shr     cx,6
        mov     al,[cs:si+MS.volume]
        cmp     [Byte cs:si+MS.tremolopos],0
        jb      mt_TremoloNeg           ; BMI  jns
        add     al,cl
        jmp     mt_Tremolo3
mt_TremoloNeg:
        sub     al,cl
mt_Tremolo3:
        jnb     mt_TremoloSkip
        xor     ax,ax
mt_TremoloSkip:
        cmp     al,40h
        jb      mt_TremoloOK            ; BLS
        mov     al,40h
mt_TremoloOK:
        call    volequ
        mov     al,[cs:si+MS.tremolocmd]
        shr     al,2
        and     al,3Ch
        add     [cs:si+MS.tremolopos],al
        ret
endp    mt_Tremolo

; Effect 9 -- Sample Offset
proc    mt_SampleOffset near
        mov     al,[Byte cs:si+MS.cmdlo]
        or      al,al
        jz      mt_sononew
        mov     [cs:si+MS.sampleoffset],al
mt_sononew:
        mov     al,[cs:si+MS.sampleoffset]         ; Variance in Protracker code.
        shl     ax,8
;        cmp     ax,[cs:si+MS.reallength]
;        jge     mt_sofskip
        mov     cx,ax
        or      cx,cx
        jnz     mt_dontset
        dec     cx
mt_dontset:
        mov     ax,[Word cs:si+MS.start]
        mov     dx,[Word cs:si+(offset (MS).start)+2]
        add     ax,cx
        adc     dx,0
        mov     [Word cs:si+MS.start],ax
        mov     [Word cs:si+(offset (MS).start)+2],dx
        ret
mt_sofskip:
        ret
endp    mt_SampleOffset


; Effect A -- Volume Slide
proc    mt_VolumeSlide near
        mov     al,[cs:si+MS.cmdlo]
        shr     al,4
        or      al,al
        jz      mt_VolSlideDown
mt_VolSlideUp:
        add     [Byte cs:si+MS.volume],al
        cmp     [Byte cs:si+MS.volume],40h
        jb      mt_vsuskip
        mov     [Byte cs:si+MS.volume],40h
mt_vsuskip:
        mov     al,[Byte cs:si+MS.volume]
        call    volequ
        ret

mt_VolSlideDown:
        mov     al,[cs:si+MS.cmdlo]
        and     al,0Fh
mt_VolSlideDown2:
        sub     [Byte cs:si+MS.volume],al
        jnb     mt_vsdskip
        mov     [Byte cs:si+MS.volume],0
mt_vsdskip:
        mov     al,[Byte cs:si+MS.volume]
        call    volequ
        ret
endp    mt_VolumeSlide


; Effect B -- Position Jump
proc    mt_PositionJump near
        mov     al,[Byte cs:si+MS.cmdlo]         ; Get where to jump
        dec     al                            ; Update the
        mov     [cs:mt_SongPos],al               ; information.
mt_pj2: mov     [Byte cs:mt_PBreakPos],0
        mov     [Byte cs:mt_PosJumpFlag],1
        ret
endp    mt_PositionJump

; Effect C -- Volume Change
proc    mt_VolumeChange near
        mov     al,[Byte cs:si+MS.cmdlo]   ; Get value for volume
        cmp     al,40h                  ; Is it greater than 40h?
        jb      mt_VolumeOK             ; Nope
        mov     al,40h
mt_VolumeOK:
        mov     [cs:si+MS.volume],al       ; Get it again
        call    volequ
        ret
endp    mt_VolumeChange

; Effect D -- Pattern Break
proc    mt_PatternBreak near
        mov     al,[Byte cs:si+MS.cmdlo]             ; Break to where?
        mov     cl,al
        shr     al,4
        mov     bl,10
        mul     bl
        and     cl,0Fh
        add     al,cl
        cmp     al,63
        jg      mt_pj2
        mov     [cs:mt_PBreakPos],al
        mov     [Byte cs:mt_PosJumpFlag],1
        ret
endp    mt_PatternBreak


; Effect F -- Set Speed
;   Doesn't handle Protracker extended speeds.
proc    mt_SetSpeed near
        mov     al,[Byte cs:si+MS.cmdlo]             ; Get value for speed
        or      al,al
        jz      mt_SpeedLeave
        cmp     al,32
        jnb     mt_SpeedExt
mt_SpeedSet:
        mov     [Byte cs:mt_counter],0
        mov     [Byte cs:mt_speed],al
mt_SpeedLeave:
        ret
mt_SpeedExt:
        ret
endp    mt_SetSpeed


proc    mt_CheckMoreEfx near
	mov	bl,[cs:si+MS.cmd]
        and     bl,0Fh
	cmp	bl,09h
	jz	mt_SampleOffset
	cmp	bl,0Bh
	jz	mt_PositionJump
	cmp	bl,0Dh
	jz	mt_PatternBreak
	cmp	bl,0Eh
	jz	mt_E_Commands
	cmp	bl,0Fh
	jz	mt_SetSpeed
	cmp	bl,0Ch
	jz	mt_VolumeChange
	jmp	mt_PerNop
endp    mt_CheckMoreEfx

proc    mt_E_Commands near
        mov     bl,[Byte cs:si+MS.cmdlo]
        and     bl,0F0h
        shr     bl,4
	cmp	bl,0
	jz	mt_FilterOnOff
	cmp	bl,1
	jz	mt_FinePortaUp
	cmp	bl,2
	jz	mt_FinePortaDown
	cmp	bl,3
	jz	mt_SetGlissControl
	cmp	bl,4
	jz	mt_SetVibratoControl
	cmp	bl,5
	jz	mt_SetFineTune
	cmp	bl,6
	jz	mt_JumpLoop
	cmp	bl,7
	jz	mt_SetTremoloControl
	cmp	bl,0Eh
	jz	mt_PatternDelay
	cmp	bl,9
	jz	mt_RetrigNote
	cmp	bl,0Ah
	jz	mt_VolumeFineUp
	cmp	bl,0Bh
	jz	mt_VolumeFineDown
	cmp	bl,0Ch
	jz	mt_NoteCut
	cmp	bl,0Dh
	jz	mt_NoteDelay
        ret
endp    mt_E_Commands

;──────────────────────────────────────────────────────────────────────────
; Effect E
;──────────────────────────────────────────────────────────────────────────
; Effect 0 -- FilterOnOff
proc    mt_FilterOnOff near
        mov     al,[Byte cs:si+MS.cmdlo]
        and     al,1
        sal     al,1
        ; Amiga
        ; Stuff
        ret
endp    mt_FilterOnOff

; Effect 1 -- Fine Porta Up
proc    mt_FinePortaUp near
        cmp     [Byte cs:mt_counter],0
        jnz     mt_Return
        mov     [Byte cs:mt_LowMask],0Fh
        jmp     mt_PortaUp
endp    mt_FinePortaUp

; Effect 2 -- Fine Porta Down
proc    mt_FinePortaDown near
        cmp     [Byte cs:mt_counter],0
        jnz     mt_Return
        mov     [Byte cs:mt_LowMask],0Fh
        jmp     mt_PortaDown
endp    mt_FinePortaDown

; Effect 3 -- Set Gliss Control
proc    mt_SetGlissControl near
        mov     al,[Byte cs:si+MS.cmdlo]
        and     al,0Fh
        and     [Byte cs:si+MS.glissfunk],0F0h
        or      [cs:si+MS.glissfunk],al
        ret
endp    mt_SetGlissControl

; Effect 4 -- Set Vibrato Control
proc    mt_SetVibratoControl near
        mov     al,[cs:si+MS.cmdlo]
        and     al,0Fh
        and     [Byte cs:si+MS.wavecontrol],0F0h
        or      [cs:si+MS.wavecontrol],al
        ret
endp    mt_SetVibratoControl

; Effect 5 -- Set Fine Tune
proc    mt_SetFineTune near
        mov     al,[cs:si+MS.cmdlo]
        and     al,0Fh
        mov     [cs:si+MS.finetune],al
        ret
endp    mt_SetFineTune

; Effect 6 -- Jump Loop
proc    mt_JumpLoop near
        cmp     [Byte cs:mt_counter],0
        jnz     mt_Return
        mov     al,[cs:si+MS.cmdlo]
        and     al,0Fh
        jz      mt_SetLoop
        cmp     [Byte cs:si+MS.loopcount],0
        jz      mt_jumpcnt
        dec     [Byte cs:si+MS.loopcount]
        jz      mt_Return
mt_jmploop:
        mov     al,[cs:si+MS.pattpos]
        mov     [cs:mt_PBreakPos],al
        mov     [Byte cs:mt_PBreakFlag],1
        ret

mt_jumpcnt:
        mov     [cs:si+MS.loopcount],al
        jmp     mt_jmploop

mt_SetLoop:
;	 xor	 dx,dx
	mov	ax,[cs:mt_PatternPos]
	mov	bx,48
;	 call	 DivIt
	div	bl
	and	ax,63
        mov     [cs:si+MS.pattpos],al
        ret
endp    mt_JumpLoop

; Effect 7 -- Set Tremolo Control
proc    mt_SetTremoloControl near
        mov     al,[Byte cs:si+MS.cmdlo]
        and     al,0Fh
        shl     al,4
        and     [Byte cs:si+MS.wavecontrol],0Fh
        or      [cs:si+MS.wavecontrol],al
        ret
endp    mt_SetTremoloControl

; Effect 9 -- Retrig Note
proc    mt_RetrigNote near
        mov     bl,[Byte cs:si+MS.cmdlo]
        and     bl,0Fh
        jz      mt_rtnend
        xor     ax,ax
        mov     al,[cs:mt_counter]
        or      al,al
        jnz     mt_rtnskp
	mov	al,[cs:si+MS.note]
	or	al,al
	jnz	mt_rtnend
;        mov     [Byte cs:mt_counter],0
        xor     ax,ax
        mov     al,[cs:mt_counter]
mt_rtnskp:
        div     bl
        xchg    ah,al
        or      al,al
        jnz     mt_rtnend
mt_DoRetrig:
        mov     [Byte cs:EfxFlag],1
        call    mt_DoIns
        mov     [Byte cs:EfxFlag],0
mt_rtnend:
        ret
endp    mt_RetrigNote

; Effect A -- Volume Fine Up
proc    mt_VolumeFineUp near
        cmp     [Byte cs:mt_counter],0
        jnz     mt_Return
        mov     al,[cs:si+MS.cmdlo]
        and     al,0Fh
        jmp     mt_VolSlideUp
endp    mt_VolumeFineUp

; Effect B -- Volume Fine Down
proc    mt_VolumeFineDown near
        cmp     [Byte cs:mt_counter],0
        jnz     mt_Return
        mov     al,[cs:si+MS.cmdlo]
        and     al,0Fh
        jmp     mt_VolSlideDown2
endp    mt_VolumeFineDown

; Effect C -- Note Cut
proc    mt_NoteCut near
        mov     al,[Byte cs:si+MS.cmdlo]
        and     al,0Fh
        cmp     al,[cs:mt_counter]
        jnz     mt_Return
        mov     [Byte cs:si+MS.volume],0
        mov     al,[Byte cs:si+MS.volume]
        call    volequ
        ret
endp    mt_NoteCut

; Effect D -- Note Delay
proc    mt_NoteDelay near
        mov     al,[Byte cs:si+MS.cmdlo]
        and     al,0Fh
        cmp     al,[cs:mt_counter]
        jnz     mt_Return
	mov	al,[cs:si]
	and	al,00111111b
        jz      mt_Return
        jmp     mt_DoRetrig
endp    mt_NoteDelay

; Effect E -- Pattern Delay
proc    mt_PatternDelay near
        cmp     [Byte cs:mt_counter],0
        jnz     mt_Return
        mov     al,[Byte cs:si+MS.cmdlo]
        and     al,0Fh
        cmp     [Byte cs:mt_PattDelayTime2],0
        jnz     mt_Return
        inc     al
        mov     [cs:mt_PattDelayTime],al
        ret
endp    mt_PatternDelay

proc    doramp near
        push    bx si
	mov	ah,0
	cmp	[Byte cs:si+MS.MasterVolume],0
        jz      @@ZeroVol
	mul	[Byte cs:si+MS.MasterVolume]
	inc	ah
@@ZeroVol:
        mov     bl,ah
	xor	bh,bh
        shl     bx,1
        mov     ax,[cs:bx+mt_VolTable]
        jmp     slideramp2
slideramp:
        push    bx si
slideramp2:
        mov     si,ax
        mov     dx,[cs:u_Command]
        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,[cs:u_Command]
        mov     al,7
        out     dx,al
        add     dx,2
        pop     ax
        out     dx,al
        mov     dx,[cs:u_Command]
        mov     al,8
        out     dx,al
        add     dx,2
        mov     ax,si
        out     dx,al
        mov     dx,[cs:u_Command]
        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,[cs:u_Command]
        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
endp    doramp

proc    volequ near
        push    bx si
	mov	[cs:si+MS.DecVolume],al
	mov	ah,0
	cmp	[Byte cs:si+MS.MasterVolume],0
	jz	@@ZeroVol
	mul	[Byte cs:si+MS.MasterVolume]
	inc	ah
@@ZeroVol:
	mov	bl,ah
	xor	bh,bh
        shl     bx,1
        mov     ax,[cs:bx+mt_VolTable]
@@Skip: mov     [cs:si+MS.sc_Vol],ax
        pop     si bx
        ret
endp    volequ

proc		DivIt	near
                or      bx,bx
                stc
                jz      Div1
                mov     cx,ax
                mov     ax,dx
                xor     dx,dx
                div     bx
                xchg    cx,ax
                div     bx
                xchg    dx,cx
                clc
Div1:           ret
endp            DivIt

proc            mt_PerNop near
                mov     cx,[cs:si+MS.period]    ; get period Value
proc            mt_PerNop2 near
                mov     ax,cx
                and     ax,0FFFh
                or      ax,ax
                jz      @@OutIt
                push    dx bx ax
                mov     bx,19
                mov     dx,36h
                mov     ax,9E9Ah
		call	DivIt
                pop     bx
		call	DivIt
                pop     bx dx
@@OutIt:        mov     [cs:si+MS.sc_Note],ax
                ret
endp            mt_PerNop2
endp            mt_PerNop

SizeSoundSeg    =       $-StartSoundSeg

ends    GUSSound

[ RETURN TO DIRECTORY ]