

        .386P

Segment                 DriverHeader PARA Public 'Code' Use16
                        Assume CS:Driver, DS:Nothing

;***** Driver Header *******

include drhead.inc
include mmx.inc

EndS

Segment                 Driver PARA Public 'Code' Use16
                        Assume CS:Driver, DS:Nothing

ORG 0
StartDriver:

include vtable.inc

;********  Required ProcedureTable *************

include reqproc.inc

;**********************************

TRACEENABLED            =       0
CREATENEWLOGFILE        =       1

include debug.inc

STEREOENABLED           EQU     1
DMABUFFERLENGTH         EQU     8192
MIXRESOLUTION           EQU     32      ; 32 bit mixing for the SB16
OUTPUTFILTERENABLED     EQU 1
FOURIERBUFFERLENGTH     EQU     2048    ; 2048 samples

FPSave          DB      128 Dup (0)

SB16Msg         DB      "Sound Blaster 16 MMX", 13
                DB      "Port ", 0FDh, "Xh, IRQ ", 0FDh, "D, DMA ", 0FDh, "D", 0

SB16NoMemoryMsg DB      "Sound Blaster 16 MMX", 13
                DB      "Error: Insufficient memory", 0

ReinitMsg       DB      "Sound Blaster 16 reinitialised", 0

DefaultDriverName DB    "ITSB16.MMX", 0
DriverName      DD      0

DSPVersion      DW      0
DSPIRQValue     DB      0
DSPDMAValue     DB      0
Forced          DB      0
Stereo          DB      0
MixVolume       DW      0

BytesToMix      DW      1000
SBMixConst      DB      0

MixSegment      DW      0
FourierSegment  DW      0

MixTransferOffset       DW      0
MixTransferRemaining    DW      0

CONFIGURATIONOFFSET     EQU     $+128
CONFIGSIZE              EQU     20
MixMode                 DW      0
MixModeOffset           DW      0
DMASize                 DW      2048
VolumeTable             DB      6 Dup (0)
                        DB      0, 16, 96, 127
                        DB      0, 0, 0, 0

IMR             DW      0
OldIRQHandler   DD      0

MIDIPort        DW      0
MIDIBuffer      DB      256 Dup (0)
MIDIBufferHead  DB      0
MIDIBufferTail  DB      0

IRQData                 Label   Word
        DW      20h,  1111111111111110b ; IRQ 0
        DW      24h,  1111111111111101b ; IRQ 1
        DW      28h,  1111110111111011b ; IRQ 2
        DW      2Ch,  1111111111110111b ; IRQ 3
        DW      30h,  1111111111101111b ; IRQ 4
        DW      34h,  1111111111011111b ; IRQ 5
        DW      38h,  1111111110111111b ; IRQ 6
        DW      3Ch,  1111111101111111b ; IRQ 7
        DW      1C0h, 1111111011111011b ; IRQ 8
        DW      1C4h, 1111110111111011b ; IRQ 9
        DW      1C8h, 1111101111111011b ; IRQ 10
        DW      1CCh, 1111011111111011b ; IRQ 11
        DW      1D0h, 1110111111111011b ; IRQ 12
        DW      1D4h, 1101111111111011b ; IRQ 13
        DW      1D8h, 1011111111111011b ; IRQ 14
        DW      1DCh, 0111111111111011b ; IRQ 15


;**********************************

SB16ScreenList          Label
                        DW      8
                        DW      Near Ptr IdleFunctionList
                        DW      Near Ptr GlobalKeyLink

                        DW      Near Ptr FullScreenBox  ; 0
                        DW      Near Ptr ScreenHeader
                        DW      Near Ptr FillHeader
                        DW      Near Ptr SB16HeaderLine

                        DW      Near Ptr VolumeText
                        DW      Near Ptr VolumeBox1
                        DW      Near Ptr VolumeBox2

                        DW      Near Ptr DriverText

                        DW      Near Ptr MasterVolumeLeft       ; 8
                        DW      Near Ptr MasterVolumeRight      ; 9
                        DW      Near Ptr TrebleVolumeLeft       ; 10
                        DW      Near Ptr TrebleVolumeRight      ; 11
                        DW      Near Ptr BassVolumeLeft         ; 12
                        DW      Near Ptr BassVolumeRight        ; 13

                        DW      Near Ptr MixModeText
                        DW      Near Ptr MixModeButton1         ; 15
                        DW      Near Ptr MixModeButton2         ; 16
                        DW      Near Ptr MixModeButton3         ; 17
                        DW      Near Ptr MixModeButton4         ; 18

                        DW      Near Ptr FrequencyText

                        DW      Near Ptr FilterText             ; 20
                        DW      Near Ptr FilterBox1
                        DW      Near Ptr FilterBox2

                        DW      Near Ptr FilterFrequency1       ; 23
                        DW      Near Ptr FilterFrequency2
                        DW      Near Ptr FilterFrequency3
                        DW      Near Ptr FilterFrequency4

                        DW      Near Ptr FilterVolume1          ; 27
                        DW      Near Ptr FilterVolume2
                        DW      Near Ptr FilterVolume3
                        DW      Near Ptr FilterVolume4

                        DW      0


SB16HeaderLine          DW      10
                        DB      "Sound Blaster 16 Driver", 0

DriverText              DW      1
                        DB      31, 48
                        DB      21h
                        DB      "Sound Blaster 16 Driver 1.4 for Impulse Tracker", 0

VolumeText              DW      1
                        DB      2, 13
                        DB      20h
                        DB      "Master Volume Left", 13
                        DB      "Master Volume Right", 13
                        DB      13
                        DB      13
                        DB      "Treble Left", 13
                        DB      "Treble Right", 13
                        DB      "Bass Left", 13
                        DB      "Bass Right", 13
                        DB      0

VolumeBox1              DW      0
                        DB      21, 12, 27, 15
                        DB      25

VolumeBox2              DW      0
                        DB      14, 16, 18, 21
                        DB      25

GlobalKeyLink           DB      7
GlobalKeyLink2          DD      0

IdleFunctionList        DD      0
                        DD      0

FillHeader              DW      8
FillHeader2             DD      0

FullScreenBox           DW      0
                        DB      0, 0, 79, 49
                        DB      4

ScreenHeader            DW      8
ScreenHeader2           DD      0

