;
; WAV output mix functions....
; Uses Cubic Spline Interpolation
;

ALIGN 4

WAVMixingTable     Label
                                ; 8 bit, 16 bit
                                ; No sound, stereo, surround
                                ; No loop, forwards loop, ping pong loop

        DW      Offset UpdateNoLoop, 0, 0, 0, 0
        DW      Offset UpdateForwardsLoop, 0, 0, 0, 0
        DW      Offset UpdatePingPongLoop, 0, 0, 0, 0

        DW      Offset MixNoLoop, PreM32SMix8Bit, MFS8Bit, MBS8Bit, Mix32Stereo8Bit
        DW      Offset MixForwardsLoop, PreM32SMix8Bit, MFS8Bit, MBS8Bit, Mix32Stereo8Bit
        DW      Offset MixPingPongLoop, PreM32SMix8Bit, MFS8Bit, MBS8Bit, Mix32Stereo8Bit

        DW      Offset MixNoLoop, PreM32UMix8Bit, MFS8Bit, MBS8Bit, Mix32Surround8Bit
        DW      Offset MixForwardsLoop, PreM32UMix8Bit, MFS8Bit, MBS8Bit, Mix32Surround8Bit
        DW      Offset MixPingPongLoop, PreM32UMix8Bit, MFS8Bit, MBS8Bit, Mix32Surround8Bit

        DW      Offset UpdateNoLoop, 0, 0, 0, 0
        DW      Offset UpdateForwardsLoop, 0, 0, 0, 0
        DW      Offset UpdatePingPongLoop, 0, 0, 0, 0

        DW      Offset MixNoLoop, PreM32SMix16Bit, MFS16Bit, MBS16Bit, Mix32Stereo16Bit
        DW      Offset MixForwardsLoop, PreM32SMix16Bit, MFS16Bit, MBS16Bit, Mix32Stereo16Bit
        DW      Offset MixPingPongLoop, PreM32SMix16Bit, MFS16Bit, MBS16Bit, Mix32Stereo16Bit

        DW      Offset MixNoLoop, PreM32UMix16Bit, MFS16Bit, MBS16Bit, Mix32Surround16Bit
        DW      Offset MixForwardsLoop, PreM32UMix16Bit, MFS16Bit, MBS16Bit, Mix32Surround16Bit
        DW      Offset MixPingPongLoop, PreM32UMix16Bit, MFS16Bit, MBS16Bit, Mix32Surround16Bit

LastLeftValue   DD      0
LastRightValue  DD      0

Sample1                 DD      0
Sample2                 DD      0
Sample3                 DD      0
Sample4                 DD      0
SampleValue             DD      0
InterpolationOffset     DD      0
Const3                  DD      3.0
Const1On65536           DD      37800000h
Const256On6             DD      422AAAAAh
Const1On6               DD      3E2AAAAAh
;Const65536              DD      65536.0
Const32768              DD      32768.0
Const1On32768           DD      38000000h
;ConstLimiter            DD      3F000000h
Const22713_0            DD      22713.0

MAXFILTERVALUE          EQU     47000000h

FILTERCLIPPINGTYPENONE          EQU     0
FILTERCLIPPINGTYPECOMPRESSOR    EQU     1
FILTERCLIPPINGTYPELIMIT         EQU     0

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

Get8BitWaveform Macro           ; Puts waveform value in EBX, range -32k->+32k
                Local X


IF CUBICINTERPOLATION

                Mov     BX, DI

                Push    EDX
                Push    DS

                Push    CS
                Pop     DS
                        Assume DS:Driver

                Sub     BX, 1
                Mov     InterpolationOffset, ECX
                AdC     BX, 0

                FILD    InterpolationOffset
                FMul    Const1On65536

                MovSX   EAX, Byte Ptr [ES:BX]
                MovSX   EBX, Byte Ptr [ES:DI]
                Mov     Sample1, EAX
                Mov     Sample2, EBX
                FILD    Sample1
                FILD    Sample2
                FMul    Const3

                MovSX   EAX, Byte Ptr [ES:DI+1]
                MovSX   EBX, Byte Ptr [ES:DI+2]
                Mov     Sample3, EAX
                Mov     Sample4, EBX
                FILD    Sample3
                FMul    Const3
                FILD    Sample4                 ; x, 3w, 3v, u, Interp

; a = x+3v-3w-u
; b = 3w+3u-6v
; c = 6w-2u-x-3v
; d = 6v

; Assignments:
; F = x+3v
; -> a = F-3w-u
; -> b = 3w+3u-6v
; -> c = 6w-2u-F
; -> d = 6v

IF INTELOPTIMISED
                FAdd    ST, ST(2)       ; x+3v[3], 3w, 3v, u, Interp
                FLd     ST(1)           ; 3w, x+3v[3], 3w, 3v, u, Interp
                FAdd    ST, ST(4)       ; 3w+u[3], x+3v[2], 3w, 3v, u, Interp
                FXCh    ST(4)           ; u, x+3v[2], 3w, 3v, 3w+u[3], Interp
                FAdd    ST, ST          ; 2u[3], x+3v[1], 3w, 3v, 3w+u[2], Interp
                FXCh    ST(3)           ; 3v, x+3v[1], 3w, 2u[3], 3w+u[2], Interp
                FLd     ST(1)           ; x+3v, 3v, x+3v, 3w, 2u[3], 3w+u[1], Interp
                FSub    ST, ST(5)       ; a[3], 3v, x+3v, 3w, 2u[2], 3w+u, Interp
                FXCh                    ; 3v, a[3], x+3v, 3w, 2u[2], 3w+u, Interp
                FAdd    ST, ST          ; 6v[3], a[2], x+3v, 3w, 2u[1], 3w+u, Interp
                FXCh    ST(5)           ; 3w+u, a[2], x+3v, 3w, 2u[1], 6v[3], Interp
                FAdd    ST, ST(4)       ; 3w+3u[3], a[1], x+3v, 3w, 2u, 6v[2], Interp
                FXCh                    ; a[1], 3w+3u[3], x+3v, 3w, 2u, 6v[2], Interp
                FMul    ST, ST(6)       ; ax[3], 3w+3u[2], x+3v, 3w, 2u, 6v[1], Interp
                FXCh    ST(2)           ; x+3v, 3w+3u[2], ax[3], 3w, 2u, 6v[1], Interp
                FAddP   ST(4), ST       ; 3w+3u[1], ax[2], 3w, 2u+F[3], 6v, Interp
                FSub    ST, ST(4)       ; 3w+3u-6v[3], ax[1], 3w, 2u+F[2], 6v, Interp
                FXCh    ST(2)           ; 3w, ax[1], b[3], 2u+F[1], 6v, Interp
                FAdd    ST, ST          ; 6w[3], ax, b[2], 2u+F, 6v, Interp
                FXCh                    ; ax, 6w[3], b[2], 2u+F, 6v, Interp
                FAddP   ST(2), ST       ; 6w[1], ax+b[3], 2u+f, d, Interp
                FSubRP  ST(2), ST       ; ax+b, c[3], d, Interp
                FMul    ST, ST(3)       ; ax^2+bx[3], c[2], d, Interp
                FXCh    ST(3)           ; Interp, c[2], d, ax^2+bx[3]
                FMul    Const256On6     ; sInterp[3], c, d, ax^2+bx[1]
                FXCh                    ; c, sInterp[3], d, ax^2+bx[1]
                FAddP   ST(3), ST       ; sInterp[2], d, ax^2+bx+c[3]
                FXCh                    ; d, sInterp[2], ax^2+bx+c[3]
                FMul    Const256On6     ; sd[3], sInterp[1], ax^2+bx+c[2]
                FXCh                    ; sInterp[1], sd[3], ax^2+bx+c[2]
                FMulP   ST(2), ST

                Pop     DS
                        Assume DS:Nothing
                Mov     EDX, [DS:0]

                FAdd                    ; SampleValue (16 bit value)

                FLd     DWord Ptr [DS:0]        ; x(k-1), x(k)
                FMul    DWord Ptr [DS:14h]      ; b.x(k-1), x(k)
                FLd     DWord Ptr [DS:4]        ; x(k-2), b.x(k-1), x(k)
                FMul    DWord Ptr [DS:18h]      ; c.x(k-2), b.x(k-1), x(k)
                FXCh    ST(2)                   ; x(k), b.x(k-1), c.x(k-2)
                FMul    DWord Ptr [DS:10h]      ; a.x(k), b.x(k-1), c.x(k-2)
                FXCh    ST(2)                   ; c.x(k-2), b.x(k-1), a.x(k)
                FAdd
                Mov     EDX, [DS:0]
                FAdd

                Mov     [DS:4], EDX

                FSt     DWord Ptr [DS:0]
                FIStP   CS:SampleValue