MasterVolumeLeft        DW      9
                        DB      22, 13
                        DW      0, 31
                        DW      9, 0
                        DW      0FFFFh, 9, 0FFFFh, 0FFFFh
                        DW      0FFFFh, 0FFFFh

MasterVolumeRight       DW      9
                        DB      22, 14
                        DW      0, 31
                        DW      9, 1
                        DW      8, 10, 0FFFFh, 0FFFFh
                        DW      0FFFFh, 0FFFFh

TrebleVolumeLeft        DW      9
                        DB      15, 17
                        DW      0, 15
                        DW      9, 2
                        DW      9, 11, 0FFFFh, 0FFFFh
                        DW      0FFFFh, 0FFFFh

TrebleVolumeRight       DW      9
                        DB      15, 18
                        DW      0, 15
                        DW      9, 3
                        DW      10, 12, 0FFFFh, 0FFFFh
                        DW      0FFFFh, 0FFFFh

BassVolumeLeft          DW      9
                        DB      15, 19
                        DW      0, 15
                        DW      9, 4
                        DW      11, 13, 0FFFFh, 0FFFFh
                        DW      0FFFFh, 0FFFFh

BassVolumeRight         DW      9
                        DB      15, 20
                        DW      0, 15
                        DW      9, 5
                        DW      12, 15, 0FFFFh, 0FFFFh
                        DW      0FFFFh, 0FFFFh

MixModeText             DW      1
                        DB      2, 23
                        DB      20h
                        DB      "Mixing Mode", 0

FrequencyText           DW      1
                        DB      2, 48
                        DB      20h
                        DB      "Playback Frequency: ", 0FDh, "DHz", 0
MixSpeed                DW      45454
                        DW      0

MixModeButton1          DW      2
                        DW      13, 16, 0FFFFh, 0FFFFh
                        DW      0
                        DW      0, 0
                        DW      6
                        DW      Offset GetMixMode
DriverSegment1          DW      0
                        DW      0
                        DW      Offset SetMixMode
DriverSegment2          DW      0
                        DB      3, 25, 32, 27, 8
                        DB      0
                        DB      "  MMX, Non-Interpolated", 0

MixModeButton2          DW      2
                        DW      15, 17, 0FFFFh, 0FFFFh
                        DW      0
                        DW      0, 0
                        DW      6
                        DW      Offset GetMixMode
DriverSegment3          DW      0
                        DW      1
                        DW      Offset SetMixMode
DriverSegment4          DW      0
                        DB      3, 28, 32, 30, 8
                        DB      0
                        DB      "  MMX, Interpolated", 0

MixModeButton3          DW      2
                        DW      16, 18, 0FFFFh, 0FFFFh
                        DW      0
                        DW      0, 0
                        DW      6
                        DW      Offset GetMixMode
DriverSegment5          DW      0
                        DW      2
                        DW      Offset SetMixMode
DriverSegment6          DW      0
                        DB      3, 31, 32, 33, 8
                        DB      0
                        DB      "  MMX, Volume Ramped", 0

MixModeButton4          DW      2
                        DW      17, 23, 0FFFFh, 0FFFFh
                        DW      0
                        DW      0, 0
                        DW      6
                        DW      Offset GetMixMode
DriverSegment7          DW      0
                        DW      3
                        DW      Offset SetMixMode
DriverSegment8          DW      0
                        DB      3, 34, 32, 36, 8
                        DB      0
                        DB      "  MMX, Filtered", 0

FilterText              DW      1
                        DB      2, 39
                        DB      20h
                        DB      "Output Equalizer", 13
                        DB      13
                        DB      "     Low Frequency Band", 13
                        DB      " Med Low Frequency Band", 13
                        DB      "Med High Frequency Band", 13
                        DB      "    High Frequency Band", 0

FilterBox1              DW      0
                        DB      25, 40, 47, 45
                        DB      25

FilterBox2              DW      0
                        DB      52, 40, 74, 45
                        DB      25

FilterFrequency1        DW      14
                        DB      26, 41
                        DW      0, 127
                        DW      9, 6
                        DW      18, 24, 27, 27
                        DW      0FFFFh, 0FFFFh
                        DW      20

FilterFrequency2        DW      14
                        DB      26, 42
                        DW      0, 127
                        DW      9, 7
                        DW      23, 25, 28, 28
                        DW      0FFFFh, 0FFFFh
                        DW      20

FilterFrequency3        DW      14
                        DB      26, 43
                        DW      0, 127
                        DW      9, 8
                        DW      24, 26, 29, 29
                        DW      0FFFFh, 0FFFFh
                        DW      20

FilterFrequency4        DW      14
                        DB      26, 44
                        DW      0, 127
                        DW      9, 9
                        DW      25, 0FFFFh, 30, 30
                        DW      0FFFFh, 0FFFFh
                        DW      20

FilterVolume1           DW      14
                        DB      53, 41
                        DW      0, 255
                        DW      9, 10
                        DW      18, 28, 23, 23
                        DW      0FFFFh, 0FFFFh
                        DW      20

FilterVolume2           DW      14
                        DB      53, 42
                        DW      0, 255
                        DW      9, 11
                        DW      27, 29, 24, 24
                        DW      0FFFFh, 0FFFFh
                        DW      20

FilterVolume3           DW      14
                        DB      53, 43
                        DW      0, 255
                        DW      9, 12
                        DW      28, 30, 25, 25
                        DW      0FFFFh, 0FFFFh
                        DW      20

FilterVolume4           DW      14
                        DB      53, 44
                        DW      0, 255
                        DW      9, 13
                        DW      29, 0FFFFh, 26, 26
                        DW      0FFFFh, 0FFFFh
                        DW      20


; ÄÄ MixingRoutines ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

MixBufferPos            DW      0

include dma.inc
include mix.inc

include m32bitm.mix
include m32bitmi.mix
include m32bitmv.mix
include m32bitmf.mix

ALIGN 2

MixFunctionTables       Label

include m32bitm.inc
include m32bitmi.inc
include m32bitmv.inc
include m32bitmf.inc
include mnomix.inc

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

RelocationTable         Label   Word
        DW      Offset DriverSegment1, Offset DriverSegment2
        DW      Offset DriverSegment3, Offset DriverSegment4
        DW      Offset DriverSegment5, Offset DriverSegment6
        DW      Offset DriverSegment7, Offset DriverSegment8
        DW      0

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SBOut           ; AL = data
                                ; DX = 2xCh

                Push    AX

SBOut1:
                In      AL, DX
                Test    AL, AL
                JS      SBOut1

                Pop     AX
                Out     DX, AL

                Ret

EndP            SBOut

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SBIn            ; DX = 2xEh, returns AL

SBIn1:
                In      AL, DX
                Test    AL, AL
                JNS     SBIn1

                Add     DL, 0Ah-0Eh     ; DX = 2xAh -> Data read port
                In      AL, DX
                Add     DL, 0Eh-0Ah

                Ret

EndP            SBIn

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            DetectMMX

                Trace   "Detecting MMX - CPUID Check"

                PushFD
                Pop     EAX
                Mov     EBX, EAX
                Xor     EAX, 00200000h
                Push    EAX
                PopFD
                PushFD
                Pop     EAX
                Cmp     EAX, EBX
                JZ      DetectMMXFail

                Trace   "CPUID - Check OK"

                Mov     EAX, 1
                DB      0Fh, 0A2h       ; CPUID
                Test    EDX, 800000h
                JZ      DetectMMXFail

                Trace   "MMX Detected"

                ClC
                Ret

DetectMMXFail:
                Trace   "MMX Not Detected"

                StC
                Ret

EndP            DetectMMX

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            DetectUART              ; Given DX = Port

; From SB-DevKit

                ClI

                Inc     DX
                Xor     CX, CX

DetectUART1:
                In      AL, DX
                Test    AL, 40h         ; Ready for output
                LoopNZ  DetectUART1
                JNZ     DetectUARTError

                Mov     AL, 0FFh        ; Reset!
                Out     DX, AL

                Xor     CX, CX

DetectUART2:
                In      AL, DX
                Test    AL, 80h
                JNZ     DetectUART3

                Dec     DX
                In      AL, DX
                Inc     DX
                Cmp     AL, 0FEh
                JE      DetectUART4

DetectUART3:
                Loop    DetectUART2

DetectUARTError:
                StI
                StC
                Ret

DetectUART4:                    ; Now to shove it into 'intelligent' mode.
                Xor     CX, CX

DetectUART5:
                In      AL, DX
                Test    AL, 40h
                LoopNZ  DetectUART5
                JNZ     DetectUARTError

                Mov     AL, 3Fh         ; Intelligent mode!
                Out     DX, AL

DetectUART6:
                Xor     CX, CX

DetectUART7:
                In      AL, DX
                Test    AL, 80h
                JNZ     DetectUART8

                Dec     DX
                In      AL, DX
                Inc     DX
                Cmp     AL, 0FEh
                JE      DetectUART9

DetectUART8:
                Loop    DetectUART7

                Jmp     DetectUARTError

DetectUART9:
                StI
                ClC
                Ret

EndP            DetectUART

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            ReinitUART

                Mov     DX, MIDIPort
                Test    DX, DX
                JZ      ReinitUART1

                Call    DetectUART

ReinitUART1:
                Ret

EndP            ReinitUART

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            ResetUART

                Mov     DX, MIDIPort
                Test    DX, DX
                JZ      ResetUART1

                Inc     DX

                Mov     AL, 0FFh
                Out     DX, AL

ResetUART1:
                Ret

EndP            ResetUART

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            GetMixMode Far

                Push    CS
                Pop     ES
                Mov     DI, Offset MixMode

                Ret

EndP            GetMixMode

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SetMixMode Far

                Mov     AX, [SI+22]

                ClI

                Mov     CS:MixMode, AX

                Mov     BX, 60
                Mul     BX
                Mov     CS:MixModeOffset, AX

                StI

                Mov     AX, 1
                Ret

EndP            SetMixMode
                Assume DS:Nothing

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SBGetRegister

                Out     DX, AL
                Inc     DX
                In      AL, DX
                Dec     DX

                Ret

EndP            SBGetRegister

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            GetSBMixConst                   ; Work out value.. and nearest
                                                ; mixspeed value.

                PushA
                Push    DS

                Push    CS
                Pop     DS
                        Assume DS:Driver

                Mov     AX, CmdLineMixSpeed
                Mov     CX, MixSpeed
                Test    AX, AX
                JZ      GetSBMixConst1

                Mov     CX, 45454
                Cmp     AX, CX
                JA      GetSBMixConst1

                Mov     CX, 12000
                Cmp     AX, CX
                JB      GetSBMixConst1

                Mov     CX, AX

GetSBMixConst1:
                Mov     AX, 1000
                Mul     AX
                Div     CX
                Mov     AH, AL
                Neg     AH
                Mov     SBMixConst, AH

                MovZX   BX, AL
                Mov     AX, 1000
                Mul     AX
                Div     BX
                Mov     MixSpeed, AX

                FNInit
                FILd    DWord Ptr [MixSpeed]
                FMul    FreqMultiplier
                FStP    FreqMultiplier

                Mov     BX, 12000
                Xor     DX, DX
                Div     BX
                Mov     FourierBufferStepOffset, AX
                Mov     FourierBufferStepFractional, DX

                Pop     DS
                PopA
                Ret

EndP            GetSBMixConst
                Assume DS:Nothing

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            ResetDSP Far            ; AX = Port

                Push    AX
                Push    CX
                Push    DX

                Mov     DX, AX
                Add     DL, 6
                Mov     AL, 1
                Out     DX, AL

                In      AL, DX
                In      AL, DX
                In      AL, DX
                In      AL, DX

                Xor     AL, AL
                Out     DX, AL

                Add     DL, 8
                Mov     CX, 200

ResetDSP1:
                In      AL, DX
                Test    AL, AL
                JS      ResetDSP2
                Loop    ResetDSP1
                Jmp     ResetDSP3

ResetDSP2:
                Sub     DL, 4
                In      AL, DX
                Cmp     AL, 0AAh
                JE      ResetDSP4
                Add     DL, 4
                Loop    ResetDSP1

ResetDSP3:
                StC

ResetDSP4:
                Pop     DX
                Pop     CX
                Pop     AX
                Ret

EndP            ResetDSP

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            ResetDSPIRQ

                Mov     DX, CS:BasePort
                Add     DL, 4
                Mov     AH, CS:DSPIRQValue
                Mov     AL, 80h
                Out     DX, AX

                Ret