ELSE
                FAdd    ST, ST(2)               ; x+3v, 3w, 3v, u, Interp
                FLd     ST(1)                   ; 3w, x+3v, 3w, 3v, u, Interp
                FSub    ST, ST(4)               ; 3w-u, x+3v, 3w, 3v, u, Interp
                FAdd    ST, ST                  ; 6w-2u, x+3v, 3w, 3v, u, Interp
                FSub    ST, ST(1)               ; "c", x+3v, 3w, 3v, u, Interp
                FXCh                            ; x+3v, "c", 3w, 3v, u, Interp
                FSub    ST, ST(2)               ; x+3v-3w, "c", 3w, 3v, u, Interp
                FSub    ST, ST(4)               ; "a", "c", 3w, 3v, u, Interp
                FMul    ST, ST(5)               ; "ax", "c", 3w, 3v, u, Interp
                FXCh    ST(3)                   ; 3v, "c", 3w, "ax", u, Interp
                FAdd    ST, ST                  ; 6v, "c", 3w, "ax", u, Interp
                FXCh    ST(4)                   ; u, "c", 3w, "ax", 6v, Interp
                FMul    Const3                  ; 3u, "c", 3w, "ax", 6v, Interp
                FSub    ST, ST(4)               ; 3u-6v, "c", 3w, "ax", 6v, Interp
                FAdd    ST, ST(2)               ; "b", "c", 3w, "ax", 6v, Interp
                FAdd    ST, ST(3)               ; "ax+b", "c", 3w, "ax", 6v, Interp
                FMul    ST, ST(5)               ; "ax^2+bx", "c", 3w, "ax", 6v, Interp
                FAdd                            ; ax^2+bx+c, 3w, "ax", 6v, Interp
                FMulP   ST(4), ST               ; 3w, "ax", 6v, ax^3+bx^2+cx
                FComPP                          ; 6v, ax^3+bx^2+cx
                FAdd                            ; SampleValue
                FMul    Const256On6             ; x(k)

                Pop     DS
                        Assume DS:Nothing

                FMul    DWord Ptr [DS:10h]

                FLd     DWord Ptr [DS:0]        ; x(k-1), x(k)
                FMul    DWord Ptr [DS:14h]      ; b.x(k-1), x(k)
                FLd     DWord Ptr [DS:4]        ; x(k-2), b.x(k-1), x(k)
                FMul    DWord Ptr [DS:18h]      ; c.x(k-2), b.x(k-1), x(k)
                FAdd
                Mov     EDX, [DS:0]
                FAdd

                Mov     [DS:4], EDX

                FSt     DWord Ptr [DS:0]
                FIStP   SampleValue

ENDIF
                Pop     EDX

 IF FILTERCLIPPINGTYPENONE
 ELSE
                Mov     EAX, [DS:0]
                And     EAX, 7FFFFFFFh
                Cmp     EAX, MAXFILTERVALUE
                JBE     X

  IF FILTERCLIPPINGTYPECOMPRESSOR

                Mov     EBX, [DS:0]
                FLd     CS:Const22713_0
                FLd     DWord Ptr [DS:0]
                FAbs
                FMul    CS:Const1On32768
                FYL2X   ; ST = ln(x/65536) / ln(2) * 65536 * ln(2)
                FAdd    CS:Const32768
                SAR     EBX, 31
                FIStP   SampleValue
                Xor     SampleValue, EBX
                Sub     SampleValue, EBX

Comment ~
                Mov     EBX, [DS:0]
                FLd     DWord Ptr [DS:0]
                FAbs
                FSub    [CS:Const65536]
                FMul    [CS:ConstLimiter]
                FAdd    [CS:Const65536]
                SAR     EBX, 31
                FIStP   SampleValue
                Xor     SampleValue, EBX
                Sub     SampleValue, EBX
;                FILD    SampleValue
;                FStP    DWord Ptr [DS:0]
~
  ENDIF
  IF FILTERCLIPPINGTYPELIMIT

                Mov     EBX, [DS:0]
                Mov     EAX, MAXFILTERVALUE
                And     EBX, 80000000h
                Or      EAX, EBX
                Mov     [DS:0], EAX
  ENDIF
X:
 ENDIF
                Mov     EBX, SampleValue

ENDIF

IF QUADRATICINTERPOLATION

                Push    EDX
                Push    EBP

                MovSX   EDX, Byte Ptr [ES:DI+2]         ; v
                MovSX   EBX, Byte Ptr [ES:DI]           ; t
                MovSX   EAX, Byte Ptr [ES:DI+1]         ; u

                LEA     EBP, [EBX+EDX]          ; v+t
                SAR     EBP, 1
                Sub     EBP, EAX                ; (v+t)/2 - u
                IMul    EBP, ECX                ; ax in 8.16 format
                SAR     EBP, 10                 ; ax in 8.6 format

                ShL     EAX, 7                  ; EBX = 2u<<6
                Add     EDX, EBX                ; EDX = v+t
                Add     EBX, EBX                ; EAX = 2t
                Add     EBP, EAX                ; EBP = ax+2u
                Add     EDX, EBX                ; 3t+v
                ShL     EDX, 5                  ; (3t+v)/2 << 6
                Sub     EBP, EDX                ; ax+b

                ShL     EBX, 7

                IMul    EBP, ECX                ; ax^2+bx in 8.22 form
                SAR     EBP, 14                 ; ax^2+bx in 8.8 form

                Add     EBX, EBP                ; ax^2+bx+c

                Pop     EBP
                Pop     EDX
ENDIF


IF LINEARINTERPOLATION
                MovSX   EBX, Byte Ptr [ES:DI+1]
                MovSX   EAX, Byte Ptr [ES:DI]
                Sub     EBX, EAX
                IMul    EBX, ECX
                SAR     EBX, 8
                ShL     EAX, 8
                Add     EBX, EAX
ENDIF

IF POINTSAMPLED
                MovSX   EBX, Byte Ptr [ES:DI]
                ShL     EBX, 8
ENDIF

EndM

Get16BitWaveform Macro          ; Puts waveform value in EBX, range -32k->+32k
                Local X