EndP            ResetDSPIRQ

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            ResetDSPDMA

                Mov     DX, CS:BasePort
                Add     DL, 4
                Mov     AH, CS:DSPDMAValue
                Mov     AL, 81h
                Out     DX, AX

                Ret

EndP            ResetDSPDMA

; ÄÄ DetectCard ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Returns carry set if error, else carry clear. Has to setup internal vars
; (eg. appropriate IRQ/DMA whatever).
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            DetectCard Far

                Push    CS
                Pop     DS
                        Assume DS:Driver

                Mov     Forced, AL

                Cmp     BX, 217h
                JAE     DetectCardUseDriver

                Mov     CX, DS
                ShL     ECX, 16
                Mov     CX, Offset DefaultDriverName

DetectCardUseDriver:
                Mov     DriverName, ECX

                Call    DetectMMX
                JC      DetectCardFailure

                Mov     AX, BasePort
                Cmp     AX, 0FFFFh
                JE      DetectCard1

                Cmp     AX, 210h
                JB      DetectCard9
                Cmp     AX, 280h
                JA      DetectCard9

                Call    ResetDSP
                JNC     DetectCard2

                Ret

DetectCard1:
                Mov     AX, 210h

DetectCard2:
                Call    ResetDSP
                JNC     DetectCard3
                Add     AL, 10h
                Cmp     AL, 80h
                JBE     DetectCard2

DetectCard9:
                StC
                Ret

DetectCard3:                            ; OK... DSP found.
                                        ; Get DSP version
                Mov     BasePort, AX

                Mov     DX, AX
                Add     DL, 0Ch         ; 2xCh -> Data ready to send...

DetectCardOuputLoop1:
                In      AL, DX
                Test    AL, AL
                JS      DetectCardOuputLoop1

                Mov     AL, 0E1h        ; Get DSP version command
                Out     DX, AL

                Add     DL, 0Eh-0Ch     ; DX = 2xEh -> Data available status

                Call    SBIn
                Mov     AH, AL          ; AH = Major version number
                Call    SBIn            ; AL = Minor version number

                Cmp     AH, 4           ; SB DSP = 4.00+
                JAE     DetectCard5

DetectCard4:
                StC
                Ret

DetectCard5:
                Mov     DSPVersion, AX

                Add     DL, 04h-0Eh     ; 2x4h = Mixer index port
                Mov     AL, 80h         ; IRQ select
                Out     DX, AL
                Inc     DL              ; 2x5h = Mixer data port

                In      AL, DX

                Dec     DL

                Mov     DSPIRQValue, AL
                                        ; OK.. now get IRQ, or set IRQ
                Mov     BX, IRQ
                Cmp     BX, 0FFFFh
                JE      DetectCardIRQ1
                Cmp     Forced, 0
                JE      DetectCardIRQ1

                Mov     AH, 11h
                Cmp     BL, 2
                JE      SetCardIRQ1
                Cmp     BL, 9
                JE      SetCardIRQ1

                Mov     AH, 12h
                Cmp     BL, 5
                JE      SetCardIRQ1

                Mov     AH, 14h
                Cmp     BL, 7
                JE      SetCardIRQ1

                Mov     AH, 18h
                Cmp     BL, 10
                JE      SetCardIRQ1

                StC
                Ret

SetCardIRQ1:
                Mov     AL, 80h
                Out     DX, AL
                Inc     DL
                Mov     AL, AH
                Out     DX, AL
                Dec     DL
                Jmp     DetectCard6

DetectCardIRQ1:
                Mov     BX, 2
                Test    AL, 1
                JNZ     DetectCardIRQ2

                Mov     BL, 5
                Test    AL, 2
                JNZ     DetectCardIRQ2

                Mov     BL, 7
                Test    AL, 4
                JNZ     DetectCardIRQ2

                Mov     BL, 10
                Test    AL, 8
                JNZ     DetectCardIRQ2

                StC
                Ret

DetectCardIRQ2:
                Cmp     IRQ, 0FFFFh
                JE      DetectCardIRQ3

                Cmp     BX, IRQ
                JE      DetectCard6

DetectCardFailure:
                StC
                Ret

DetectCardIRQ3:
                Mov     IRQ, BX

DetectCard6:                    ; Detect DMA
                Mov     AL, 81h ; DMA select
                Out     DX, AL
                Inc     DL
                In      AL, DX  ; AL = DMA
                Dec     DL

                Mov     DSPDMAValue, AL

                Mov     BX, DMA
                Cmp     BX, 0FFFFh
                JE      DetectCardDMA1
                Cmp     Forced, 0
                JE      DetectCardDMA1

                Mov     CL, 1
                Cmp     BX, 1
                JB      SetCardDMA1

                Mov     CL, 2
                JE      SetCardDMA1

                Cmp     BX, 3
                JB      DetectCard7

                Mov     CL, 8
                JE      DetectCard7

                Mov     CL, 20h
                Cmp     BX, 5
                JB      DetectCard7
                JE      SetCardDMA1

                Mov     CL, 80h
                Cmp     BX, 7
                JA      DetectCard7
                JE      SetCardDMA1

                Mov     CL, 40h

SetCardDMA1:
                And     AL, 0Bh
                Test    CL, 0Bh
                JZ      SetCardDMA4

                Xor     AL, AL

SetCardDMA4:
                Or      CL, AL

                Mov     AL, 81h
                Out     DX, AL
                Inc     DL
                Mov     AL, CL
                Out     DX, AL
                Jmp     DetectCard7

DetectCardDMA1:
                Mov     BX, 5
                Test    AL, 20h
                JNZ     DetectCardDMA2

                Inc     BL
                Test    AL, 40h
                JNZ     DetectCardDMA2

                Inc     BL
                Test    AL, 80h
                JNZ     DetectCardDMA2

                Mov     BL, 0
                Test    AL, 1
                JNZ     DetectCardDMA2

                Inc     BL
                Test    AL, 2
                JNZ     DetectCardDMA2

                Add     BL, 2
                Test    AL, 8
                JNZ     DetectCardDMA2

DetectCard8:
                Call    ResetDSPIRQ
                StC
                Ret

DetectCardDMA2:
                Cmp     DMA, 0FFFFh
                JE      DetectCardDMA3

                Cmp     BX, DMA
                JNE     DetectCard8

DetectCardDMA3:
                Mov     DMA, BX

DetectCard7:
                Mov     EAX, 'Jeff'

                ClC
                Ret