IF CUBICINTERPOLATION
                Mov     EBX, EDI

                Push    EDX
                Push    DS

                Push    CS
                Pop     DS
                        Assume DS:Driver

                Sub     BX, 1
                Mov     InterpolationOffset, ECX
                AdC     BX, 0

                FILD    InterpolationOffset
                FMul    Const1On65536

                MovSX   EAX, Word Ptr [ES:EBX+EBX]
                MovSX   EBX, Word Ptr [ES:EDI+EDI]
                Mov     Sample1, EAX
                Mov     Sample2, EBX
                FILD    Sample1
                FILD    Sample2
                FMul    Const3

                MovSX   EAX, Word Ptr [ES:EDI+EDI+2]
                MovSX   EBX, Word Ptr [ES:EDI+EDI+4]
                Mov     Sample3, EAX
                Mov     Sample4, EBX
                FILD    Sample3
                FMul    Const3
                FILD    Sample4                 ; x, 3w, 3v, u, Interp


; a = x+3v-3w-u
; b = 3w+3u-6v
; c = 6w-2u-x-3v
; d = 6v

; Assignments:
; F = x+3v
; -> a = F-3w-u
; -> b = 3w+3u-6v
; -> c = 6w-2u-F
; -> d = 6v

IF INTELOPTIMISED
                FAdd    ST, ST(2)       ; x+3v[3], 3w, 3v, u, Interp
                FLd     ST(1)           ; 3w, x+3v[3], 3w, 3v, u, Interp
                FAdd    ST, ST(4)       ; 3w+u[3], x+3v[2], 3w, 3v, u, Interp
                FXCh    ST(4)           ; u, x+3v[2], 3w, 3v, 3w+u[3], Interp
                FAdd    ST, ST          ; 2u[3], x+3v[1], 3w, 3v, 3w+u[2], Interp
                FXCh    ST(3)           ; 3v, x+3v[1], 3w, 2u[3], 3w+u[2], Interp
                FLd     ST(1)           ; x+3v, 3v, x+3v, 3w, 2u[3], 3w+u[1], Interp
                FSub    ST, ST(5)       ; a[3], 3v, x+3v, 3w, 2u[2], 3w+u, Interp
                FXCh                    ; 3v, a[3], x+3v, 3w, 2u[2], 3w+u, Interp
                FAdd    ST, ST          ; 6v[3], a[2], x+3v, 3w, 2u[1], 3w+u, Interp
                FXCh    ST(5)           ; 3w+u, a[2], x+3v, 3w, 2u[1], 6v[3], Interp
                FAdd    ST, ST(4)       ; 3w+3u[3], a[1], x+3v, 3w, 2u, 6v[2], Interp
                FXCh                    ; a[1], 3w+3u[3], x+3v, 3w, 2u, 6v[2], Interp
                FMul    ST, ST(6)       ; ax[3], 3w+3u[2], x+3v, 3w, 2u, 6v[1], Interp
                FXCh    ST(2)           ; x+3v, 3w+3u[2], ax[3], 3w, 2u, 6v[1], Interp
                FAddP   ST(4), ST       ; 3w+3u[1], ax[2], 3w, 2u+F[3], 6v, Interp
                FSub    ST, ST(4)       ; 3w+3u-6v[3], ax[1], 3w, 2u+F[2], 6v, Interp
                FXCh    ST(2)           ; 3w, ax[1], b[3], 2u+F[1], 6v, Interp
                FAdd    ST, ST          ; 6w[3], ax, b[2], 2u+F, 6v, Interp
                FXCh                    ; ax, 6w[3], b[2], 2u+F, 6v, Interp
                FAddP   ST(2), ST       ; 6w[1], ax+b[3], 2u+f, d, Interp
                FSubRP  ST(2), ST       ; ax+b, c[3], d, Interp
                FMul    ST, ST(3)
                FXCh    ST(3)           ; Interp, c[2], d, ax^2+bx[3]
                FMul    Const1On6       ; sInterp[3], c, d, ax^2+bx[1]
                FXCh                    ; c, sInterp[3], d, ax^2+bx[1]
                FAddP   ST(3), ST       ; sInterp[2], d, ax^2+bx+c[3]
                FXCh                    ; d, sInterp[2], ax^2+bx+c[3]
                FMul    Const1On6       ; sd[3], sInterp[1], ax^2+bx+c[2]
                FXCh                    ; sInterp[1], sd[3], ax^2+bx+c[2]
                FMulP   ST(2), ST

                Pop     DS
                        Assume DS:Nothing
                Mov     EDX, [DS:0]

                FAdd                    ; SampleValue (16 bit value)

                FLd     DWord Ptr [DS:0]        ; x(k-1), x(k)
                FMul    DWord Ptr [DS:14h]      ; b.x(k-1), x(k)
                FLd     DWord Ptr [DS:4]        ; x(k-2), b.x(k-1), x(k)
                FMul    DWord Ptr [DS:18h]      ; c.x(k-2), b.x(k-1), x(k)
                FXCh    ST(2)                   ; x(k), b.x(k-1), c.x(k-2)
                FMul    DWord Ptr [DS:10h]      ; a.x(k), b.x(k-1), c.x(k-2)
                FXCh    ST(2)                   ; c.x(k-2), b.x(k-1), a.x(k)
                FAdd
                Mov     EDX, [DS:0]
                FAdd

                Mov     [DS:4], EDX

                FSt     DWord Ptr [DS:0]
                FIStP   CS:SampleValue

ELSE
                FAdd    ST, ST(2)               ; x+3v, 3w, 3v, u, Interp
                FLd     ST(1)                   ; 3w, x+3v, 3w, 3v, u, Interp
                FSub    ST, ST(4)               ; 3w-u, x+3v, 3w, 3v, u, Interp
                FAdd    ST, ST                  ; 6w-2u, x+3v, 3w, 3v, u, Interp
                FSub    ST, ST(1)               ; "c", x+3v, 3w, 3v, u, Interp
                FXCh                            ; x+3v, "c", 3w, 3v, u, Interp
                FSub    ST, ST(2)               ; x+3v-3w, "c", 3w, 3v, u, Interp
                FSub    ST, ST(4)               ; "a", "c", 3w, 3v, u, Interp
                FMul    ST, ST(5)               ; "ax", "c", 3w, 3v, u, Interp
                FXCh    ST(3)                   ; 3v, "c", 3w, "ax", u, Interp
                FAdd    ST, ST                  ; 6v, "c", 3w, "ax", u, Interp
                FXCh    ST(4)                   ; u, "c", 3w, "ax", 6v, Interp
                FMul    Const3                  ; 3u, "c", 3w, "ax", 6v, Interp
                FSub    ST, ST(4)               ; 3u-6v, "c", 3w, "ax", 6v, Interp
                FAdd    ST, ST(2)               ; "b", "c", 3w, "ax", 6v, Interp
                FAdd    ST, ST(3)               ; "ax+b", "c", 3w, "ax", 6v, Interp
                FMul    ST, ST(5)               ; "ax^2+bx", "c", 3w, "ax", 6v, Interp
                FAdd                            ; ax^2+bx+c, 3w, "ax", 6v, Interp
                FMulP   ST(4), ST               ; 3w, "ax", 6v, ax^3+bx^2+cx
                FComPP                          ; 6v, ax^3+bx^2+cx
                FAdd                            ; SampleValue
                FMul    Const1On6

                Pop     DS
                        Assume DS:Nothing

                FMul    DWord Ptr [DS:10h]

                FLd     DWord Ptr [DS:0]        ; x(k-1), x(k)
                FMul    DWord Ptr [DS:14h]      ; b.x(k-1), x(k)
                FLd     DWord Ptr [DS:4]        ; x(k-2), b.x(k-1), x(k)
                FMul    DWord Ptr [DS:18h]      ; c.x(k-2), b.x(k-1), x(k)
                FAdd
                Mov     EDX, [DS:0]
                FAdd

                Mov     [DS:4], EDX

                FSt     DWord Ptr [DS:0]
                FIStP   SampleValue
ENDIF
                Pop     EDX

 IF FILTERCLIPPINGTYPENONE
 ELSE
                Mov     EAX, [DS:0]
                And     EAX, 7FFFFFFFh
                Cmp     EAX, MAXFILTERVALUE
                JBE     X

  IF FILTERCLIPPINGTYPECOMPRESSOR

                Mov     EBX, [DS:0]
                FLd     CS:Const22713_0
                FLd     DWord Ptr [DS:0]
                FAbs
                FMul    CS:Const1On32768
                FYL2X   ; ST = ln(x/65536) / ln(2) * 65536 * ln(2)
                FAdd    CS:Const32768
                SAR     EBX, 31
                FIStP   SampleValue
                Xor     SampleValue, EBX
                Sub     SampleValue, EBX

Comment ~
                Mov     EBX, [DS:0]
                FLd     DWord Ptr [DS:0]
                FAbs
                FSub    [CS:Const65536]
                FMul    [CS:ConstLimiter]
                FAdd    [CS:Const65536]
                SAR     EBX, 31
                FIStP   SampleValue
                XOr     SampleValue, EBX
                Sub     SampleValue, EBX
;                FILD    SampleValue
;                FStP    DWord Ptr [DS:0]
~

  ENDIF
  IF FILTERCLIPPINGTYPELIMIT

                Mov     EBX, [DS:0]
                Mov     EAX, MAXFILTERVALUE
                And     EBX, 80000000h
                Or      EAX, EBX
                Mov     [DS:0], EAX
  ENDIF
X:
 ENDIF
                Mov     EBX, SampleValue

ENDIF

IF QUADRATICINTERPOLATION

                Push    ECX
                Push    EDX
                Push    EBP

                MovSX   EDX, Word Ptr [ES:EDI+EDI+4]     ; v
                MovSX   EBX, Word Ptr [ES:EDI+EDI]       ; t
                MovSX   EAX, Word Ptr [ES:EDI+EDI+2]     ; u

                ShR     ECX, 3                  ; 0.13
                LEA     EBP, [EBX+EDX]
                SAR     EBP, 1
                Sub     EBP, EAX                ; (v+t)/2 - u
                IMul    EBP, ECX                ; 16.13
                SAR     EBP, 14                 ; 15.0

                Add     EDX, EBX                ; EDX = v+t
                Add     EBP, EAX                ; EBP = ax+2u
                LEA     EDX, [EDX+EBX*2]
                SAR     EDX, 2                  ; EDX = (3t+v)/2
                Sub     EBP, EDX                ; ax + b, 15 form

                IMul    EBP, ECX                ; ax^2+bx in 15.13 form
                SAR     EBP, 12                 ; ax^2+bx in 16.0 form

                Add     EBX, EBP

                Pop     EBP
                Pop     EDX
                Pop     ECX

ENDIF

IF LINEARINTERPOLATION
                MovSX   EBX, Word Ptr [ES:EDI+EDI+2]
                MovSX   EAX, Word Ptr [ES:EDI+EDI]
                Sub     EBX, EAX
                SAR     EBX, 1
                IMul    EBX, ECX
                SAR     EBX, 15
                Add     EBX, EAX
ENDIF

IF POINTSAMPLED
                MovSX   EBX, Word Ptr [ES:EDI+EDI]
ENDIF

EndM

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

Proc            Mix32Stereo8Bit         ; Given DS:SI = buffer
                                        ; Given ES:DI = sample
                                        ; AX = bytes to mix
                                        ; CX = error
                                        ; DX = delta offset
                                        ; BP = delta error

                ShL     AX, 3
                Add     AX, SI
                Mov     Word Ptr [CS:M32S8BEND], AX

Mix32Stereo8Bit1:
                Get8BitWaveForm

M32S8BLVC       EQU     $+3
                IMul    EAX, EBX, 12345678h
                Sub     [SI], EAX

                Mov     CS:LastLeftValue, EAX

M32S8BRVC       EQU     $+3
                IMul    EAX, EBX, 12345678h
                Sub     [SI+4], EAX

                Mov     CS:LastRightValue, EAX

                Add     CX, BP
                AdC     DI, DX
                Add     SI, 8

M32S8BLVSet     EQU     $+2
                Mov     EAX, 12345678h          ; Destination volume left
M32S8BRVSet     EQU     $+2
                Mov     EBX, 12345678h          ; Destination volume right

                Sub     EAX, DWord Ptr [CS:M32S8BLVC]     ; Delta
                Sub     EBX, DWord Ptr [CS:M32S8BRVC]

                SAR     EAX, RAMPSPEED
                SAR     EBX, RAMPSPEED

                Add     DWord Ptr [CS:M32S8BLVC], EAX
                Add     DWord Ptr [CS:M32S8BRVC], EBX

M32S8BNoRightRamp:

M32S8BEND       EQU     $+2
                Cmp     SI, 1234h
                JNE     Mix32Stereo8Bit1

                Ret

EndP            Mix32Stereo8Bit

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

Proc            PreM32SMix8Bit

IF VOLUMERAMP
                PushAD

                Xor     EAX, EAX
                Xor     EBX, EBX
                Xor     EDX, EDX
                Xor     EBP, EBP
                Xor     EDI, EDI

                Mov     AX, Word Ptr [SI+0Ch]   ; New right volume
                Mov     BX, Word Ptr [SI+0Eh]   ; New left volume

                Mov     DX, Word Ptr [SI+1Ch]   ; Old right volume
                Mov     BP, Word Ptr [SI+1Eh]   ; Old left volume

                Mov     DWord Ptr [CS:M32S8BRVC], EDX
                Mov     DWord Ptr [CS:M32S8BLVC], EBP

; Compensate for upwards ramp.

                Cmp     AX, DX
                JB      PreM32Mix8BitNoRightCompensate

                Add     AX, RAMPCOMPENSATE

PreM32Mix8BitNoRightCompensate:

                Cmp     BX, BP
                JB      PreM32Mix8BitNoLeftCompensate

                Add     BX, RAMPCOMPENSATE

PreM32Mix8BitNoLeftCompensate:
                Mov     DWord Ptr [CS:M32S8BRVSet], EAX
                Mov     DWord Ptr [CS:M32S8BLVSet], EBX

; Now to figure out exact final volumes

                Push    SI
                Mov     CX, CS:RealBytesToMix

PreM32Mix8Bit1:
                Mov     ESI, EAX        ; Set values
                Mov     EDI, EBX
                Sub     ESI, EDX        ; Current values
                Sub     EDI, EBP
                SAR     ESI, RAMPSPEED
                SAR     EDI, RAMPSPEED
                Add     EDX, ESI
                Add     EBP, EDI

                Loop    PreM32Mix8Bit1

                Pop     SI

                Mov     Word Ptr [SI+1Ch], DX
                Mov     Word Ptr [SI+1Eh], BP

                PopAD
                Ret