EndP            DetectCard
                Assume DS:Nothing

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

include mmxmsam.inc
include fourier.inc

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            AckIRQ
                Assume DS:Driver

                Mov     AL, 20h
                Cmp     CS:IRQ, 7
                JBE     AckIRQ1

                Out     0A0h, AL

AckIRQ1:
                Out     20h, AL
                Ret

EndP            AckIRQ
                Assume DS:Nothing

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            CheckMIDI

                Push    DS

                Push    CS
                Pop     DS
                        Assume DS:Driver

                Xor     BX, BX
                Mov     DX, MIDIPort

                Mov     BL, [MIDIBufferTail]
                Test    DX, DX
                JZ      CheckMIDIEnd

                Inc     DX
                Mov     CX, 0FFFFh

CheckMIDIAgain:
                In      AL, DX

                Test    AL, 80h
                LoopNZ  CheckMIDIAgain

                Dec     DX
                In      AL, DX

                Cmp     AL, 0F0h
                JAE     CheckMIDIEnd

                Inc     BL
                Cmp     BL, MIDIBufferHead
                JE      CheckMIDIEnd

                Mov     [MIDIBuffer+BX], AL
                Mov     [MIDIBufferTail], BL
;                Jmp     CheckMIDIAgain

CheckMIDIEnd:
                Pop     DS
                Ret

EndP            CheckMIDI
                Assume DS:Nothing

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SB16IRQHandler

                PushAD
                Push    DS
                Push    ES

                CLD

SBIRQAgain:
                Mov     AX, CS
                Mov     DS, AX
                        Assume DS:Driver

                Mov     DX, BasePort
                Add     DL, 4           ; Mixer Port
                Mov     AL, 82h
                Out     DX, AL
                Inc     DL              ; DX = BasePort+5
                In      AL, DX

Comment ~
                Test    AL, 1
                JZ      SB8BitDigitalInterruptEnd

SB8BitDigitalInterrupt:
                Push    AX
                Add     DL, 0Eh-5
                In      AL, DX
                Pop     AX

SB8BitDigitalInterruptEnd:

        ~
                Test    AL, 4
                JZ      SBMIDIInterruptEnd

                Push    AX
                Call    CheckMIDI
                Pop     AX

SBMIDIInterruptEnd:
                Test    AL, 2
                JNZ     SBDigitalInterrupt

                Call    AckIRQ
                Jmp     SBIRQEnd

SBDigitalInterrupt:
                FNSave  [FPSave]

                Mov     DX, BasePort
                Add     DL, 0Fh
                In      AL, DX          ; 16-bit IRQ ack.

                Call    AckIRQ

                Mov     AX, MixBufferPos
                Mov     BX, AX
                Mul     DMASize
                Cmp     AX, DMABUFFERLENGTH
                JB      SB16IRQHandler2

                Xor     AX, AX
                Xor     BX, BX

SB16IRQHandler2:
                Inc     BX
                Mov     MixBufferPos, BX


                                        ; OK... time to get next block
                                        ;  Check whether stereo thing is on..
                                        ;
                LES     DI, [ActualDMAPtr]
                Mov     BX, DMASize             ; BX = bytes required
                Add     DI, AX
                ShR     BX, 1
                                                ; BX = samples required
                Call    SaveEMSPageFrame

                Cmp     MixTransferRemaining, 0
                JNE     SB16IRQHandler4
                        Assume DS:Nothing

SB16IRQHandler3:
                Push    BX
                Push    CX
                Push    BP
                Push    ES
                Push    DI

                Call    Update
                Call    MixSamples
                Call    UpdateFourierBuffer

                Pop     DI
                Pop     ES
                Pop     BP
                Pop     CX
                Pop     BX

SB16IRQHandler4:
                Mov     DS, MixSegment
                Mov     SI, MixTransferOffset
                Mov     DX, BX          ;  DX = samples to transfer
                Cmp     DX, MixTransferRemaining
                JBE     SB16IRQHandler5

                Mov     DX, MixTransferRemaining

SB16IRQHandler5:

include mmxtrans.inc

                Sub     MixTransferRemaining, DX        ; } Memory write
                Sub     BX, DX
                JNZ     SB16IRQHandler3

                Mov     MixTransferOffset, SI           ; } Memory write

                Call    RestoreEMSPageFrame

                FNRstor [CS:FPSave]

SBIRQEnd:
                Pop     ES
                Pop     DS
                PopAD
                IRet

EndP            SB16IRQHandler
                Assume DS:Nothing

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SetIRQ

                PushAD
                Push    DS
                Push    ES

                Push    CS
                Pop     DS
                        Assume DS:Driver

                Xor     AX, AX
                Mov     ES, AX

                Mov     DI, IRQ
                ShL     DI, 2
                Add     DI, Offset IRQData
                Mov     BX, [DI]

                Mov     AX, CS
                ShL     EAX, 16
                Mov     AX, Offset SB16IRQHandler

                XChg    [ES:BX], EAX
                Mov     OldIRQHandler, EAX

                Mov     AX, IMR
                And     AX, [DI+2]

                Out     21h, AL
                Mov     AL, AH
                Out     0A1h, AL

                Pop     ES
                Pop     DS
                PopAD

                Ret

EndP            SetIRQ
                Assume DS:Nothing

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            ResetIRQ

                PushAD
                Push    DS
                Push    ES

                Push    CS
                Pop     DS
                        Assume DS:Driver

                Xor     AX, AX
                Mov     ES, AX

                Mov     DI, IRQ
                ShL     DI, 2
                Mov     BX, [IRQData+DI]

                Mov     EAX, OldIRQHandler
                Mov     [ES:BX], EAX

                Pop     ES
                Pop     DS
                PopAD

                Ret