ELSE

                Xor     EAX, EAX
                Xor     EBX, EBX

                Mov     AX, Word Ptr [SI+0Ch]
                Mov     BX, Word Ptr [SI+0Eh]

                Mov     DWord Ptr [CS:M32S8BRVC], EAX
                Mov     DWord Ptr [CS:M32S8BLVC], EBX

                Mov     DWord Ptr [CS:M32S8BRVSet], EAX
                Mov     DWord Ptr [CS:M32S8BLVSet], EBX

                Mov     [SI+1Ch], AX
                Mov     [SI+1Eh], BX

                Ret
ENDIF

EndP            PreM32SMix8Bit

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

Proc            Mix32Surround8Bit       ; Given DS:SI = buffer
                                        ; Given ES:DI = sample
                                        ; AX = bytes to mix
                                        ; CX = error
                                        ; DX = delta offset
                                        ; BP = delta error

                ShL     AX, 3
                Add     AX, SI
                Mov     Word Ptr [CS:M32U8BEND], AX

Mix32Surround8Bit1:
                Get8BitWaveForm

M32U8BLVC       EQU     $+3
                IMul    EAX, EBX, 12345678h
                Sub     [SI], EAX
                Mov     CS:LastLeftValue, EAX

                Neg     EAX
M32U8BLVSet     EQU     $+2
                Mov     EBX, 12345678h

                Sub     [SI+4], EAX
                Sub     EBX, DWord Ptr [CS:M32U8BLVC]


                SAR     EBX, RAMPSPEED
                Add     SI, 8

                Add     CX, BP
                AdC     DI, DX

                Add     DWord Ptr [CS:M32U8BLVC], EBX

M32U8BEND       EQU     $+2
                Cmp     SI, 1234h
                JNE     Mix32Surround8Bit1

                Mov     EAX, CS:LastLeftValue
                Neg     EAX
                Mov     CS:LastRightValue, EAX
                Ret

EndP            Mix32Surround8Bit

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

Proc            PreM32UMix8Bit

IF VOLUMERAMP
                Xor     EAX, EAX
                Xor     EBX, EBX
                Mov     AX, Word Ptr [SI+1Eh]   ; Old
                Mov     BX, Word Ptr [SI+0Eh]   ; New
                Mov     DWord Ptr [CS:M32U8BLVC], EAX

; Compensate for upwards ramp.

                Cmp     BX, AX
                JB      PreM32MixU8Bit2

                Add     BX, RAMPCOMPENSATE

PreM32MixU8Bit2:
                Mov     DWord Ptr [CS:M32U8BLVSet], EBX

                Mov     CX, CS:RealBytesToMix

PreM32UMix8Bit1:
                Mov     EDX, EBX
                Sub     EDX, EAX
                SAR     EDX, RAMPSPEED
                Add     EAX, EDX

                Loop    PreM32UMix8Bit1

                Mov     [SI+1Eh], AX
                Ret

ELSE
                Xor     EAX, EAX
                Mov     AX, Word Ptr [SI+0Eh]
                Mov     DWord Ptr [CS:M32U8BLVC], EAX
                Mov     DWord Ptr [CS:M32U8BLVSet], EAX
                Mov     [SI+1Eh], AX

                Ret
ENDIF

EndP            PreM32UMix8Bit

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

Proc            Mix32Stereo16Bit

                ShL     AX, 3
                Add     AX, SI
                Mov     Word Ptr [CS:M32S16BEND], AX

Mix32Stereo16Bit1:
                Get16BitWaveform

M32S16BLVC      EQU     $+3
                IMul    EAX, EBX, 12345678h
                Sub     [SI], EAX

                Mov     CS:LastLeftValue, EAX

M32S16BRVC      EQU     $+3
                IMul    EAX, EBX, 12345678h
                Sub     [SI+4], EAX

                Mov     CS:LastRightValue, EAX

                Add     CX, BP
                AdC     DI, DX

M32S16BLVSet    EQU     $+2
                Mov     EAX, 12345678h          ; Destination volume left
M32S16BRVSet    EQU     $+2
                Mov     EBX, 12345678h          ; Destination volume right

                Sub     EAX, DWord Ptr [CS:M32S16BLVC]     ; Delta
                Sub     EBX, DWord Ptr [CS:M32S16BRVC]

                SAR     EAX, RAMPSPEED
                SAR     EBX, RAMPSPEED

                Add     DWord Ptr [CS:M32S16BLVC], EAX
                Add     DWord Ptr [CS:M32S16BRVC], EBX

                Add     SI, 8

M32S16BEND      EQU     $+2
                Cmp     SI, 1234h
                JNE     Mix32Stereo16Bit1

                Ret

EndP            Mix32Stereo16Bit

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

Proc            PreM32SMix16Bit

IF VOLUMERAMP
                PushAD

                Xor     EAX, EAX
                Xor     EBX, EBX
                Xor     EDX, EDX
                Xor     EBP, EBP
                Xor     EDI, EDI

                Mov     AX, Word Ptr [SI+0Ch]   ; New right volume
                Mov     BX, Word Ptr [SI+0Eh]   ; New left volume

                Mov     DX, Word Ptr [SI+1Ch]   ; Old right volume
                Mov     BP, Word Ptr [SI+1Eh]   ; Old left volume

                Mov     DWord Ptr [CS:M32S16BRVC], EDX
                Mov     DWord Ptr [CS:M32S16BLVC], EBP

; Compensate for upwards ramp.

                Cmp     AX, DX
                JB      PreM32Mix16BitNoRightCompensate

                Add     AX, RAMPCOMPENSATE

PreM32Mix16BitNoRightCompensate:

                Cmp     BX, BP
                JB      PreM32Mix16BitNoLeftCompensate

                Add     BX, RAMPCOMPENSATE

PreM32Mix16BitNoLeftCompensate:
                Mov     DWord Ptr [CS:M32S16BRVSet], EAX
                Mov     DWord Ptr [CS:M32S16BLVSet], EBX

; Now to figure out exact final volumes

                Push    SI
                Mov     CX, CS:RealBytesToMix

PreM32Mix16Bit1:
                Mov     ESI, EAX        ; Set values
                Mov     EDI, EBX

                Sub     ESI, EDX        ; Current values
                Sub     EDI, EBP

                SAR     ESI, RAMPSPEED
                SAR     EDI, RAMPSPEED

                Add     EDX, ESI
                Add     EBP, EDI

                Loop    PreM32Mix16Bit1
                Pop     SI

                Mov     Word Ptr [SI+1Ch], DX
                Mov     Word Ptr [SI+1Eh], BP

                PopAD
                Ret
ELSE

                Xor     EAX, EAX
                Xor     EBX, EBX

                Mov     AX, Word Ptr [SI+0Ch]
                Mov     BX, Word Ptr [SI+0Eh]

                Mov     DWord Ptr [CS:M32S16BRVC], EAX
                Mov     DWord Ptr [CS:M32S16BLVC], EBX

                Mov     DWord Ptr [CS:M32S16BRVSet], EAX
                Mov     DWord Ptr [CS:M32S16BLVSet], EBX

                Mov     [SI+1Ch], AX
                Mov     [SI+1Eh], BX

                Ret
ENDIF

EndP            PreM32SMix16Bit

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

Proc            Mix32Surround16Bit       ; Given DS:SI = buffer
                                        ; Given ES:DI = sample
                                        ; AX = bytes to mix
                                        ; CX = error
                                        ; DX = delta offset
                                        ; BP = delta error

                ShL     AX, 3
                Add     AX, SI
                Mov     Word Ptr [CS:M32U16BEND], AX

Mix32Surround16Bit1:
                Get16BitWaveForm

M32U16BLVC       EQU     $+3
                IMul    EAX, EBX, 12345678h
                Sub     [SI], EAX

M32U16BLVSet     EQU     $+2
                Mov     EBX, 12345678h

                Neg     EAX
                Sub     EBX, DWord Ptr [CS:M32U16BLVC]

                Sub     [SI+4], EAX

                SAR     EBX, RAMPSPEED
                Add     SI, 8

                Add     CX, BP
                AdC     DI, DX

                Add     DWord Ptr [CS:M32U16BLVC], EBX

M32U16BEND      EQU     $+2
                Cmp     SI, 1234h
                JNE     Mix32Surround16Bit1

                Mov     CS:LastRightValue, EAX
                Neg     EAX
                Mov     CS:LastLeftValue, EAX
                Ret

EndP            Mix32Surround16Bit

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

Proc            PreM32UMix16Bit

IF VOLUMERAMP
                Xor     EAX, EAX
                Xor     EBX, EBX
                Mov     AX, Word Ptr [SI+1Eh]
                Mov     BX, Word Ptr [SI+0Eh]
                Mov     DWord Ptr [CS:M32U16BLVC], EAX

; Compensate for upwards ramp.

                Cmp     BX, AX
                JB      PreM32MixU16Bit2

                Add     BX, RAMPCOMPENSATE

PreM32MixU16Bit2:

                Mov     DWord Ptr [CS:M32U16BLVSet], EBX

                Mov     CX, CS:RealBytesToMix

PreM32UMix16Bit1:
                Mov     EDX, EBX
                Sub     EDX, EAX
                SAR     EDX, RAMPSPEED
                Add     EAX, EDX

                Loop    PreM32UMix16Bit1

                Mov     [SI+1Eh], AX
                Ret

ELSE
                Xor     EAX, EAX
                Mov     AX, Word Ptr [SI+0Eh]
                Mov     DWord Ptr [CS:M32U16BLVC], EAX
                Mov     DWord Ptr [CS:M32U16BLVSet], EAX
                Mov     [SI+1Eh], AX
                Ret
ENDIF

EndP            PreM32UMix16Bit

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

NUMBEROFFILTERBANDS     EQU     4

ALIGN 4
LastClickRemovalLeft    DD      0
LastClickRemovalRight   DD      0
StartingChannelOffset   DW      0
FilterParameters        DB      64 Dup (7Fh), 64 Dup (0)
FilterValues            DD      4*256 Dup (0)
SampleFilterCopyOffset  DW      16*64
FreqMultiplier          DD      3A9F7867h   ; = 1/(2*PI*110.0*2^0.25)
FreqParameterMultiplier DD      0B92AAAAAh  ; = -1/(24*256)
FilterFreqValue         DW      0
NewControlWord          DW      7Fh
include q.inc

LastFilter              DD      NUMBEROFFILTERBANDS*2 Dup (0) ; 4 stereo values
FilterCoefficients      DD      NUMBEROFFILTERBANDS*2 Dup (0)
FilterVolumes           DD      NUMBEROFFILTERBANDS   Dup (0)

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

Proc            IsSampleMode            ; returns zero flag if sample mode.

                Push    DS

                Mov     DS, CS:SongDataArea
                Test    Byte Ptr [DS:2Ch], 4

                Pop     DS
                Ret

EndP            IsSampleMode
                Assume DS:Nothing

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

Proc            M32MixHandler
                                ; Clear output buffer first...

                Mov     CS:StartingChannelOffset, SI

                Push    CX

                Mov     ES, CS:MixSegment
                Mov     EAX, CS:BytesToMixFractional
                Mov     CX, CS:BytesToMix
                Add     CurrentFractional, EAX
                AdC     CX, 0
                Mov     CS:RealBytestoMix, CX
;                Add     CX, CX          ; Stereo = 2 * BytesToMix
;                Mov     DI, 32
;                Xor     EAX, EAX
;                Rep     StosD

                Pop     CX

                PushAD

                Mov     EDX, CS:LastClickRemovalLeft
                Mov     EBP, CS:LastClickRemovalRight

; Do left first.
                Mov     SI, 80
                Mov     CX, CS:RealBytesToMix

ClickRemoval3:

Comment ~

                Mov     [ES:SI], EDX
                Mov     [ES:SI+4], EBP

                Inc     EDX
                JS      ClickRemoval4

                Sub     EDX, 2
                JGE     ClickRemoval4

                Inc     EDX

ClickRemoval4:
                Inc     EBP
                JS      ClickRemoval5

                Sub     EBP, 2
                JGE     ClickRemoval5

                Inc     EBP

ClickRemoval5:
~

                Mov     EAX, EDX
                Mov     EBX, EBP
                SAR     EAX, 12
                SAR     EBX, 12
                Mov     [ES:SI], EDX
                Mov     [ES:SI+4], EBP

                Sub     EAX, 1
                AdC     EAX, 1
                Sub     EBX, 1
                AdC     EBX, 1

                Sub     EDX, EAX
                Sub     EBP, EBX

                Add     SI, 8
                Loop    ClickRemoval3

                Mov     CS:LastClickRemovalLeft, EDX
                Mov     CS:LastClickRemovalRight, EBP

                PopAD

                                ; Check each channel...
                                ; Prepare mixing stuff

; Work backwards
                Mov     AX, CX
                Dec     AX
                ShL     AX, 7
                Add     SI, AX

M32MixHandler1:
                Test    Byte Ptr [SI], 1
                JZ      M32MixHandlerEnd2
                Cmp     Byte Ptr [SI+36h], 100
                JE      M32MixHandlerEnd2

                Push    CX
                Mov     BP, SI
                Sub     BP, [CS:StartingChannelOffset]  ; BP = SlaveChannel*128
                SHR     BP, 3                           ; BP = SlaveChannel*16
                Mov     DI, BP
                Add     BP, Offset FilterValues

                Mov     CX, [SI]
                Test    CH, 2
                JZ      M32MixHandler13

                                                        ; Note cut.
                And     Byte Ptr [SI], Not 1            ; Turn off channel
                Mov     Word Ptr [SI+4Ah], 0
                Or      CL, 40h

M32MixHandler13:
                Test    CL, 20h         ; New freq?
                JZ      M32MixHandler3

                Mov     AX, [SI+10h]
                Mov     DX, [SI+12h]
                Mov     BX, MixSpeed
                Cmp     DX, BX
                JAE     M32MixHandlerError

                Div     BX
                ShL     EAX, 16
                Xor     AX, AX
                Div     BX
                Mov     STEPVALUE, EAX

M32MixHandler3:
                Test    CH, 1                   ; New note?
                JZ      M32MixHandler12

                Xor     EAX, EAX
                Mov     DWord Ptr [SI+1Ch], EAX
                Mov     DWord Ptr [CS:BP], EAX
                Mov     DWord Ptr [CS:BP+4], EAX
                Mov     DWord Ptr [CS:BP+8], 3F800000h
                Mov     DWord Ptr [CS:BP+0Ch], EAX

M32MixHandler12:
                Test    CX, 8440h               ; New volume, loop or pan?
                JZ      M32MixHandler4

                Mov     AL, [SI+3Ah]
                Test    AL, AL
                JNS     M32MixHandlerFilter1

                Mov     BL, [SI+3Fh]
                Jmp     M32MixHandlerFilter2

M32MixHandlerFilter1:
                Mov     DI, AX
                And     DI, 63
                Add     DI, Offset FilterParameters

                Mov     AL, [CS:DI]
                Mov     BL, [CS:DI+64]
                Mov     [SI+5Bh], AL
                Mov     [SI+3Fh], BL