EndP            ResetIRQ
                Assume DS:Nothing

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            StartSB16               ;

                PushA
                Push    DS
                Push    ES

                Push    CS
                Pop     DS
                        Assume DS:Driver

                                ; Setup DMA
                Mov     BX, MixSegment
                Mov     AX, 80
                Mov     DX, DMA
                Mov     DI, DMABUFFERLENGTH
                Call    SetDMA

                LES     DI, ActualDMAPtr
                Xor     AX, AX
                Mov     CX, DMABUFFERLENGTH/2
                Rep     StosW

                Mov     MixBufferPos, 0
                Mov     MixTransferRemaining, 0

                Mov     DX, BasePort
                Add     DL, 0Ch

                Mov     AL, 0D1h        ; turn on speaker
                Call    SBOut

                Mov     AL, 40h         ; time constant
                Call    SBOut
                Mov     AL, SBMixConst
                Call    SBOut

                Mov     AL, 0B6h         ; 16 bit, DAC
                Call    SBOut
                Mov     AL, Stereo
                ShL     AL, 5
                Or      AL, 10h
                Call    SBOut

                Mov     AX, DMASize
                ShR     AX, 1
                Dec     AX

                Call    SBOut           ; DMALength, Lo
                Mov     AL, AH
                Call    SBOut

                Pop     ES
                Pop     DS
                PopA

                Ret

                        Assume DS:Nothing

EndP            StartSB16

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            GetMixerRegisters

                Push    DS

                Push    CS
                Pop     DS
                        Assume   DS:Driver

                Pop     DS

                Ret

EndP            GetMixerRegisters
                Assume DS:Nothing

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;ÄÄ InitSound ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Sets up any memory required for output
; Initiates output
;
; Parameters: AX = Number of Channels
;
; If sucessful, returns:
;   Carry flag clear
;   DS:SI = pointer to text to display
;      AX = parameter 1 in text
;      BX = parameter 2 in text
;      CX = parameter 3 in text
;      DX = parameter 4 in text
;      DI = parameter 5 in text
;
; If unsucessful, returns:
;   Carry flag set
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            InitSound Far

                Push    CS
                Pop     DS
                        Assume DS:Driver

                Mov     ECX, IdleUpdateInfoLine
                Mov     EDX, GlobalKeyList
                Mov     IdleFunctionList, ECX
                Mov     GlobalKeyLink2, EDX

                Mov     ECX, FillHeaderFunction
                Mov     EDX, DrawHeaderFunction
                Mov     FillHeader2, ECX
                Mov     ScreenHeader2, EDX

                Mov     SI, Offset RelocationTable

RelocationFix:
                LodsW
                Test    AX, AX
                JZ      RelocationEnd
                Mov     BX, AX
                Mov     [BX], DS
                Jmp     RelocationFix

RelocationEnd:
                Call    GetEMSPageFrame
                Mov     EMSPageFrame, AX

                In      AL, 0A1h
                Mov     AH, AL
                In      AL, 21h
                Mov     IMR, AX

                Mov     DX, BasePort
                Add     DL, 4

                Mov     AL, 30h
                Call    SBGetRegister
                ShR     AL, 3
                Mov     VolumeTable, AL

                Mov     AL, 31h
                Call    SBGetRegister
                ShR     AL, 3
                Mov     [VolumeTable+1], AL

                Mov     AL, 44h
                Call    SBGetRegister
                ShR     AL, 4
                Mov     [VolumeTable+2], AL

                Mov     AL, 45h
                Call    SBGetRegister
                ShR     AL, 4
                Mov     [VolumeTable+3], AL

                Mov     AL, 46h
                Call    SBGetRegister
                ShR     AL, 4
                Mov     [VolumeTable+4], AL

                Mov     AL, 47h
                Call    SBGetRegister
                ShR     AL, 4
                Mov     [VolumeTable+5], AL

                Call    GetSBMixConst

                ; Parags to allocate = (8/(.4*31*16))*MixSpeed
                ; = .04032258*MixSpeed = (65536*.04032258*MixSpeed) / 65536

                Mov     AX, 2643
                Mul     MixSpeed
                Add     AX, 0FFFFh
                AdC     DX, 5+(DMABUFFERLENGTH*2)/16+(FOURIERBUFFERLENGTH*2)/16
                Mov     BX, DX

                        ; Allocate MixSegment first
                Mov     AH, 48h

                Int     21h
                JNC     InitSound1

InitSoundNoMemory:
                Mov     SI, Offset SB16NoMemoryMsg
                Ret

InitSound1:
                Mov     MixSegment, AX
                Add     AX, DX
                Sub     AX, (FOURIERBUFFERLENGTH*2)/16
                Mov     FourierSegment, AX

                Call    SetIRQ
                Call    GetTempo
                Call    SetTempo

                Mov     DX, 330h
                Call    DetectUART
                JC      DetectMIDI1

                Mov     MIDIPort, 330h
                Jmp     DetectMIDIEnd

DetectMIDI1:
                Mov     DX, 300h
                Call    DetectUART
                JC      DetectMIDIEnd

                Mov     MIDIPort, 300h

DetectMIDIEnd:
                Call    CalculateFilterCoefficients

                Mov     SI, Offset SB16Msg

                Mov     AX, BasePort
                Mov     BX, IRQ
                Mov     CX, DMA

                Ret

EndP            InitSound
                Assume DS:Nothing

;ÄÄ ReInitSound ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Reinitialises sound output
; Initiates sound output
;
; Parameters: AX = number of channels.
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            ReInitSound Far

                PushA
                Push    DS
                Push    ES

                Push    CS
                Pop     DS
                        Assume DS:Driver

                Mov     AX, BasePort
                Call    ResetDSP

                Call    ResetUART
                Call    ResetIRQ

                                        ; Delay..
                Mov     DX, BasePort
                Add     DL, 0Ch

                Mov     CX, 1000
ReInitSound1:
                In      AL, DX
                Loop    ReInitSound1

                Call    SetIRQ
                Call    ReinitUART

                Mov     SI, Offset ReInitMsg
                Mov     BX, 40
                Call    SetInfoLine

                Mov     AL, Stereo
                Call    SetStereo

                Pop     ES
                Pop     DS
                PopA

                Ret

EndP            ReInitSound
                Assume DS:Nothing

;ÄÄ UnInitSound ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Stops sound output, releases any memory used by driver
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            UnInitSound Far

                Call    GotoHomeDirectory

                Mov     DS, Word Ptr [CS:DriverName+2]
                Mov     DX, Word Ptr [CS:DriverName]

                Mov     AX, 3D02h       ; Read write access
                Int     21h

                Push    CS
                Pop     DS
                        Assume DS:Driver

                JC      SaveConfig2

                Mov     BX, AX

                Mov     AX, 4200h
                Xor     CX, CX
                Mov     DX, Offset CONFIGURATIONOFFSET
                Int     21h
                JC      SaveConfig1

                Mov     AH, 40h
                Mov     CX, CONFIGSIZE
                Mov     DX, Offset MixMode
                Int     21h