M32MixHandlerFilter2:
                Mov     AL, [SI+3Eh]
                Mul     Byte Ptr [SI+5Bh]
                Mov     CS:FilterFreqValue, AX
                ShR     AX, 8
                Mov     AH, BL
                AdC     AX, 0

                Cmp     AX, 7Fh
                JE      M32MixHandlerNoFilter

                And     BX, 0FFh
                ShL     BX, 2

                FNInit
                FLdCW   [CS:NewControlWord]

                FILD    [CS:FilterFreqValue]         ; 0->127*256
                FMul    [CS:FreqParameterMultiplier] ; -i/(24*256)
                FLd     ST
                FRndInt
                FSub    ST(1), ST
                FXCh
                F2XM1
                FLd1
                FAdd
                FScale                              ; = 2^(i/24*256)
                FMul    [CS:FreqMultiplier]         ; = r
                FLd     ST                              ; r, r
                FMul    ST(1), ST                       ; r, r^2

                FLd     [CS:QualityFactorTable+BX]      ; 2d, r, r^2
                FMul    ST(1), ST                       ; 2d, 2dr, r^2
                FLd1                                    ; 1, 2d, 2dr, r^2
                FSubP   ST(1), ST                       ; 2d-1, 2dr, r^2
                FAdd

                FLd1                                    ; 1, d, e
                FAdd    ST, ST(1)
                FAdd    ST, ST(2)                       ; 1+d+e, d, e
                FLd1                                    ; 1, 1+d+e, d, e
                FDivRP  ST(1), ST                       ; 1/(1+d+e), d, e
                FSt     DWord Ptr [CS:BP+8]
                FXCh                                    ; d, 1/(1+d+e), e
                FAdd    ST, ST(2)
                FAddP   ST(2), ST                       ; 1/(1+d+e), d+2e
                FMul
                FStP    DWord Ptr [CS:BP+0Ch]
                FStP    ST

M32MixHandlerNoFilter:

IF REGISTERED
                Test    CH, 8
                JNZ     M32MixHandler7

                Cmp     CS:Stereo, 0
                JE      M32MixHandler6

                Mov     AL, [SI+37h]            ; Final pan
                Cmp     AL, 100
                JE      M32MixHandler6

                Mul     Byte Ptr MixVolume
                Mul     Word Ptr [SI+4Ah]
                SHRD    AX, DX, 14

                Mov     [SI+0Ch], AX            ; Store into right volume

                Mov     AL, 64                  ; Do left volume
                Sub     AL, [SI+37h]            ; AL = 64-FinalPan
                Mul     Byte Ptr MixVolume
                Mul     Word Ptr [SI+4Ah]       ; Final volume
                SHRD    AX, DX, 14
                Mov     [SI+0Eh], AX

                                                ; Now to decide on mixing method
                Cmp     DWord Ptr [SI+0Ch], 0
                JNE     M32MixHandler5
ELSE
                Test    CH, 8
                JZ      M32MixHandler6

ENDIF

M32MixHandler7:
                                                ; Zero volume
                Xor     EAX, EAX
                Mov     [SI+0Ch], EAX
                Cmp     [SI+1Ch], EAX           ; Last volumes = 0?
                JE      M32MixHandler8

M32MixHandler5:                                ; Other.. (ie. panned)
                Mov     AX, 30
                Jmp     M32MixHandler8

M32MixHandler6:                                ; Surround sound
                Mov     AX, [SI+4Ah]
                Mul     MixVolume

IF REGISTERED
                ShRD    AX, DX, 8
                Cmp     CS:Stereo, 0
                JE      M32MixHandlerHalfStereoVolume

                ShR     AX, 1

M32MixHandlerHalfStereoVolume:

ELSE

                ShRD    AX, DX, 9
ENDIF

                Mov     [SI+0Ch], AX
                Mov     [SI+0Eh], AX

                Test    AX, AX
                JNZ     M32MixHandlerSurround1

                Cmp     DWord Ptr [SI+1Ch], 0
                JE      M32MixHandler7

M32MixHandlerSurround1:
                Mov     AX, 60

M32MixHandler8:
                Mov     BL, [SI+0Ah]
                Test    Byte Ptr [SI+18h], 2
                JZ      M32MixHandler9

                Add     AX, 90

M32MixHandler9:
                Cmp     BL, 8
                JB      M32MixHandler11        ; No loop
                JE      M32MixHandler10

                Add     AX, 10

M32MixHandler10:
                Add     AX, 10

M32MixHandler11:
                Add     AX, Offset WAVMixingTable
                Mov     [SI+8], AX              ; Offset...

M32MixHandler4:
                                                ; Mixing routine call...
                Mov     BX, [SI+8]              ; BX = offset into
                Mov     EAX, [CS:BX+2]
                Mov     DWord Ptr PreMixFunction, EAX
                Mov     EAX, [CS:BX+6]
                Mov     DWord Ptr MixFunctionSeparateBackwards, EAX

                Mov     AX, RealBytesToMix
                Mov     MixBlockSize, AX
                Mov     MixBufferOffset, 80

                Mov     EAX, CURRENTPOSITION
                Mov     OLDPOSITION, EAX

                Cmp     CS:StartNoRamp, 0
                JE      NoStartRamp

                Test    CH, 1
                JZ      NoStartRamp
                Cmp     DWord Ptr [SI+4Ch], 0
                JNE     NoStartRamp

                Mov     EAX, [SI+0Ch]
                Mov     [SI+1Ch], EAX

NoStartRamp:

                Mov     ES, CS:MixSegment       ; Get filter data
                Mov     EAX, [CS:BP]            ; Last sample 1
                Mov     EDX, [CS:BP+4]          ; Last sample 2
                Mov     [ES:0], EAX
                Mov     [ES:4], EDX
                Mov     EAX, [CS:BP+8]          ; Filtera
                Mov     EDX, [CS:BP+0Ch]        ; Filterb
                Mov     [ES:10h], EAX
                Mov     [ES:14h], EDX
                FLd1
                FSub    DWord Ptr [ES:10h]
                FSub    DWord Ptr [ES:14h]
                FStP    DWord Ptr [ES:18h]      ; Filterc

                Push    BP
                Call    Word Ptr [CS:BX]
                Pop     BP

                Mov     ES, CS:MixSegment       ; Store filter data
                Mov     EAX, [ES:0]
                Mov     EDX, [ES:4]
                Mov     [CS:BP], EAX
                Mov     [CS:BP+4], EDX

                And     Word Ptr [SI], 0111100010001101b

                Call    IsSampleMode
                JNE     M32MixHandlerEnd

                Mov     [CS:BP+16*64], EAX
                Mov     [CS:BP+16*64+4], EDX
                Mov     EAX, [CS:BP+8]
                Mov     EDX, [CS:BP+0Ch]
                Mov     [CS:BP+16*64+8], EAX
                Mov     [CS:BP+16*64+0Ch], EDX

                Jmp     M32MixHandlerEnd

M32MixHandlerError:
                Mov     Word Ptr [SI], 200h

                Test    Byte Ptr [SI+3Ah], 80h
                JNZ     M32MixHandlerEnd

                Mov     BX, [SI+38h]
                And     Byte Ptr [BX], Not 4    ; Turn off channel

M32MixHandlerEnd:
                Pop     CX