SaveConfig1:
                Mov     AH, 3Eh
                Int     21h

SaveConfig2:
                Mov     DX, CS:BasePort
                Add     DL, 0Ch

                Mov     AL, 0D9h
                Call    SBOut

                Call    ResetUART

                Mov     AX, BasePort
                Call    ResetDSP

                Call    ResetDSPDMA
                Call    ResetDSPIRQ

                Mov     AX, IMR
                Out     21h, AL
                Mov     AL, AH
                Out     0A1h, AL

                Mov     AX, MixSegment
                Test    AX, AX
                JZ      UnInitSound1

                Mov     ES, AX
                Mov     AH, 49h         ; Release MixSegment
                Int     21h

                Call    ResetIRQ

UnInitSound1:
                Ret

EndP            UnInitSound

;ÄÄ Poll ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; This procedure is called as often as possible by IT.EXE
; AX = Playmode (0 for nothing in particular, 1 = pattern, 2 = song)
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            Poll Far

                Push    CS
                Pop     DS
                        Assume DS:Driver

Poll1:
                Call    [UARTBufferEmpty]
                JNC     PollEnd

                Xor     BX, BX

                ClI

                Mov     BL, MIDIBufferHead
                Cmp     BL, MIDIBufferTail
                JZ      PollEnd         ; Nothing in queue

                Inc     BL
                Mov     AL, [MIDIBuffer+BX]
                Mov     MIDIBufferHead, BL

                Call    [UARTSend]
                Jmp     Poll1

PollEnd:
                StI

                Ret

EndP            Poll
                Assume DS:Nothing

;ÄÄ SetTempo ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Parameters: BX = tempo
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SetTempo Far

                Push    AX
                Push    BX
                Push    DX

                Push    BX

                Mov     AX, MixSpeed
                Mov     BX, AX
                Xor     DX, DX

                ShL     AX, 1
                RCL     DX, 1           ; DX:AX = Mixspeed*2

                ShR     BX, 1           ; BX = Mixspeed/2

                Add     AX, BX
                AdC     DX, 0           ; DX:AX = Mixspeed*2.5

                Pop     BX              ; BX = tempo
                Div     BX

                Mov     BytesToMix, AX

                Pop     DX
                Pop     BX
                Pop     AX

                Ret

EndP            SetTempo

;ÄÄ SetMixVolume ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Parameters: AX = MixVolume
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SetMixVolume Far

                Mov     CS:MixVolume, AX
                Mov     DS, Word Ptr [CS:RecalculateAllVolumes+2]
                Jmp     CS:RecalculateAllVolumes

EndP            SetMixVolume

;ÄÄ SetStereo ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Parameters: AL = Stereo on/off, 0 = off.
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SetStereo Far

                Cmp     CS:MixSegment, 0
                JE      SetStereo1

                Mov     CS:Stereo, AL
                Mov     AX, CS:BasePort
                Call    ResetDSP

                Call    StartSB16

SetStereo1:
                Ret

EndP            SetStereo

;ÄÄ LoadSample ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Parameters: AX = sample to load
;             DS:SI points to sample header
;             ES:0 points to first sample
;
; Returns: **Carry set if NO error**
;          **Carry clear if error**
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

include loadsam.inc

;ÄÄ ReleaseSample ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Parameters: AX = sample to release
;             DS:SI points to sample header
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            ReleaseSample Far

                Ret

EndP            ReleaseSample

;ÄÄ ResetMemory ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
;  Frees all on-board memory
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            ResetMemory Far

                Ret

EndP            ResetMemory

;ÄÄ GetStatus ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
;  Frees all on-board memory
;
;  Returns text to show on status line, AX = display parameter
;  Carry set if not to show anything.
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            GetStatus Far

                StC
                Ret

EndP            GetStatus

;ÄÄ SoundCardScreen ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
;  Function to have driver interactive part of program
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SoundCardScreen Far

                Mov     AX, 5
                Mov     SI, 1
                Mov     CX, CS
                Mov     DX, Offset SB16ScreenList

                ClC
                Ret

EndP            SoundCardScreen

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            GetVariable Far         ; Returns AX, given DI

                Xor     AH, AH
                Mov     AL, [CS:VolumeTable+DI]
                Ret

EndP            GetVariable

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

TempVariable    DW      0
Const1          DD      3F800000h

Proc            GetFilterFrequency              ; Given AL= Freq
                Assume DS:Driver

                ShL     AX, 8
                Mov     TempVariable, AX
                FILD    TempVariable

                FMul    FreqParameterMultiplier ; -i/(24*256)
                FLd     ST
                FRndInt
                FSub    ST(1), ST
                FXCh
                F2XM1
                FLd1
                FAdd
                FScale                          ; = 2^(i/24*256)
                FMul    FreqMultiplier          ; = r

                FLd1                            ; 1, c
                FAdd    ST, ST(1)               ; 1+c, c
                FDivR   Const1                  ; 1/(1+c), c
                FSt     DWord Ptr [SI]
                FMul
                FStP    DWord Ptr [SI+4]
                FStP    ST

                Ret

EndP            GetFilterFrequency
                Assume DS:Nothing

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Const1On16      DD      3D000000h       ; actually 1 on 32

Proc            CalculateFilterCoefficients
                Assume DS:Driver

                PushA

                FNInit
                FLdCW   NewControlWord

                Mov     AL, [VolumeTable+6]
                Mov     SI, Offset FilterCoefficients
                ShR     AL, 1
                Call    GetFilterFrequency

                Mov     AL, [VolumeTable+7]     ; FilterFrequency1
                Add     SI, 8
                Call    GetFilterFrequency

                Mov     AL, [VolumeTable+8]     ; FilterFrequency1
                Add     SI, 8
                Call    GetFilterFrequency

                Mov     AL, [VolumeTable+9]     ; FilterFrequency1
                Add     SI, 8
                Call    GetFilterFrequency

; Now volumes
                Mov     SI, Offset VolumeTable+10
                Mov     DI, Offset FilterVolumes
                Xor     AX, AX
                Mov     CX, 4

FilterVolumeLoop1:
                LodSB
                Mov     TempVariable, AX
                FILD    TempVariable
                FMul    Const1On16
                FStP    DWord Ptr [DI]

                Add     DI, 4
                Loop    FilterVolumeLoop1

                PopA
                Ret

EndP            CalculateFilterCoefficients
                Assume DS:Nothing

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SetVariable Far         ; Given AX, DI

                Push    DS
                Push    DX

                Push    CS
                Pop     DS
                        Assume DS:Driver

                Mov     [VolumeTable+DI], AL

                Cmp     DI, 9
                JA      SetVariable3

                Cmp     DI, 6
                JB      SetVariable1

                JE      SetVariable2

                Cmp     AL, [VolumeTable+DI-1]
                JAE     SetVariable2

                Mov     AL, [VolumeTable+DI-1]
                Mov     [VolumeTable+DI], AL

SetVariable2:
                Cmp     DI, 9
                JAE     SetVariable3

                Cmp     AL, [VolumeTable+DI+1]
                JBE     SetVariable3

                Mov     AL, [VolumeTable+DI+1]
                Mov     [VolumeTable+DI], AL

SetVariable3:
                Call    CalculateFilterCoefficients
                Jmp     SetVariableEnd

SetVariable1:
                Mov     DX, BasePort
                Add     DL, 4
                Mov     AL, 30h
                Mov     AH, [VolumeTable]
                ShL     AH, 3
                Out     DX, AX

                Mov     AL, 31h
                Mov     AH, [VolumeTable+1]
                ShL     AH, 3
                Out     DX, AX

                Mov     AL, 44h
                Mov     AH, [VolumeTable+2]
                ShL     AH, 4
                Out     DX, AX

                Mov     AL, 45h
                Mov     AH, [VolumeTable+3]
                ShL     AH, 4
                Out     DX, AX

                Mov     AL, 46h
                Mov     AH, [VolumeTable+4]
                ShL     AH, 4
                Out     DX, AX

                Mov     AL, 47h
                Mov     AH, [VolumeTable+5]
                ShL     AH, 4
                Out     DX, AX

SetVariableEnd:
                Pop     DX
                Pop     DS
                Ret

EndP            SetVariable
                Assume DS:Nothing

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            UARTOut

                Push    CX
                Push    DX
                Mov     DX, CS:MIDIPort
                Test    DX, DX
                JZ      UARTOutEnd

                Push    AX
                Xor     CX, CX
                Inc     DX

UARTOut1:
                In      AL, DX
                Test    AL, 40h
                LoopNZ  UARTOut1

                Pop     AX
                JNZ     UARTOutEnd

                Dec     DX
                Out     DX, AL

UARTOutEnd:
                Pop     DX
                Pop     CX

                Ret

EndP            UARTOut

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

InterpretState  DB      0
InterpretType   DB      0

Proc            SendUARTOut Far ; Local interpreter activated with 0F0h 0F0h.

                Mov     AH, CS:InterpretState
                Cmp     AH, 2
                JB      SendUARTOut1

; In interpreter.
                JE      SendUARTOut3

; Have InterpretType, now get parameter, then return to normal.

                Cmp     AL, 7Fh
                JA      SendUARTOut4

                Push    BX

                Mov     BL, CS:InterpretType    ; Want BX = InterpretType*64+Channel
                                                ;
                ShL     BX, 6
                Add     BL, [DI+20h]
                And     BX, 127
                Mov     [CS:FilterParameters+BX], AL

                Pop     BX

                Test    SI, SI
                JZ      SendUARTOut4

                Or      Byte Ptr [SI], 64

SendUARTOut4:
                Mov     CS:InterpretState, 0
                Ret

SendUARTOut3:
                Cmp     AL, 2
                JAE     SendUARTOut4

                Mov     CS:InterpretType, AL
                Jmp     SendUARTOutStateInc

SendUARTOut1:
                Cmp     AL, 0F0h
                JNE     SendUARTOut2

SendUARTOutStateInc:
                Inc     CS:InterpretState
                Ret

SendUARTOut2:
                Test    AH, AH
                JZ      SendUARTOutEnd

                Push    AX
                Mov     AL, 0F0h
                Call    UARTOut
                Pop     AX
                Mov     CS:InterpretState, 0

SendUARTOutEnd:
                Cmp     AL, 0FCh
                JE      ResetFilters
                Cmp     AL, 0FAh
                JE      ResetFilters

                Cmp     AL, 0FFh
                JNE     SendUARTOutNoClear

ResetFilters:
                PushA
                Push    ES

                Push    CS
                Pop     ES

                Mov     DI, Offset FilterParameters
                Mov     CX, 64
                Mov     AL, 7Fh
                Rep     StosB
                Mov     CX, 64
                Xor     AX, AX
                Rep     StosB

                Pop     ES
                PopA

SendUARTOutNoClear:
                Call    UARTOut
                Ret

EndP            SendUARTOut

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            GetWaveForm Far         ; Given ES:DI = destination
                Assume DS:Nothing       ; want 2048 samples.

                PushA
                Push    DS

                Mov     DS, FourierSegment
                Mov     SI, FourierBufferStart
                Mov     CX, 2048

GetWaveForm1:
                MovsW
                And     SI, (FOURIERBUFFERLENGTH*2)-1
                Loop    GetWaveForm1

                Pop     DS
                PopA

                Ret

EndP            GetWaveForm

;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

EndDriver:

;********  Provided Variable Table *************

MaxNumberOfChannels     DW      0FFFFh  ; Maximum number of channels the
                                        ; driver can handle.

StopAfterPlay           DW      0
DefaultChannels         DW      128
                        DW      7       ; MIDI, hiqual
                        DW      4 Dup (0)


;********  Provided Procedure Table *************

ProvidedTableStart:

        DW      Offset DetectCard

        DW      Offset InitSound        ; Playing related
        DW      Offset ReinitSound
        DW      Offset UninitSound

        DW      Offset Poll

        DW      Offset SetTempo         ; Sound variable related
        DW      Offset SetMixVolume
        DW      Offset SetStereo

        DW      Offset LoadSample       ; Sample related
        DW      Offset ReleaseSample
        DW      Offset ResetMemory
        DW      Offset GetStatus        ; Returns string to show on status line

        DW      Offset SoundCardScreen  ; Sound card 'screen'

        DW      Offset GetVariable      ; For interface
        DW      Offset SetVariable

        DW      Offset SendUARTOut

        DW      Offset GetWaveform

ProvidedTableEnd:
        DW      32-(ProvidedTableEnd-ProvidedTableStart)/2 Dup (0)

EndS

End