M32MixHandlerEnd2:
                Sub     SI, 128
                Dec     CX
                JNZ     M32MixHandler1

                Push    CS
                Pop     DS
                        Assume DS:Driver

                Xor     DI, DI
                Mov     SI, Offset LastFilter
                Mov     CX, 80/4
                Mov     ES, MixSegment

                Rep     MovsD

; Now do filtering.
                FNInit
                Mov     CX, RealBytesToMix

                Push    ES
                Pop     DS
                        Assume DS:Nothing

                Mov     SI, 80

OutputFilter1:
                FILD    DWord Ptr [SI]          ; Left sample
                FILD    DWord Ptr [SI+4]        ; R, L

                FLd     DWord Ptr [DS:20h]      ; LB, R, L
                FMul    ST, ST(2)               ; L.LB, R, L
                FLd     DWord Ptr [DS:20h]      ; LB, L.LB, R, L
                FMul    ST, ST(2)               ; R.LB, L.LB, R, L
                FLd     DWord Ptr [DS:0]        ; OL, R.LB, L.LB, R, L
                FMul    DWord Ptr [DS:24h]      ; OL.LB, R.LB, L.LB, R, L
                FLd     DWord Ptr [DS:4]        ; OR, OL.LB, R.LB, L.LB, R, L
                FMul    DWord Ptr [DS:24h]      ; OR.LB, OL.LB, R.LB, L.LB, R, L

                FXCh                            ; OL.LB, OR.LB, R.LB, L.LB, R, L
                FAddP   ST(3), ST
                FAdd                            ; RLB, LLB, R, L

                FLd     DWord Ptr [DS:28h]      ; MB, RLB, LLB, R, L
                FMul    ST, ST(4)               ; L.MB, RLB, LLB, R, L
                FLd     DWord Ptr [DS:28h]      ; MB, L.MB, RLB, LLB, R, L
                FMul    ST, ST(4)               ; R.MB, L.MB, RLB, LLB, R, L
                FLd     DWord Ptr [DS:8]        ; OL, R.MB, L.MB, RLB, LLB, R, L
                FMul    DWord Ptr [DS:2Ch]      ; OL.MB, R.MB, L.MB, RLB, LLB, R, L
                FLd     DWord Ptr [DS:0Ch]      ; OR, OL.MB, R.MB, L.MB, RLB, LLB, R, L
                FMul    DWord Ptr [DS:2Ch]      ; OR.MB, OL.MB, R.MB, L.MB, RLB, LLB, R, L

                FXCh                            ; OL.MB, OR.MB, R.MB, L.MB, RLB, LLB, R, L
                FAddP   ST(3), ST
                FAdd                            ; RMB, LMB, RLB, LLB, R, L
                FXCh    ST(3)                   ; LLB, LMB, RLB, RMB, R, L
                FStP    DWord Ptr [DS:0]
                FStP    DWord Ptr [DS:8]
                FStP    DWord Ptr [DS:4]
                FStP    DWord Ptr [DS:0Ch]

                FLd     DWord Ptr [DS:30h]
                FMul    ST, ST(2)
                FLd     DWord Ptr [DS:30h]
                FMul    ST, ST(2)
                FLd     DWord Ptr [DS:10h]
                FMul    DWord Ptr [DS:34h]
                FLd     DWord Ptr [DS:14h]
                FMul    DWord Ptr [DS:34h]

                FXCh
                FAddP   ST(3), ST
                FAdd

                FLd     DWord Ptr [DS:38h]
                FMul    ST, ST(4)
                FLd     DWord Ptr [DS:38h]
                FMul    ST, ST(4)
                FLd     DWord Ptr [DS:18h]
                FMul    DWord Ptr [DS:3Ch]
                FLd     DWord Ptr [DS:1Ch]
                FMul    DWord Ptr [DS:3Ch]

                FXCh
                FAddP   ST(3), ST
                FAdd
                FXCh    ST(3)
                FStP    DWord Ptr [DS:10h]
                FStP    DWord Ptr [DS:18h]
                FStP    DWord Ptr [DS:14h]
                FStP    DWord Ptr [DS:1Ch]      ; R, L

; For each one, output value += ((band value) - (previous band value)) * Volume

                FLd     DWord Ptr [DS:18h]
                FSub    DWord Ptr [DS:10h]      ; L4, R, L
                FLd     DWord Ptr [DS:1Ch]
                FSub    DWord Ptr [DS:14h]      ; R4, L4, R, L
                FLd     DWord Ptr [DS:10h]
                FSub    DWord Ptr [DS:8]
                FLd     DWord Ptr [DS:14h]
                FSub    DWord Ptr [DS:0Ch]      ; R3, L3, R4, L4, R, L
                FLd     DWord Ptr [DS:8]
                FSub    DWord Ptr [DS:0]
                FLd     DWord Ptr [DS:0Ch]
                FSub    DWord Ptr [DS:4]        ; R2, L2, R3, L3, R4, L4, R, L
                FXCh    ST(5)                   ; L4, L2, R3, L3, R4, R2, R, L
                FMul    DWord Ptr [DS:4Ch]      ; L4V, L2, R3, L3, R4, R2, R, L
                FXCh    ST(4)                   ; R4, L2, R3, L3, L4V, R2, R, L
                FMul    DWord Ptr [DS:4Ch]      ; R4V, L2, R3, L3, L4V, R2, R, L
                FXCh    ST(3)                   ; L3, L2, R3, R4V, L4V, R2, R, L
                FMul    DWord Ptr [DS:48h]      ; L3V, L2, R3, R4V, L4V, R2, R, L
                FXCh    ST(2)                   ; R3, L2, L3V, R4V, L4V, R2, R, L
                FMul    DWord Ptr [DS:48h]      ; R3V, L2, L3V, R4V, L4V, R2, R, L
                FXCh                            ; L2, R3V, L3V, R4V, L4V, R2, R, L
                FMul    DWord Ptr [DS:44h]      ; L2V, R3V, L3V, R4V, L4V, R2, R, L
                FXCh    ST(5)                   ; R2, R3V, L3V, R4V, L4V, L2V, R, L
                FMul    DWord Ptr [DS:44h]      ; R2V, R3V, L3V, R4V, L4V, L2V, R, L
                FXCh    ST(4)                   ; L4V, R3V, L3V, R4V, R2V, L2V, R, L
                FAddP   ST(7), ST               ; R3V, L3V, R4V, R2V, L2V, R, L
                FAddP   ST(5), ST               ; L3V, R4V, R2V, L2V, R, L
                FAddP   ST(3), ST
                FAdd
                FLd     DWord Ptr [DS:0]
                FMul    DWord Ptr [DS:40h]      ; L1V, RV, LV, R, L
                FLd     DWord Ptr [DS:4]        ;
                FMul    DWord Ptr [DS:40h]      ; R1V, L1V, RV, LV, R, L
                FXCh    ST(2)                   ; RV, L1V, R1V, LV, R, L
                FAddP   ST(4), ST               ; L1V, R1V, LV, R, L
                FAddP   ST(4), ST               ; R1V, LV, R, L
                FAddP   ST(2), ST
                FAddP   ST(2), ST

                FIStP   DWord Ptr [SI+4]
                FIStP   DWord Ptr [SI]

                Add     SI, 8
                Dec     CX
                JNZ     OutputFilter1

; Transfer contents out
                Push    CS
                Pop     ES

                Mov     DI, Offset LastFilter
                Xor     SI, SI
                Mov     CX, 32/4

                Rep     MovsD
; Finished output filtering!

                Ret

EndP            M32MixHandler

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