Files
lba1-classic/LIB386/LIB_SAMP/WAVE_A.ASM

3770 lines
84 KiB
NASM

;*──────────────────────────────────────────────────────────────────────────*
; SAMP_A.ASM 386
; (c) Adeline 1993
;*──────────────────────────────────────────────────────────────────────────*
;*--------------------------------------------------------------------------*
include wave.inc
;*--------------------------------------------------------------------------*
MIDPOINT MACRO
IFDEF SAMPLE16BIT
xor eax, eax
ELSE
mov eax, 80808080h
ENDIF
ENDM
;*--------------------------------------------------------------------------*
.386
jumps
.model FLAT, SYSCALL
.CODE
;*--------------------------------------------------------------------------*
PUBLIC driver_start
driver_start dd OFFSET ListFuncs
IFDEF SB16
db 'Sound Blaster 16 (DSP 4.XX)'
ELSEIFDEF SBPRO
db 'Sound Blaster Pro (DSP 3.XX)'
ELSEIFDEF SBLASTER1
db 'Sound Blaster 2 (DSP 2.01+)'
ELSEIFDEF SBLASTER
db 'Sound Blaster (DSP 1.00-2.00)'
ELSEIFDEF MWSS
db 'Microsoft Windows Sound System (AD1848 SoundPort)'
ELSEIFDEF GOLD
db 'Adlib Gold (Yamaha GOLD)'
ELSEIFDEF GUS
db 'Advanced Gravis UltraSound'
ELSEIFDEF PAS16
db 'Media Vision Pro Audio Spectrum 16'
ELSEIFDEF PAS
db 'Media Vision Pro Audio Spectrum/Spectrum Plus'
ENDIF
db ' Wave Driver,', 13, 10
IFDEF SAMPLE16BIT
db '16 bit'
ELSE
db '8 bit'
ENDIF
IFDEF STEREO
db ' Stereo'
ELSE
db ' Mono'
ENDIF
IFDEF SURROUND
db ' Surround'
ENDIF
db ' playback, Version 1.00.', 13, 10
IFDEF GUS
db 'Copyright (C) 1991,1992 Miles Design, Inc.', 0Dh, 0Ah
db 'Copyright (C) 1993,1994 Advanced Gravis Computer '
db 'Technology Ltd. All rights reserved.', 0Dh, 0Ah
db 'Copyright (C) 1992,1993,1994 Forte Technologies.', 0Dh, 0Ah
db 'Copyright (C) 1994 Adeline Software International.', 0Dh, 0Ah
db 'All rights reserved.', 0Dh, 0Ah
db 'UltraSound conversion by Jayeson Lee-Steere.', 0Dh, 0Ah
db 'Adeline Software conversion by Serge Plagnol.', 0Dh, 0Ah
db 'MIDI and Digital sound library by Forte.', 0Dh, 0Ah, 0Ah, 0
ELSE
db 'Copyright (c) Adeline Software International 1994, All Rights Reserved.', 13, 10, 10, 0
ENDIF
ListFuncs dd offset InitCard
dd offset ClearCard
dd offset AskVars
dd offset MixSample
dd offset GiveSampleInfo0
dd offset StopSample
dd offset StopOneSample
dd offset SampleInList
dd offset GetSnapSample
dd offset PauseSample
dd offset ContinueSample
dd offset SaveStateSample
dd offset RestoreStateSample
dd offset GetDMAAddr
dd offset GetBufferSize
dd offset ChangeVolume
dd offset ShiftSamples
dd offset StopOneSampleLong
;*--------------------------------------------------------------------------*
ADDRESS equ 0
FRACT equ 4
LEFT equ 8
C_REPEAT equ 12
INCR equ 14
SON equ 16
HANDLE equ 20
START equ 24
DLENGTH equ 28
VOL_LEFT equ 32
VOL_RIGHT equ 34
INFO0 equ 36
INTERPOL equ 40
LAST_SAMPLE equ 41
;*--------------------------------------------------------------------------*
DSP_VO8S_CMD equ 14h
DSP_VO8_CMD equ 1Ch
DSP_TIME_CMD equ 40h
DSP_RATE_CMD equ 41h
DSP_BSIZE_CMD equ 48h
DSP_VO8H_CMD equ 90h
DSP_VO16S_CMD equ 0B0h
DSP_VO16_CMD equ 0B6h
DSP_VO8S_4_CMD equ 0C0h
DSP_VO8_4_CMD equ 0C6h
DSP_ONSPK_CMD equ 0D1h
DSP_OFFSPK_CMD equ 0D3h
DSP_16MONO_MODE equ 10h
DSP_16STEREO_MODE equ 30h
DSP_8MONO_MODE equ 00h
DSP_8STEREO_MODE equ 20h
RESET_TEST_CODE equ 0AAh
;*--------------------------------------------------------------------------*
ifndef NOIRQ
VOICE_OUT equ 0 ; equ to access the 2 arrays below
AUTO_OUT equ 1
MASK1 equ 2
MASK2 equ 3
ADDX_REG equ 4
COUNT_REG equ 6
MASK_REG equ 8
MODE_REG equ 10
FF_REG equ 12
PAGE_REG equ 14
DMA0 equ $ ; Ports for DMA0
DMA0_VOICE_OUT db 48H
DMA0_AUTO_OUT db 58H
DMA0_MASK1 db 00H
DMA0_MASK2 db 04H
DMA0_ADDX_REG dw 00H
DMA0_COUNT_REG dw 01H
DMA0_MASK_REG dw 0AH
DMA0_MODE_REG dw 0BH
DMA0_FF_REG dw 0CH
DMA0_PAGE_REG dw 87H
DMA1 equ $ ; Ports for DMA1
DMA1_VOICE_OUT db 49H
DMA1_AUTO_OUT db 59H
DMA1_MASK1 db 01H
DMA1_MASK2 db 05H
DMA1_ADDX_REG dw 02H
DMA1_COUNT_REG dw 03H
DMA1_MASK_REG dw 0AH
DMA1_MODE_REG dw 0BH
DMA1_FF_REG dw 0CH
DMA1_PAGE_REG dw 83H
DMA3 equ $ ; Ports for DMA3
DMA3_VOICE_OUT db 4BH
DMA3_AUTO_OUT db 5BH
DMA3_MASK1 db 03H
DMA3_MASK2 db 07H
DMA3_ADDX_REG dw 06H
DMA3_COUNT_REG dw 07H
DMA3_MASK_REG dw 0AH
DMA3_MODE_REG dw 0BH
DMA3_FF_REG dw 0CH
DMA3_PAGE_REG dw 82H
DMA5 equ $ ; Ports for DMA5
DMA5_VOICE_OUT db 49H
DMA5_AUTO_OUT db 59H
DMA5_MASK1 db 01H
DMA5_MASK2 db 05H
DMA5_ADDX_REG dw 0C4H
DMA5_COUNT_REG dw 0C6H
DMA5_MASK_REG dw 0D4H
DMA5_MODE_REG dw 0D6H
DMA5_FF_REG dw 0D8H
DMA5_PAGE_REG dw 08BH
DMA6 equ $ ; Ports for DMA6
DMA6_VOICE_OUT db 4AH
DMA6_AUTO_OUT db 5AH
DMA6_MASK1 db 02H
DMA6_MASK2 db 06H
DMA6_ADDX_REG dw 0C8H
DMA6_COUNT_REG dw 0CAH
DMA6_MASK_REG dw 0D4H
DMA6_MODE_REG dw 0D6H
DMA6_FF_REG dw 0D8H
DMA6_PAGE_REG dw 089H
DMA7 equ $ ; Ports for DMA7
DMA7_VOICE_OUT db 4BH
DMA7_AUTO_OUT db 5BH
DMA7_MASK1 db 03H
DMA7_MASK2 db 07H
DMA7_ADDX_REG dw 0CCH
DMA7_COUNT_REG dw 0CEH
DMA7_MASK_REG dw 0D4H
DMA7_MODE_REG dw 0D6H
DMA7_FF_REG dw 0D8H
DMA7_PAGE_REG dw 08AH
ALIGN 4
TAB_DMA dd offset DMA0
dd offset DMA1
dd 0
dd offset DMA3
dd 0
dd offset DMA5
dd offset DMA6
dd offset DMA7
endif
;*--------------------------------------------------------------------------*
CurrentList db STRUCT_SIZE*LIST_SIZE+4 dup (?)
SonList db STRUCT_SIZE*LIST_SIZE+4 dup (?)
BackCurrentList db STRUCT_SIZE*LIST_SIZE+4 dup (?)
BackSonList db STRUCT_SIZE*LIST_SIZE+4 dup (?)
SnapList db SNAP_SIZE*LIST_SIZE dup (?)
IRQ_mask db ?
FlagPause db 0
WaveBase db 'WaveBase',0
WaveIRQ db 'WaveIRQ',0
WaveDMA db 'WaveDMA',0
WaveRate db 'WaveRate'
Empty db 0
ifdef SBPRO
OkIRQ db 0
Filter db ?
endif
ifdef GOLD
Mixer_13 db ?
Mixer_14 db ?
Gold_IRQ db 3, 4, 5, 7, 10, 11, 12, 15
endif
ifdef SB16
SB16_IRQ db 2, 5, 7, 10
endif
EVEN
ifdef MWSS
MWSSFreq dw 11025, 3, 16000, 2, 18900, 5, 22050, 7
dw 27429, 4, 32000, 6, 33075, 0dh, 37800, 9
dw 44100, 0Bh
MWSSIrq db 0, 0, 010000b, 0, 0, 0, 0, 001000b, 0, 010000b
db 011000b, 100000b, 0, 0, 0, 0
MWSSDma db 01b, 10b, 0, 11b, 0, 0, 0, 0
endif
Critical dw ?
DoUpdate dw ?
Old_RIRQ_Seg dw ?
Old_PIRQ_Sel dw ?
Old_18_Sel dw ?
Old_RIRQ_Off dw ?
ALIGN 4
Old_PIRQ_Off dd ?
Old_18_Off dd ?
ifdef GOLD
ListNames dd offset WaveBase
dd offset Empty
elseifdef SB16
ListNames dd offset WaveBase
dd offset WaveRate
dd offset Empty
elseifdef GUS
ListNames dd offset WaveRate
dd offset Empty
elseifdef PAS
ListNames dd offset WaveRate
dd offset Empty
else
ListNames dd offset WaveBase
dd offset WaveRate
dd offset WaveIRQ
dd offset WaveDMA
dd offset Empty
endif
public Nolanguage PlayRate
ListVars equ $
ifdef GOLD
BASE_ADDR dd 388h ; By default 388h
PlayRate dd 22000 ; By default 22 Khz
IRQ_number dd ? ; no default (read card)
DMA_number dd ? ; no default (read card)
elseifdef SBLASTER
BASE_ADDR dd 220h ; By default 220h
PlayRate dd 22000 ; By default 22 Khz
IRQ_number dd 5 ; By default 5
DMA_number dd 1 ; By default 1
elseifdef MWSS
BASE_ADDR dd 540h ; By default 540h
PlayRate dd 22000 ; By default 22 Khz
IRQ_number dd 9 ; By default 9
DMA_number dd 1 ; By default 1
elseifdef GUS
PlayRate dd 22000 ; By default 22 Khz
elseifdef PAS
PlayRate dd 22000 ; By default 22 Khz
IRQ_number dd 0 ; no default
DMA_number dd 0 ; no default
else
BASE_ADDR dd 0 ; no default
PlayRate dd 22000 ; By default 22 Khz
IRQ_number dd 0 ; no default
DMA_number dd 0 ; no default
endif
INT_number dd 0Dh ; By default 0Dh
public Nolanguage BufferHalf
BufferHalf dd ?
follow dd -1
backfollow dd -1
ifndef NOIRQ
DMA dd offset DMA1 ; By default DMA1
endif
weirdcount dd ?
backweirdcount dd ?
TheVolumeR dd ?
TheVolumeL dd ?
save_1 dd ?
save_2 dd ?
save_3 dd ?
save_4 dd ?
public Nolanguage BUFFER_DMA
public Nolanguage CURRENT_BUFFER
ifdef RAM_CARD
BUFFER_DMA dd ? ; adress of the buffer
R_BUFFER_CARD dd ? ; adress of the buffer on the card for Right channel
MID_R_BUFFER_CARD dd ? ; adress of the mid buffer for Right channel
CURRENT_R_BUFFER_CARD dd ? ; current half for Right channel
L_BUFFER_CARD dd ? ; adress of the buffer on the card for Left channel
MID_L_BUFFER_CARD dd ? ; adress of the mid buffer for Left channel
CURRENT_L_BUFFER_CARD dd ? ; current half for Left channel
else
BUFFER_DMA dd ? ; adress of the buffer
MID_BUFFER_DMA dd ? ; adress of the mid buffer
CURRENT_BUFFER dd ? ; current half
endif
ifdef INTERRRUPT
DMA_COUNT dd ?
DMA_PTR dd ?
endif
;----------------------------------------------------------------------------
IFDEF PAS
MV_filter dd ?
MV_xchannel dd ?
DPMI_real_int LABEL BYTE ;DPMI real-mode interrupt structure
int_DI dw ? ;*** MUST REMAIN CONTIGUOUS ***
dw 0
int_SI dw ?
dw 0
int_BP dw ?
dw 0
dd 0
int_BX dw ?
dw 0
int_DX dw ?
dw 0
int_CX dw ?
dw 0
int_AX dw ?
dw 0
int_flags dw ?
int_ES dw ?
int_DS dw ?
dw 0
dw 0
dw 0
dw 0
dw 0
dw 0
ENDIF
;*--------------------------------------------------------------------------*
Redirector PROC
int 18h
iretd
Redirector ENDP
;*--------------------------------------------------------------------------*
setalc MACRO
db 0D6h
ENDM
lve MACRO Reg, Exp
lea Reg, [Exp]
ENDM
;*--------------------------------------------------------------------------*
GET_REAL_VECT MACRO
mov ax, 0200h
int 31h
ENDM
SET_REAL_VECT MACRO
mov ax, 0201h
int 31h
ENDM
GET_PROT_VECT MACRO
mov ax, 0204h
int 31h
ENDM
SET_PROT_VECT MACRO
mov ax, 0205h
int 31h
ENDM
CRIT_SECT MACRO ; Enter Critical Section ;-)
mov word ptr[Critical], 1 ; tell the IRQ not to update the buffer
; we'll take care of it if nescessary O:-)
ENDM
END_CRIT_SECT MACRO ; Exit Critical Section O:-)
local NoUpdate ; Update buffer if necessary
; Dealing with the critical section flags................
; DO NOT TOUCH !!!!
mov word ptr[Critical], 0 ; exit crit. sect.
; this way DoUpdate can't change to 1 anymore
cmp word ptr[DoUpdate], 0 ; IRQ happened ?
je NoUpdate ; if DopUpdate change to 0 now, we are in deep
; shit anyway because we missed one round!
; The program won't crash but we'll ear the old
; content of half a buffer and also miss half a buffer
; of new data... :-(
mov word ptr[Critical], 1 ; yes, crit. again, so we don't update twice
; because UpdateBuffer is not reentrant
; and we don't want to take a chance on crashing!
pushad ; if DoUpdate change to 1 HERE
; it means again that we missed one round!
; So we play the buffer we are updating! (funny noise :-( )
; and then will ear half buffer of old data!
call UpdateBuffer ; do the update
popad
mov word ptr[Critical], 0 ; exit crit. sect
; this way DoUpdate can't change to 1 anymore
mov word ptr[DoUpdate], 0 ; Update done, so DoUpdate = 0
NoUpDate:
; ALL THOSE NASTY THING SHOULD NOT HAPPEN :-) !!!!
; BECAUSE IT WOULD MEAN THAT THE UPDATE OF THE BUFFER
; TAKES MORE THAN 46000 microsec!
; (at 33 Mhz one cycle = .03 microsec so 4600 microsec = 1.5 million cycle)
ENDM
;*--------------------------------------------------------------------------*
GetDMAAddr PROC USES EBX
xor eax, eax
ifndef NOIRQ
mov ebx, dword ptr[DMA]
cli
mov dx, word ptr[ebx + PAGE_REG]
in al, dx
shl eax, 16
mov dx, word ptr[ebx + FF_REG]
out dx, al ; Flip-Flop
mov dx, word ptr[ebx + ADDX_REG] ; to get offset
in al, dx
mov ah, al
in al, dx
sti
xchg al, ah
cmp word ptr[DMA_number], 3
jbe noadjust
lve eax, eax*2
noadjust:
endif
ret
GetDMAAddr ENDP
;*--------------------------------------------------------------------------*
ifndef NOIRQ
NewIRQ PROC
pushad
push ds
push es
cld ; DAMN IT !! :-o
local_DS equ $+2
mov ax, 1234h
mov ds, ax ; restore DS
mov es, ax ; and ES !!!
call AckIrq
pushf
ifdef SINGLE_DMA
jc notransfert
call BlockTransfert
; call Ackirq ; security
notransfert:
endif
mov al, 20h ; allows for new int
cmp byte ptr[IRQ_number], 7
jbe short NoSecondCtrl
out 0A0h, al
NoSecondCtrl: out 20h, al
popf
jc short FinIRQ ; not a DMA IRQ
mov eax, dword ptr[BufferHalf]
xor al, 4 ; switch half
mov byte ptr[BufferHalf], al
ifdef RAM_CARD
mov eax, dword ptr[R_BUFFER_CARD+eax]; get current card buffer address
mov dword ptr[CURRENT_R_BUFFER_CARD], eax; update CURRENT_BUFFER_CARD
else
mov eax, dword ptr[BUFFER_DMA+eax] ; get current buffer address
mov dword ptr[CURRENT_BUFFER], eax ; update CURRENT_BUFFER
endif
mov word ptr[DoUpdate], 1 ; Time to do the update
cmp word ptr[Critical], 0 ; crit. sect ?
jne FinIRQ ; yes, don't update yet!
mov word ptr[Critical], 1 ; just to make jure it case the interrupt
call UpdateBuffer ; happen again before its finished
mov word ptr[Critical], 0
mov word ptr[DoUpdate], 0 ; Update done
FinIRQ:
pop es
pop ds
popad
iretd
NewIRQ ENDP
endif
;*--------------------------------------------------------------------------*
ifdef GUS
PUBLIC Nolanguage UpdateBuffer
PUBLIC Nolanguage DoUpdate
PUBLIC Nolanguage Critical
endif
;*--------------------------------------------------------------------------*
UpdateBuffer PROC
ifdef GUS
push es
pushf
cld
mov ax, ds
mov es, ax
endif
mov eax, BUFFER_SIZE
ifdef RAM_CARD
mov edi, dword ptr[BUFFER_DMA] ; Buffer
else
mov edi, dword ptr[CURRENT_BUFFER] ; Buffer
endif
cmp byte ptr[FlagPause], 1
je short dopause
lea ebx, CurrentList ; Point to List of samples
mov esi, dword ptr[ebx] ; Current Source
or esi, esi ; if 0 then empty list
jnz process_1st
dopause:
mov ecx, (BUFFER_SIZE * SSIZE) / 4
MIDPOINT
rep stosd
mov al, byte ptr[FlagPause]
and al, 1
mov byte ptr[FlagPause], al
ifdef GUS
popf
pop es
endif
ret
exit:
mov al, byte ptr[FlagPause]
dec al
js reallyexit
ifdef RAM_CARD
mov edi, dword ptr[BUFFER_DMA] ; Buffer
else
mov edi, dword ptr[CURRENT_BUFFER] ; Buffer
endif
mov esi, ( BUFFER_SIZE * SSIZE ) / 4
bsr cx, si
dec si ; no need to fade first/last sample
; since it will be multiplied by 1
dec al
jnz short fadeout
mov ebx, 1 ; skip 0
ifdef SAMPLE16BIT
loopfadein: mov edx, dword ptr[edi]
movsx eax, dx
imul eax, ebx
sar eax, cl
sar edx, 16
imul edx, ebx
sar edx, cl
shl edx, 16
mov dx, ax
mov dword ptr[edi], edx
add edi, 4
inc bx
dec si
jnz short loopfadein
else
loopfadein: mov edx, dword ptr[edi]
xor edx, 80808080h ; convert to signed
REPT 2
movsx eax, dl
imul eax, ebx
sar eax, cl
mov dl, al
movsx eax, dh
imul eax, ebx
sar eax, cl
mov dh, al
rol edx, 16
ENDM
xor edx, 80808080h ; back to unsigned
mov dword ptr[edi], edx
add edi, 4
inc bx
dec si
jnz short loopfadein
endif
xor al, al
jmp short endfade
fadeout:
add edi, 4 ; skip first
ifdef SAMPLE16BIT
loopfadeout: mov edx, dword ptr[edi]
movsx eax, dx
imul eax, esi
sar eax, cl
sar edx, 16
imul edx, esi
sar edx, cl
shl edx, 16
mov dx, ax
mov dword ptr[edi], edx
add edi, 4
dec si
jnz short loopfadeout
else
loopfadeout: mov edx, dword ptr[edi]
xor edx, 80808080h ; convert to signed
REPT 2
movsx eax, dl
imul eax, esi
sar eax, cl
mov dl, al
movsx eax, dh
imul eax, esi
sar eax, cl
mov dh, al
rol edx, 16
ENDM
xor edx, 80808080h ; back to unsigned
mov dword ptr[edi], edx
add edi, 4
dec si
jnz short loopfadeout
endif
mov al, 1
endfade:
mov byte ptr[FlagPause], al
reallyexit:
ifdef GUS
popf
pop es
endif
ret
FinishFill0:
or ax, ax ; still some room in the buffer?
jz Finish2
process_1st:
mov cx, ax
shl eax, 16
mov ax, cx ; eax = BUFFER_SIZE:BUFFER_SIZE
mov dx, word ptr[ebx+FRACT] ; fractionnal Source
mov bp, word ptr[ebx+INCR] ; fractionnal inc
mov ecx, dword ptr[ebx+LEFT] ; length left
cmp ecx, 0FFFFh ; length left to fill after sample
ja Longer0 ; 64K or +, then more than the buffer
sub ax, cx
jae short NotLonger0 ; some left?
Longer0:
shr eax, 16
mov ecx, eax ; length = buffer_size
sub dword ptr[ebx+LEFT], ecx ; reduce length left
mov word ptr[save_4], 0 ; no room left
jmp short StartMix0
NotLonger0:
inc ax ; length + 1 (in case left = 0)
mov word ptr[save_4], ax
StartMix0:
shl edx, 16
or ecx, edx ; hecx = FRACT
shl ebp, 16 ; hebp = INCR
ifdef SAMPLE16BIT
mov edx, dword ptr[ebx+VOL_LEFT] ; read left & right volume
ifdef STEREO
cmp byte ptr[ebx+INTERPOL], 0
je nofilter
mov dword ptr[save_3], ebx
movsx eax, dx
mov [TheVolumeL], eax
sar edx, 16
mov [TheVolumeR], edx
shr ebp, 16 ; BP = fract inc
mov edx, ecx
shr edx, 16 ; DX = fract
rol ecx, 8
mov cl, [ebx+LAST_SAMPLE]
ror ecx, 8
jmp short next0
start0: rol ecx, 8
mov cl, [esi]
inc esi
ror ecx, 8
next0: mov eax, ecx
mov al, [esi] ; read data
rol eax, 8
xor ax, 8080h ; 8 bit signed
movsx ebx, al
movsx eax, ah ; sign extension to 32 bit
not dx
inc edx
imul ebx, edx
dec edx
not dx
imul eax, edx
add ebx, eax
mov eax, ebx
imul ebx, [TheVolumeR] ; Right
imul eax, [TheVolumeL] ; Left
sar eax, 16
mov bx, ax
mov [edi], ebx ; store buffer content
add edi, 4 ; next location
add dx, bp ; update fractional part of address
dec cx ; length-1, doesn't touch C but set Z ;-)
ja short next0 ; if (not C) and (not Z) next
jnz short start0 ; if some left, read a new one
mov ebx, dword ptr[save_3]
pushf
rol ecx, 8
mov [ebx+LAST_SAMPLE], cl
shl edx, 16
mov ecx, edx
inc esi
popf
jmp short end16
nofilter:
mov dword ptr[save_3], ebx
start01: lodsb ; read new data
xor al, 80h ; 8 bit signed
movsx eax, al ; sign extension to 32 bit
mov ebx, eax ; copy into ebx
imul ax, dx ; ax = left
imul ebx, edx
mov bx, ax
next01: mov dword ptr[edi], ebx ; write data
add edi, 4 ; next location
add ecx, ebp ; update fractional part of address
dec cx ; length-1, doesn't touch C but set Z ;-)
ja short next01 ; if (not C) and (not Z) next
jnz short start01 ; if some left, read a new one
mov ebx, dword ptr[save_3]
end16:
else
start0: lodsb ; read new data
xor al, 80h ; 8 bit signed
movsx ax, al ; sign extension to 16 bit
imul ax, dx ; ax = "volumed" sample
next0: mov word ptr[edi], ax ; write data
add edi, 2 ; next location
add ecx, ebp ; update fractional part of address
dec cx ; length-1, doesn't touch C but set Z ;-)
ja short next0 ; if (not C) and (not Z) next
jnz short start0 ; if some left, read a new one
endif
else
ifdef STEREO
mov dl, byte ptr[ebx+VOL_LEFT]
or dl, dl
jz short middle0
dec dl
jz short left0
mov al, 80h ; "0" -> left
r_start0: mov ah, byte ptr[esi] ; read new data -> right
inc esi
r_next0: mov word ptr[edi], ax ; write data
add edi, 2 ; next location
add ecx, ebp ; update fractional part of address
dec cx ; length-1, doesn't touch C but set Z ;-)
ja short r_next0 ; if (not C) and (not Z) next
jnz short r_start0 ; if some left, read a new one
jmp short end0
left0:
mov ah, 80h ; "0" -> right
l_start0: lodsb ; read new data -> left
l_next0: mov word ptr[edi], ax ; write data
add edi, 2 ; next location
add ecx, ebp ; update fractional part of address
dec cx ; length-1, doesn't touch C but set Z ;-)
ja short l_next0 ; if (not C) and (not Z) next
jnz short l_start0 ; if some left, read a new one
jmp short end0
middle0:
m_start0: lodsb ; read new data -> left
mov ah, al ; data -> right
m_next0: mov word ptr[edi], ax ; write data
add edi, 2 ; next location
add ecx, ebp ; update fractional part of address
dec cx ; length-1, doesn't touch C but set Z ;-)
ja short m_next0 ; if (not C) and (not Z) next
jnz short m_start0 ; if some left, read a new one
end0:
else
start0: lodsb ; read new data
next0: mov byte ptr[edi], al ; write data
inc edi ; next location
add ecx, ebp ; update fractional part of address
dec cx ; length-1, doesn't touch C but set Z ;-)
ja short next0 ; if (not C) and (not Z) next
jnz short start0 ; if some left, read a new one
endif
endif
jc noadjust0 ; was a new data going to be read?
dec esi ; no, last data will be read again
noadjust0:
mov ax, word ptr[save_4] ; left to copy
or ax, ax
jz Finish ; 0 normal end
dec ax ; readjust size
dec word ptr[ebx+C_REPEAT] ; repeat again?
jnz Reset0 ; yes, then reset
mov edx, dword ptr[ebx+SON] ; no, got a son?
or edx, edx
js short NoSon0 ; no, remove the sample
lea esi, SonList ; yes, then find it
KeepLooking0:
cmp dword ptr[esi], 0 ; the end ?
je short NoSon0 ; yes, then no son
cmp edx, dword ptr[esi+HANDLE] ; this one?
je short FoundSon0 ; yes, found!
add esi, STRUCT_SIZE ; no, keep looking
jmp short KeepLooking0
NoSon0:
or ax, ax
jz noclear
xor ecx, ecx
mov cx, ax ; clear rest of the buffer
MIDPOINT
IFDEF SCHAR
mov edx, ecx
and ecx, 3 ; up to 3 by byte
rep stosb
mov ecx, edx
shr ecx, 2 ; the rest by dword
ELSEIFDEF SUWORD
shr ecx, 1
jnc short NoAdjustByOne
stosw
NoAdjustByOne:
ENDIF
rep stosd
noclear:
mov esi, ebx ; point where it is
mov edi, ebx ; idem
add esi, STRUCT_SIZE ; source one further
LoopRemove0: cmp dword ptr[esi], 0 ; end ?
je short EndRemove0 ; yes, exit
mov ecx, STRUCT_SIZE / 4 ; trasnfert one struct
rep movsd ; transfer
jmp short LoopRemove0
EndRemove0:
mov dword ptr[edi], 0 ; write 0 to mark the end
jmp NextSample
FoundSon0:
mov ebp, esi ; save esi
mov edx, edi ; save edi
mov edi, ebx ; transfert at the location of the father
mov ecx, STRUCT_SIZE / 4 ; count in dword
rep movsd ; transfert
mov esi, ebp ; remove son from SonList
mov edi, ebp ; so, point to it
add esi, STRUCT_SIZE ; source one further
LoopSon0: cmp dword ptr[esi], 0
je short EndSon0
mov ecx, STRUCT_SIZE / 4
rep movsd ; transfer while not 0
jmp short LoopSon0
EndSon0:
mov dword ptr[edi], 0 ; write 0 to mark the end
mov edi, edx ; restore edi in the buffer
mov esi, dword ptr[ebx+START] ; restore source, no need to write it
jmp FinishFill0
Reset0:
mov esi, dword ptr[ebx+START] ; restore source, no need to write it
mov ebp, dword ptr[ebx+DLENGTH] ; restore length
mov dword ptr[ebx+LEFT], ebp
mov word ptr[ebx+FRACT], 0
jmp FinishFill0
NextSample:
mov esi, dword ptr[ebx] ; Current Source
or esi, esi ; if 0 then end of the list
jz exit
ifdef RAM_CARD
mov edi, dword ptr[BUFFER_DMA] ; Buffer
else
mov edi, dword ptr[CURRENT_BUFFER] ; Buffer
endif
mov ax, BUFFER_SIZE
FinishFill:
or ax, ax ; still some room in the buffer?
jz Finish2
mov cx, ax
shl eax, 16
mov ax, cx ; eax = BUFFER_SIZE:BUFFER_SIZE
mov dx, word ptr[ebx+FRACT] ; fractionnal Source
mov bp, word ptr[ebx+INCR] ; fractionnal inc
mov ecx, dword ptr[ebx+LEFT] ; length left
cmp ecx, 0FFFFh ; length left to fill after sample
ja Longer ; 64K or +, then more than the buffer
sub ax, cx
jae short NotLonger ; some left?
Longer:
shr eax, 16 ; no, restore buffer_size in ax
mov ecx, eax ; length = buffer_size
sub dword ptr[ebx+LEFT], ecx ; reduce length left
mov word ptr[save_4], 0 ; no room left
jmp short startMix00
NotLonger:
inc ax ; length + 1 (in case left = 0)
mov word ptr[save_4], ax
StartMix00:
shl edx, 16
or ecx, edx ; hecx = FRACT
shl ebp, 16 ; hebp = INCR
ifdef SAMPLE16BIT
mov edx, dword ptr[ebx+VOL_LEFT]
ifdef STEREO
cmp byte ptr[ebx+INTERPOL], 0
je nofilter00
mov dword ptr[save_3], ebx
movsx eax, dx
mov [TheVolumeL], eax
sar edx, 16
mov [TheVolumeR], edx
shr ebp, 16 ; BP = fract inc
mov edx, ecx
shr edx, 16 ; DX = fract
rol ecx, 8
mov cl, [ebx+LAST_SAMPLE]
ror ecx, 8
jmp short next00
start00: rol ecx, 8
mov cl, [esi]
inc esi
ror ecx, 8
next00: mov eax, ecx
mov al, [esi] ; read data
rol eax, 8
xor ax, 8080h ; 8 bit signed
movsx ebx, al
movsx eax, ah ; sign extension to 32 bit
not dx
inc edx
imul ebx, edx
dec edx
not dx
imul eax, edx
add ebx, eax
mov eax, ebx
imul ebx, [TheVolumeR] ; Right
imul eax, [TheVolumeL] ; Left
sar eax, 16
mov bx, ax
add [edi], ebx ; store buffer content
add edi, 4 ; next location
add dx, bp ; update fractional part of address
dec cx ; length-1, doesn't touch C but set Z ;-)
ja short next00 ; if (not C) and (not Z) next
jnz short start00 ; if some left, read a new one
mov ebx, dword ptr[save_3]
pushf
rol ecx, 8
mov [ebx+LAST_SAMPLE], cl
shl edx, 16
mov ecx, edx
inc esi
popf
jmp short end016
nofilter00:
mov dword ptr[save_3], ebx
start001: lodsb ; read new data
xor al, 80h ; 8 bit signed
movsx eax, al ; sign extension to 32 bit
mov ebx, eax ; copy into ebx
imul ax, dx ; ax = left
imul ebx, edx
mov bx, ax
next001: add dword ptr[edi], ebx ; write data
add edi, 4 ; next location
add ecx, ebp ; update fractional part of address
dec cx ; length-1, doesn't touch C but set Z ;-)
ja short next001 ; if (not C) and (not Z) next
jnz short start001 ; if some left, read a new one
mov ebx, dword ptr[save_3]
end016:
else
start00: lodsb ; read new data
xor al, 80h ; 8 bit signed
movsx ax, al ; sign extension to 16 bit
imul ax, dx ; ax = "volumed" sample
next00: add word ptr[edi], ax ; add with buffer content
add edi, 2 ; next location
add ecx, ebp ; update fractional part of address
dec cx ; length-1, doesn't touch C but set Z ;-)
ja short next00 ; if (not C) and (not Z) next
jnz short start00 ; if some left, read a new one
endif
else
ifdef STEREO
mov dl, byte ptr[ebx+VOL_LEFT]
or dl, dl
jz short middle00
dec dl
jz short left00
inc edi ; go right
r_start00: lodsb ; read new data
mov ah, al ; save it in ah
r_next00: add al, byte ptr[edi] ; add with buffer content
rcr al, 1 ; average
mov byte ptr[edi], al ; write result back
add edi, 2 ; next location
mov al, ah ; restore data
add ecx, ebp ; update fractional part of address
dec cx ; length-1, doesn't touch C but set Z ;-)
ja short r_next00 ; if (not C) and (not Z) next
jnz short r_start00 ; if some left, read a new one
dec edi ; go back left
jmp short end00
left00:
l_start00: lodsb ; read new data
mov ah, al ; save it in ah
l_next00: add al, byte ptr[edi] ; add with buffer content
rcr al, 1 ; average
mov byte ptr[edi], al ; write result back
add edi, 2 ; next location
mov al, ah ; restore data
add ecx, ebp ; update fractional part of address
dec cx ; length-1, doesn't touch C but set Z ;-)
ja short l_next00 ; if (not C) and (not Z) next
jnz short l_start00 ; if some left, read a new one
jmp short end00
middle00:
m_start00: lodsb ; read new data
m_next00: mov dx, word ptr[edi] ; read buffer, left & right
add dl, al ; average with left
rcr dl, 1
add dh, al ; average with right
rcr dh, 1
mov word ptr[edi], dx ; write result back
add edi, 2 ; next location
add ecx, ebp ; update fractional part of address
dec cx ; length-1, doesn't touch C but set Z ;-)
ja short m_next00 ; if (not C) and (not Z) next
jnz short m_start00 ; if some left, read a new one
end00:
else
start00: lodsb ; read new data
mov ah, al ; save it in ah
next00: add al, byte ptr[edi] ; add with buffer content
rcr al, 1 ; average
adc al, 0
mov byte ptr[edi], al ; write result back
inc edi ; next location
mov al, ah ; restore data
add ecx, ebp ; update fractional part of address
dec cx ; length-1, doesn't touch C but set Z ;-)
ja short next00 ; if (not C) and (not Z) next
jnz short start00 ; if some left, read a new one
endif
endif
jc noadjust ; was a new data going to be read?
dec esi ; no, last data will be read again
noadjust:
mov ax, word ptr[save_4] ; left to copy
or ax, ax
jz short Finish ; 0 normal end
dec ax ; readjust size
dec word ptr[ebx+C_REPEAT] ; repeat again?
jnz short Reset ; yes, then reset
mov edx, dword ptr[ebx+SON] ; no, got a son?
or edx, edx
js short NoSon ; no, remove the sample
lea esi, SonList ; yes, then find it
KeepLooking:
cmp dword ptr[esi], 0 ; the end ?
je short NoSon ; yes, then no son
cmp edx, dword ptr[esi+HANDLE] ; this one?
je short FoundSon ; yes, found!
add esi, STRUCT_SIZE ; no, keep looking
jmp short KeepLooking
NoSon: ; remove it
mov esi, ebx ; point where it is
mov edi, ebx ; idem
add esi, STRUCT_SIZE ; source one further
LoopRemove: cmp dword ptr[esi], 0 ; end ?
je short EndRemove ; yes, exit
mov ecx, STRUCT_SIZE / 4 ; trasnfert one struct
rep movsd ; transfer
jmp short LoopRemove
EndRemove:
mov dword ptr[edi], 0 ; write 0 to mark the end
jmp NextSample
FoundSon:
mov ebp, esi ; save esi
mov edx, edi ; save edi
mov edi, ebx ; transfert at the location of the father
mov ecx, STRUCT_SIZE / 4 ; count in dword
rep movsd ; transfert
mov esi, ebp ; remove son from SonList
mov edi, ebp ; so, point to it
add esi, STRUCT_SIZE ; source one further
LoopSon: cmp dword ptr[esi], 0
je short EndSon
mov ecx, STRUCT_SIZE / 4
rep movsd ; transfer while not 0
jmp short LoopSon
EndSon:
mov dword ptr[edi], 0 ; write 0 to mark the end
mov edi, edx ; restore edi in the buffer
mov esi, dword ptr[ebx+START] ; restore source, no need to write it
jmp FinishFill
Finish:
shr ecx, 16
mov word ptr[ebx+FRACT], cx ; save fractional part
Finish2: mov dword ptr[ebx], esi ; save current address
add ebx, STRUCT_SIZE ; point to next sample
jmp NextSample
Reset:
mov esi, dword ptr[ebx+START] ; restore source, no need to write it
mov ebp, dword ptr[ebx+DLENGTH] ; restore length
mov dword ptr[ebx+LEFT], ebp
mov word ptr[ebx+FRACT], 0
jmp FinishFill
UpdateBuffer ENDP
;*--------------------------------------------------------------------------*
StopSample PROC
CRIT_SECT
xor eax, eax
mov dword ptr[CurrentList], eax
mov dword ptr[SonList], eax
mov byte ptr[FlagPause], al
dec eax
mov dword ptr[follow], eax ; -1
mov dword ptr[weirdcount], 10000h
END_CRIT_SECT
ret
StopSample ENDP
;*--------------------------------------------------------------------------*
StopOneSample PROC USES EBX ESI EDI,\
thehandle:DWORD
push -1 ; end of recursion
mov eax, thehandle
lea edx, CurrentList
mov ebx, edx
CRIT_SECT
keeplooking: cmp dword ptr[ebx], 0
je short exit
cmp ax, word ptr[ebx+HANDLE]
je short found
add ebx, STRUCT_SIZE
jmp short keeplooking
exit:
lea ebx, SonList
cmp edx, ebx
mov edx, ebx
jne short keeplooking
pop eax ; get "son"
or eax, eax
jns short keeplooking ; less than #2 billions samples !
END_CRIT_SECT
ret
found:
mov ecx, dword ptr[ebx+SON]
or ecx, ecx
js short noson
push ecx ; "son" to be removed
noson:
mov esi, ebx
mov edi, ebx
add esi, STRUCT_SIZE
LoopRemove: cmp dword ptr[esi], 0
je short EndRemove
mov ecx, STRUCT_SIZE / 4
rep movsd
jmp short LoopRemove
EndRemove:
mov dword ptr[edi], 0
jmp short keeplooking
StopOneSample ENDP
;----------------------------------------------------------------------------
ShiftSamples PROC USES ESI EDI EBX,\
DestAddr:DWORD, SrcAddr:DWORD, SizeByte:DWORD
lea edx, CurrentList
mov esi, SrcAddr ; Source
mov eax, esi ; save Source for comparison
mov edi, DestAddr ; Destination
mov ecx, SizeByte ; number of bytes to move
mov bl, cl ; compute counters
shr ecx, 2
and bl, 3
CRIT_SECT
rep movsd ; move the data
mov cl, bl
rep movsb
sub edi, esi ; shift (delta addr)
mov ebx, edx
keeplooking: cmp dword ptr[ebx], 0
je short exit
cmp eax, [ebx+START]
ja short notfound
add [ebx+START], edi
add [ebx], edi
notfound:
add ebx, STRUCT_SIZE
jmp short keeplooking
exit:
lea ebx, SonList
cmp edx, ebx
mov edx, ebx
jne short keeplooking
END_CRIT_SECT
ret
ShiftSamples ENDP
;----------------------------------------------------------------------------
StopOneSampleLong PROC USES ESI EDI,\
LongHandle:DWORD
mov eax, LongHandle
CRIT_SECT
call SearchLongHandle
or edx, edx
jz short notfound
mov esi, edx
mov edi, edx
add esi, STRUCT_SIZE
LoopRemove: cmp dword ptr[esi], 0
je short EndRemove
mov ecx, STRUCT_SIZE / 4
rep movsd
jmp short LoopRemove
EndRemove:
mov dword ptr[edi], 0
notfound:
END_CRIT_SECT
ret
StopOneSampleLong ENDP
;*--------------------------------------------------------------------------*
SampleInList PROC USES EBX,\
thehandle:DWORD
CRIT_SECT
mov edx, thehandle
mov eax, 1 ; True
lea ecx, CurrentList
mov ebx, ecx
keeplooking: cmp dword ptr[ebx], 0
je short exit
cmp dx, word ptr[ebx+HANDLE]
je short found
add ebx, STRUCT_SIZE
jmp short keeplooking
exit:
lea ebx, SonList
cmp ecx, ebx
mov ecx, ebx
jne keeplooking
xor eax, eax ; False
found:
END_CRIT_SECT
ret
SampleInList ENDP
;*--------------------------------------------------------------------------*
SearchLongHandle PROC
lea edx, CurrentList
lea ecx, SonList
keeplooking: cmp dword ptr[edx], 0
je short exit
cmp eax, dword ptr[edx+HANDLE]
je short found
add edx, STRUCT_SIZE
jmp short keeplooking
exit:
cmp edx, ecx
mov edx, ecx
jne keeplooking
xor edx, edx
found:
ret
SearchLongHandle ENDP
;*--------------------------------------------------------------------------*
ChangeVolume PROC \
LongHandle:DWORD, volleft:DWORD, volright:DWORD
ifdef STEREO
ifdef SAMPLE16BIT
mov eax, LongHandle
CRIT_SECT
call SearchLongHandle
or edx, edx
jz short notfound
mov eax, volleft
shr eax, SHIFT_SAMPLE - 1 ; Preshift according to number of channels
mov word ptr[edx+VOL_LEFT], ax
mov eax, volright
shr eax, SHIFT_SAMPLE - 1 ; Preshift according to number of channels
ifdef SURROUND
neg eax
endif
mov word ptr[edx+VOL_RIGHT], ax
notfound:
END_CRIT_SECT
else
mov eax, LongHandle
CRIT_SECT
call SearchLongHandle
or edx, edx
jz short notfound
push edi
mov edi, edx
mov cx, word ptr[volleft]
or cx, cx
jnz short okleft
mov cx, 2 ; if volleft = 0 then right
jmp short storepos
okleft: mov ax, word ptr[volright]
shl ax, 7 ; * 128
xor dx, dx
div cx
mov cx, 2 ; right
cmp ax, 74 ; .577 (= tan 30) * 128
jb short storepos
dec cx ; left
cmp ax, 222 ; 1.732 (= tan 60) * 128
jae short storepos
dec cx ; middle
storepos: mov word ptr[edi+VOL_LEFT], cx ; Store position (0:middle, 1:left, 2:right)
pop edi
notfound:
END_CRIT_SECT
endif
else
ifdef SAMPLE16BIT
mov eax, LongHandle
CRIT_SECT
call SearchLongHandle
or edx, edx
jz short notfound
push edi
push ebx
mov edi, edx
mov eax, volleft
imul eax, eax
mov ecx, volright
imul ecx, ecx
add eax, ecx
call sqr2
shr eax, SHIFT_SAMPLE - 1 ; Preshift according to number of channels
mov word ptr[edi+VOL_LEFT], ax ; VOL_LEFT = sqr(volleft^2 + volright^2)
pop ebx
pop esi
notfound:
END_CRIT_SECT
endif
endif
ret
ChangeVolume ENDP
ifdef SAMPLE16BIT
ifndef STEREO
;*--------------------------------------------------------------------------*
; EAX = Sqr(EAX)
Sqr2 PROC
cmp eax, 3 ; if eax <= 3 then
jbe short asqr_0_1 ; square root is 0 or 1
xor edx, edx ; clear edx
mov ebx, eax ; copy eax into ebx so that
; edx:ebx are used "like" a 64 bit
; register
bsr eax, ebx ; position of last 1 of ebx in eax
mov cl, 33 ; compute how many left shift
sub cl, al ; are needed in order to have the
and cl, 11111110b ; most significant 2 bit pair at the
; leftmost position of edx
shld edx, ebx, cl ; shift edx:ebx by the number
shl ebx, cl ; computed above
mov ecx, eax ; compute in ecx how many pairs of
shr ecx, 1 ; 2 bit are left to be processed
mov eax, 1 ; eax = 1
dec edx ; edx = edx - 1
asqr_loop: shld edx, ebx, 2 ; edx:ebx << 2
shl ebx, 2 ;
lve eax, eax*2 ; eax * 2
cmp edx, eax ; compare edx and eax
jb short asqr_neg ; if edx<eax then go asqr_neg
inc eax ; else eax = eax + 1
sub edx, eax ; edx = edx - eax
jnc short asqr_1 ; if edx was greater than eax
; then no pb and go asqr_1
add edx, eax ; else undo, edx = edx + eax
asqr_neg: shr eax, 1 ; shift eax right by one
dec ecx ; one less pair to process
jnz short asqr_loop ; if there is some left then go asqr_loop
ret ; return to caller
asqr_1: inc eax ; eax = eax + 1
shr eax, 1 ; eax >> 1
dec ecx ; one less pair to process
jnz short asqr_loop ; if there is some left then go asqr_loop
ret ; return to caller
asqr_0_1: or eax, eax ; if eax = 0
jz short asqr_00 ; then return to caller
mov eax, 1 ; else eax = 1
asqr_00: ret ; return to caller
Sqr2 ENDP
endif
endif
;*--------------------------------------------------------------------------*
MixSample PROC USES ESI EDI EBX,\
thehandle:DWORD, pitchbend:DWORD, therepeat:DWORD,\
plug:DWORD, volleft:DWORD, volright:DWORD,\
buffer:DWORD; buffer with .VOC
mov esi, buffer
xor eax, eax
mov al, [esi]
inc al
cmp al, 10
jb okfilter
xor eax, eax
okfilter: push eax
movzx eax, word ptr[esi+14h]
add esi, eax ; skip header
cmp byte ptr[esi], 1 ; only 1 bloc type allowed
jne typeunknown
cmp byte ptr[esi + 5], 0 ; pack method
jne typeunknown
; This crap should be removed by using a file format containing the
; real sampling frequency instead of that stupid sr number in .VOC !
; :-(
mov dx, 0Fh
mov ax, 4240h ; dx:ax = 1000000
xor ebx, ebx
mov bl, byte ptr[esi + 4] ; bl = sr
neg bl ; bl = 256 - sr
div bx
shl dx, 1
adc ax, 0 ; round to nearest
mov bx, ax
; ebx = real sampling rate
; up to here ! and then avoid this ^ div !
mov eax, dword ptr[esi + 1] ; size sample
and eax, 0FFFFFFh ; 24 significant bits
sub eax, 2 ; -2 header
add esi, 6 ; esi->data
mov dword ptr[save_1], esi ; save it
mov edx, pitchbend
shl edx, 4
imul ebx, edx
shr ebx, 16
adc bx, 0 ; ebx = scaled sampling rate
xor edx, edx
xchg eax, ebx ; edx = 0, eax = sr, ebx = size
xchg edx, eax ; edx = sr, eax = 0, ebx = size
div word ptr[PlayRate] ; dx:ax / PlayRate; ax = INCR
cmp eax, 0FFFFh
jbe okincr
mov eax, 0FFFFh
okincr: mov dword ptr[save_2], eax ; save_2 = INCR
mov ecx, ebx ; ecx = size
mov esi, ebx
shr esi, 16 ; esi = hi(size)
mov edx, esi
xchg eax, ebx ; eax = size, ebx = INCR
dec eax ; A TRY !!!! (will make loop around next longer...)
shl eax, 16
div ebx ; div 64 bits !!!
sub eax, esi ; sub max roundoff error
mov esi, eax ; esi = eax = new size
mul ebx ; remultiply
mov bx, ax ; FRACT in bx
shrd eax, edx, 16 ; size in eax
mov dx, word ptr[save_2] ; INCR in dx
sub ecx, eax ; how much am I off?
jbe typeunknown ; security, should not happen!
next: inc esi ; length + 1
add bx, dx ; update fractional part of address
jnc short next ; if (not C) next
dec cx
jnz short next ; not right yet, loop
mov eax, dword ptr[follow]
lea ebx, CurrentList
mov edi, ebx
mov cx, word ptr[thehandle]
IFNDEF SAMPLE16BIT
cmp cx, VOICE_HANDLE
jne ok_handle
push eax
push ecx
push edx
call StopSample
pop edx
pop ecx
pop eax
ok_handle:
ENDIF
or ecx, dword ptr[weirdcount] ; why not ?
inc word ptr[weirdcount+2]
CRIT_SECT
cmp plug, 0
je NoPlug
lea edi, SonList
keeplooking0: cmp dword ptr[ebx], 0
je short SearchSonList
cmp eax, dword ptr[ebx+HANDLE] ; look for the "father" sample
je short found
add ebx, STRUCT_SIZE
jmp short keeplooking0
SearchSonList:
lea ebx, SonList
keeplooking1: cmp dword ptr[ebx], 0
je short Exit
cmp eax, dword ptr[ebx+HANDLE] ; look for the "father" sample
je short found
add ebx, STRUCT_SIZE
jmp short keeplooking1
exit:
xor eax, eax
jmp endcritical
found:
mov dword ptr[ebx+SON], ecx ; connect it to ist "son"
NoPlug:
lea ebx, [edi+STRUCT_SIZE*LIST_SIZE]
xor eax, eax
sub edi, STRUCT_SIZE
SearchEnd: add edi, STRUCT_SIZE
cmp eax, dword ptr[edi]
jne short SearchEnd
cmp edi, ebx
jae typeunknown
mov dword ptr[follow], ecx ; update follow
mov dword ptr[edi+HANDLE], ecx ; sample handle
mov cx, word ptr[therepeat]
mov word ptr[edi+C_REPEAT], cx ; Repeat
mov dword ptr[edi+LEFT], esi ; length
mov dword ptr[edi+DLENGTH], esi ; length
mov eax, dword ptr[save_1]
mov dword ptr[edi], eax ; Start
mov dword ptr[edi+START], eax ; Start
mov eax, dword ptr[save_2]
mov word ptr[edi+INCR], ax ; increment
mov dword ptr[edi+FRACT], 10000h ; fractional (with 1 above so != 0)
mov dword ptr[edi+SON], -1 ; son
mov dword ptr[edi+INFO0], -1 ; info0
pop eax
mov [edi+INTERPOL], al ; filter on/off
mov byte ptr[edi+LAST_SAMPLE], 80h ; 80h ( 0 )
ifdef STEREO
ifdef SAMPLE16BIT
mov eax, volleft
shr eax, SHIFT_SAMPLE - 1 ; Preshift according to number of channels
mov word ptr[edi+VOL_LEFT], ax
mov eax, volright
shr eax, SHIFT_SAMPLE - 1 ; Preshift according to number of channels
ifdef SURROUND
neg eax
endif
mov word ptr[edi+VOL_RIGHT], ax
else
mov si, 2 ; right
mov ecx, volleft
or ecx, ecx
jz short storepos
okleft: mov eax, volright
shl eax, 7 ; * 128
xor edx, edx
div ecx
cmp eax, 74 ; 1.732 (= tan 60) * 128
jb short storepos
dec si ; left
cmp eax, 222 ; .577 (= tan 30) * 128
jae short storepos
dec si ; middle
storepos: mov word ptr[edi+VOL_LEFT], si ; Store position (0:middle, 1:left, 2:right)
mov word ptr[edi+VOL_RIGHT], 1 ; to fill with non 0
endif
else
ifdef SAMPLE16BIT
mov eax, volleft
imul eax, eax
mov ecx, volright
imul ecx, ecx
add eax, ecx
call sqr2
shr eax, SHIFT_SAMPLE - 1 ; Preshift according to number of channels
mov word ptr[edi+VOL_LEFT], ax ; VOL_LEFT = sqr(volleft^2 + volright^2)
mov word ptr[edi+VOL_RIGHT], 1 ; to fill with non 0
else
mov dword ptr[edi+VOL_LEFT], 1 ; to fill with non 0
endif
endif
mov dword ptr[edi+STRUCT_SIZE], 0 ; mark end of List
mov eax, dword ptr[follow]
endcritical:
END_CRIT_SECT
ret
typeunknown:
pop eax
xor eax, eax
ret
MixSample ENDP
;*--------------------------------------------------------------------------*
ifdef SINGLE_DMA
BlockTransfert PROC
push ebx
mov ecx, BUFFER_SIZE * SSIZE
cmp word ptr[DMA_number], 3
jbe noLengthAdj
shr ecx, 1
NoLengthAdj:
dec ecx ; buffer size - 1
mov ebx, dword ptr[DMA] ; Point to DMAx
mov dx, word ptr[ebx + MASK_REG]
mov al, byte ptr[ebx + MASK2] ; mask channel
out dx, al
mov dx, word ptr[ebx + FF_REG]
out dx, al ; flip-flop
mov dx, word ptr[ebx + COUNT_REG]
mov al, cl ; buffer size - 1
out dx, al
mov al, ch
out dx, al
mov dx, word ptr[ebx + ADDX_REG]
mov eax, dword ptr[BufferHalf]
mov eax, dword ptr[BUFFER_DMA+eax] ; start offset
cmp word ptr[DMA_number], 3
jbe noAddrAdj
shr eax, 1
NoAddrAdj:
out dx, al
shr eax, 8
out dx, al
mov dx, word ptr[ebx + PAGE_REG]
shr eax, 8 ; page of DMA transfert
out dx, al
mov dx, word ptr[ebx + MODE_REG]
mov al, byte ptr[ebx + VOICE_OUT] ; output sample
out dx, al
mov dx, word ptr[ebx + MASK_REG]
mov al, byte ptr[ebx + MASK1] ; channel OK
out dx, al
pop ebx
jmp StartDMACard
BlockTransfert ENDP
endif
;*--------------------------------------------------------------------------*
PauseSample PROC
xor eax, eax
CRIT_SECT
mov al, byte ptr[FlagPause]
dec al
and al, 10b
or al, 01b ; 0->3, 1->1, 2->1, 3->3
mov byte ptr[FlagPause], al
shr eax, 1
xor al, 1
END_CRIT_SECT
ret
PauseSample ENDP
;*--------------------------------------------------------------------------*
ContinueSample PROC
xor eax, eax
CRIT_SECT
mov al, byte ptr[FlagPause]
inc al
and al, 10b ; 0->0, 1->2, 2->2, 3->0
mov byte ptr[FlagPause], al
shr eax, 1
xor al, 1
END_CRIT_SECT
ret
ContinueSample ENDP
;----------------------------------------------------------------------------
ifndef NOIRQ
InstallISR PROC
push edx
mov bl, byte ptr[INT_number] ; plug ISR on user INT
mov cx, cs
SET_PROT_VECT
pop edx
cmp dword ptr[IRQ_number], 7 ; if IRQ > 7
jbe nobi
mov bl, 18h ; plug as well on int 18h
mov cx, cs
SET_PROT_VECT
mov bl, byte ptr[INT_number] ; plug into real usr INT
mov ecx, offset Redirector
mov dx, cx ; compute real-mode
xor cx, cx ; seg:ofs
shr ecx, 4
SET_REAL_VECT
nobi:
ret
InstallISR ENDP
endif
;----------------------------------------------------------------------------
InitCard PROC USES EBX EDI ESI EBP,\
Buffer:DWORD
ifndef NOIRQ
mov word ptr[local_DS], ds
endif
mov eax, Buffer
mov dword ptr[BUFFER_DMA], eax
ifndef SBPRO
call ResetCard
endif
ifndef NOIRQ
xor eax, eax
mov ax, word ptr[DMA_number]
cmp ax, 7
ja short ErrorDMA
mov eax, dword ptr[TAB_DMA+eax*4]
or eax, eax
jnz short DMAFound
ErrorDMA:
xor eax, eax
ret
DMAFound:
mov dword ptr[DMA], eax
mov eax, dword ptr[IRQ_number]
cmp al, 7
ja short Second
add al, 8
jmp short gotvect
Second:
add al, 70h - 8
gotvect:
mov dword ptr[INT_number], eax ; save user int
mov bl, al
GET_PROT_VECT
mov word ptr[Old_PIRQ_Sel], cx
mov dword ptr[Old_PIRQ_Off], edx
cmp dword ptr[IRQ_number], 7
jbe nobi
mov bl, byte ptr[INT_number] ; if IRQ>7 save real vect
GET_REAL_VECT
mov word ptr[Old_RIRQ_Seg], cx
mov word ptr[Old_RIRQ_Off], dx
mov bl, 18h ; if IRQ>7 save int 18h
GET_PROT_VECT
mov word ptr[Old_18_Sel], cx
mov dword ptr[Old_18_Off], edx
nobi:
mov dx, 21h ; IRQ mask reg
mov cx, word ptr[IRQ_number]
cmp cx, 7
jbe short Ok21
mov dx, 0A1h ; reg A1h, 2nd ctrl
Ok21: in al, dx
mov byte ptr[IRQ_mask], al ; save mask
and cl, 7
mov bl, 1
shl bl, cl
not bl
and al, bl ; unmask IRQ
out dx, al ; write new mask
ifdef SBPRO
call ResetCard
endif
mov edx, offset NewIRQ
call InstallISR
endif
call StopSample ; to reset everything
xor eax, eax
mov dword ptr[BackCurrentList], eax
mov dword ptr[BackSonList], eax
mov edi, dword ptr[BUFFER_DMA]
mov eax, edi
add eax, BUFFER_SIZE * SSIZE
mov dword ptr[MID_BUFFER_DMA], eax ; init pointer
mov dword ptr[CURRENT_BUFFER], eax ; init pointer
mov dword ptr[BufferHalf], 4 ; point on second half
mov ecx, (BUFFER_SIZE * 2 * SSIZE) / 4; clear all buffer
MIDPOINT
rep stosd
ifndef NOIRQ
ifdef AUTO_DMA
mov ecx, BUFFER_SIZE * 2 * SSIZE
cmp word ptr[DMA_number], 3
jbe noLengthAdj
shr ecx, 1
NoLengthAdj:
dec ecx
mov ebx, dword ptr[DMA] ; Point to DMAx
mov dx, word ptr[ebx + MASK_REG]
mov al, byte ptr[ebx + MASK2] ; mask channel
out dx, al
mov dx, word ptr[ebx + FF_REG]
out dx, al ; flip-flop
mov dx, word ptr[ebx + COUNT_REG]
mov al, cl ; buffer size - 1
out dx, al
mov al, ch
out dx, al
mov dx, word ptr[ebx + ADDX_REG]
mov eax, dword ptr[BUFFER_DMA] ; start offset
cmp word ptr[DMA_number], 3
jbe noAddrAdj
shr eax, 1
mov di, ax
xor ax, ax
shl eax, 1
mov ax, di
NoAddrAdj:
out dx, al
shr eax, 8
out dx, al
mov dx, word ptr[ebx + PAGE_REG]
shr eax, 8 ; page of DMA transfert
out dx, al
mov dx, word ptr[ebx + MODE_REG]
mov al, byte ptr[ebx + AUTO_OUT] ; output sample
out dx, al
mov dx, word ptr[ebx + MASK_REG]
mov al, byte ptr[ebx + MASK1] ; channel OK
out dx, al
endif
endif
ifdef AUTO_DMA
call StartDMACard
elseifdef SINGLE_DMA
call BlockTransfert ; Start DMA transfert
endif
mov eax, 1
ret
InitCard ENDP
;----------------------------------------------------------------------------
ClearCard PROC USES EBX ESI EDI EBP
call StopSample ; just in case something was playing...
call CloseCard
ifndef NOIRQ
mov dx, 21h ; read IRQ mask
cmp word ptr[IRQ_number], 7
jbe short Ok21
add dx, 80h ; reg 0A1h
Ok21: mov al, byte ptr[IRQ_mask] ; get old mask
out dx, al ; write old IRQ mask
mov bl, byte ptr[INT_number]
mov cx, word ptr[Old_PIRQ_sel]
mov edx, dword ptr[Old_PIRQ_off]
SET_PROT_VECT
cmp dword ptr[IRQ_number], 7
jbe nobi
mov bl, byte ptr[INT_number]
mov cx, word ptr[Old_RIRQ_seg]
mov dx, word ptr[Old_RIRQ_off]
SET_REAL_VECT
mov bl, 18h
mov cx, word ptr[Old_18_sel]
mov edx, dword ptr[Old_18_off]
SET_PROT_VECT
nobi:
endif
ret
ClearCard ENDP
;----------------------------------------------------------------------------
AskVars PROC ,\
pListNames:DWORD, pListVars:DWORD
mov eax, offset ListNames
mov ecx, pListNames
mov dword ptr[ecx], eax
mov eax, offset ListVars
mov ecx, pListVars
mov dword ptr[ecx], eax
ret
AskVars ENDP
;----------------------------------------------------------------------------
GetBufferSize PROC
mov eax, BUFFER_SIZE * 2 * SSIZE
ret
GetBufferSize ENDP
;----------------------------------------------------------------------------
GiveSampleInfo0 PROC \
LongHandle:DWORD, Info:DWORD
mov eax, LongHandle
CRIT_SECT
call SearchLongHandle
or edx, edx
jz short notfound
mov eax, Info
mov dword ptr[edx+INFO0], eax
notfound:
END_CRIT_SECT
ret
GiveSampleInfo0 ENDP
;----------------------------------------------------------------------------
GetSnapSample PROC USES EBX,\
pList:DWORD
lea eax, SnapList
mov edx, pList
mov dword ptr[edx], eax
lea edx, CurrentList
lea ecx, SonList
CRIT_SECT
keeplooking: cmp dword ptr[edx], 0
je short exit
mov ebx, dword ptr[edx+HANDLE]
mov dword ptr[eax], ebx
mov ebx, dword ptr[edx+INFO0]
mov dword ptr[eax+4], ebx
mov ebx, dword ptr[edx]
sub ebx, dword ptr[edx+START]
mov dword ptr[eax+8], ebx
add eax, 12
add edx, STRUCT_SIZE
jmp short keeplooking
exit:
cmp ecx, edx
mov edx, ecx
jne keeplooking
END_CRIT_SECT
sub eax, offset SnapList
shr eax, 3
ret
GetSnapSample ENDP
;----------------------------------------------------------------------------
CopyList PROC
keepcopying: cmp dword ptr[esi], 0
je short endcopy
mov ecx, STRUCT_SIZE / 4
rep movsd
jmp short keepcopying
endcopy: mov dword ptr[edi], 0
ret
CopyList ENDP
;----------------------------------------------------------------------------
SAveStateSample PROC USES ESI EDI
call PauseSample
waitpause: cmp byte ptr[FlagPause], 1
jne short waitpause
CRIT_SECT
lea esi, CurrentList ; backup CurrentList
lea edi, BackCurrentList
call CopyList
lea esi, SonList ; backup SonList
lea edi, BackSonList
call CopyList
mov eax, dword ptr[follow] ; Backup follow
mov dword ptr[backfollow], eax
mov eax, dword ptr[weirdcount] ; Backup weirdcount
mov dword ptr[backweirdcount], eax
xor eax, eax ; empty both lists
mov dword ptr[CurrentList], eax
mov dword ptr[SonList], eax
mov byte ptr[FlagPause], 0
END_CRIT_SECT
ret
SAveStateSample ENDP
;----------------------------------------------------------------------------
RestoreStateSample PROC USES ESI EDI
call PauseSample
waitpause: cmp byte ptr[FlagPause], 1
jne short waitpause
CRIT_SECT
lea esi, BackCurrentList ; restore CurrentList
lea edi, CurrentList
call CopyList
lea edi, BackSonList ; restore SonList
lea edi, SonList
call CopyList
mov eax, dword ptr[backfollow] ; restore follow
mov dword ptr[follow], eax
mov eax, dword ptr[backweirdcount] ; restore weirdcount
mov eax, dword ptr[weirdcount]
END_CRIT_SECT
call ContinueSample
waitcontinue: cmp byte ptr[FlagPause], 0
jne short waitcontinue
ret
RestoreStateSample ENDP
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
ifdef PAS
INT2F PROC\ ;Perform DPMI call to real-mode INT 2F
USES esi edi\ ;for Pro Audio Spectrum driver access
,regAX,regBX
mov ax,WORD PTR [regAX]
mov int_AX,ax
mov ax,WORD PTR [regBX]
mov int_BX,ax
mov int_DS,0
mov int_ES,0
pushf
pop ax
mov int_flags,ax
mov eax,0300h
mov ebx,002fh
mov ecx,0
mov edi,OFFSET DPMI_real_int
int 31h
mov ax,int_AX
mov bx,int_BX
mov cx,int_CX
mov dx,int_DX
ret
INT2F ENDP
;----------------------------------------------------------------------------
ResetCard PROC USES EBX
mov eax,0bc04h ;get current DMA and IRQ settings
invoke INT2F,eax,eax
and ebx,0ffh
and ecx,0ffh
mov [DMA_number],ebx
mov [IRQ_number],ecx
mov eax,0bc07h ;get state table entries
invoke INT2F,eax,eax
xor eax,eax ;update local state table
mov al,bh
mov MV_xchannel,eax
mov al,ch
mov MV_filter,eax
mov eax, MV_xchannel
mov edx, CROSSCHANNEL ;disable DRQs from PAS
IFDEF SAMPLE16BIT
and eax, 00110000b ;and disable PCM state machine
or eax, 00001001b
ELSE
and eax, 00110000b ;and disable PCM state machine
or eax, 00000110b
ENDIF
out dx, al
mov MV_xchannel, eax
mov edx, PCMDATA ;silence PCM output
mov al, 80h
out dx, al
mov edx, SYSCONF
in al, dx
IFDEF SAMPLE16BIT
or al, 100b
ELSE
and al, 11111011b
ENDIF
out dx, al
mov ecx, [PlayRate]
shl ecx, 1
xor edx, edx
mov eax, 1193180
div ecx
mov ecx, eax
mov al, 00110110b ;timer 0, square wave, binary mode
mov edx, TMRCTLR
out dx, al
mov edx, SAMPLERATE
mov al, cl
out dx, al
jmp $+2
mov al, ch
out dx, al
mov edx,INTRCTLRST ;enable IRQs on sample buffer empty
out dx,al
jmp $+2
in al,dx
mov edx,INTRCTLR
in al,dx
or eax,00001000b
out dx,al
ret
ResetCard ENDP
;----------------------------------------------------------------------------
CloseCard PROC
mov eax,MV_xchannel
mov edx,CROSSCHANNEL ;disable DRQs from PAS
and eax,00111111b ;and disable PCM state machine
out dx,al
mov MV_xchannel,eax
ret
CloseCard ENDP
;----------------------------------------------------------------------------
StartDMACard PROC
mov eax,MV_xchannel
mov edx,CROSSCHANNEL
or eax,10000000b ;secure the DMA channel
out dx,al
mov MV_xchannel,eax
mov cx, BUFFER_SIZE * SSIZE
mov eax,01110100b ;program sample buffer counter
mov edx,TMRCTLR
out dx,al
mov edx,SAMPLECNT
mov al,cl
out dx,al
jmp $+2
mov al,ch
out dx,al
mov al,BYTE PTR MV_xchannel
and al,00001111b ;reset PCM state machine
or al,10010000b
mov edx,CROSSCHANNEL
out dx,al
jmp $+2
or al,01000000b
out dx,al
mov BYTE PTR MV_xchannel,al
; mov eax,MV_filter
; or eax,11000000b
mov eax,11100000b
mov edx,AUDIOFILT
out dx,al ;start the transfer
mov MV_filter,eax
ret
StartDMACard ENDP
;----------------------------------------------------------------------------
AckIrq PROC
mov edx,INTRCTLRST
in al,dx ;acknowledge the interrupt
test eax,00001000b
jz error ;it wasn't caused by our board, exit
out dx,al
clc
ret
error:
stc
ret
AckIrq ENDP
endif
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
ifdef MWSS
ResetCard PROC USES EBX
mov ax, word ptr[PlayRate]
cmp ax, 44100
jae short Freq44
lea edx, MWSSFreq
SearchFreq: cmp ax, word ptr[edx]
jb short FoundFreq
add edx, 4
jmp short SearchFreq
Freq44:
mov ax, 44100
mov cl, 0Bh
jmp short WBack
FoundFreq:
mov ax, word ptr[edx] ; closest faster speed
mov cl, byte ptr[edx+2] ; clock select
WBack:
mov word ptr[PlayRate], ax
or cl, 01010000b ; 16 bit linear, Stereo
mov edx, [IRQ_number] ; IRQ
mov al, [MWSSIrq+edx]
mov edx, [DMA_number] ; DMA
or al, [MWSSDma+edx]
mov dx, word ptr[BASE_ADDR]
add dl, 3 ; offset 3
out dx, al ; program IRQ & DMA
inc dl ; offset 4
mov al, 6 ; left vol
out dx, al
inc dl ; offset 5
mov al, 80h ; mute
out dx, al
dec dl ; offset 4
mov al, 7 ; right vol
out dx, al
inc dl ; offset 5
mov al, 80h ; mute
out dx, al
dec dl ; offset 4
mov al, 13 ; digital mix
out dx, al
inc dl ; offset 5
xor al, al ; mute
out dx, al
dec dl ; offset 4
mov al, 2 ; left aux1
out dx, al
inc dl ; offset 5
mov al, 80h ; mute
out dx, al
dec dl ; offset 4
mov al, 3 ; right aux1
out dx, al
inc dl ; offset 5
mov al, 80h ; mute
out dx, al
dec dl ; offset 4
mov al, 4 ; left aux2
out dx, al
inc dl ; offset 5
mov al, 80h ; mute
out dx, al
dec dl ; offset 4
mov al, 5 ; right aux2
out dx, al
inc dl ; offset 5
mov al, 80h ; mute
out dx, al
dec dl ; offset 4
mov al, 49h ; enter MCE, Interface Ctrl
out dx, al
inc dl ; offset 5
mov al, 08h ; auto-calibrate
out dx, al
dec dl ; offset 4
mov al, 48h ; MCE, Interface Ctrl
out dx, al
inc dl ; offset 5
mov al, cl ; 16 bit linear, stereo, speed
out dx, al
dec dl ; offset 4
wait_init: in al, dx
and al, 80h
jnz wait_init
xor al, al
out dx, al ; clear MCE
xor bx, bx ; at least 6 millisec.
wait0: in al, dx
dec bx
jnz short wait0
wait_cal: mov al, 0Bh ; Test & Init Reg
out dx, al
inc dl ; offset 5
in al, dx
dec dl ; offset 4
and al, 20h
jnz wait_cal
mov al, 6 ; left vol
out dx, al
inc dl ; offset 5
xor al, al ; max vol
out dx, al
dec dl ; offset 4
mov al, 7 ; right vol
out dx, al
inc dl ; offset 5
xor al, al ; max vol
out dx, al
ret
ResetCard ENDP
;*--------------------------------------------------------------------------*
CloseCard PROC
mov dx, word ptr[BASE_ADDR] ; DSP
add dl, 4 ; offset 4
mov al, 0Ah ; Pin Ctrl reg
out dx, al
inc dx ; offset 5
xor al, al ; turn off interrupts
out dx, al
inc dx ; offset 6
out dx, al ; Ack outstanding interrupts
sub dl, 2 ; offset 4
mov al, 9 ; Interface Config reg
out dx, al
inc dx ; offset 5
xor al, al ; turn off codec DMA
out dx, al
sub dl, 2
out dx, al ; deselect IRQ and DMA
ret
CloseCard ENDP
;----------------------------------------------------------------------------
AckIrq PROC
mov dx, word ptr[BASE_ADDR] ; DSP
add dl, 6
in al, dx
shr al, 1 ; get int flag in C
cmc ; complement C in order to return error if 0
out dx, al ; Ack anyway
ret
AckIrq ENDP
;----------------------------------------------------------------------------
StartDMACard PROC
mov cx, BUFFER_SIZE - 1
mov dx, word ptr[BASE_ADDR] ; DSP
add dl, 6
out dx, al ; clear any pending IRQ
sub dl, 2 ; offset 4
mov al, 15 ; DMA Count Lower
out dx, al
inc dl ; offset 5
mov al, cl
out dx, al
dec dl ; offset 4
mov al, 14 ; DMA Count Upper
out dx, al
inc dl ; offset 5
mov al, ch
out dx, al
dec dl ; offset 4
mov al, 9 ; Interface config
out dx, al
inc dl ; offset 5
mov al, 00000101b ; DMA Playback
out dx, al
dec dl ; offset 4
mov al, 0Ah ; Pin Ctrl Reg
out dx, al
inc dx ; offset 5
mov al, 00000010b ; Turn on Interrupts
out dx, al
ret
StartDMACard ENDP
endif
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
ifdef SBLASTER
WRITE_DSP MACRO VAL ; write to DSP whithout timeout
local wait_dsp
wait_dsp: in al, dx
or al, al
js wait_dsp
mov al, VAL
out dx, al
ENDM
WRITE_MIXER MACRO REG, VAL ; write to MIXER chip
mov al, REG
out dx, al
inc dx
mov al, VAL
out dx, al
dec dx
ENDM
READ_MIXER MACRO REG ; read from MIXER chip
mov al, REG
out dx, al
inc dx
in al, dx
dec dx
ENDM
ifdef SBPRO
InitIRQ PROC
pushad
push ds
mov ax, cs:word ptr[local_DS] ; restore DS
mov ds, ax
mov al, 20h ; allows for new int
cmp byte ptr[IRQ_number], 7
jbe short NoSecondCtrl
out 0A0h, al
NoSecondCtrl: out 20h, al
call AckIrq
jc short FinIRQ ; not a DMA IRQ
mov byte ptr[OkIRQ], 1
FinIRQ:
pop ds
popad
iretd
InitIRQ ENDP
endif
ResetCard PROC
cmp dword ptr[PlayRate], 12000
jae OkRateLow
mov dword ptr[PlayRate], 12000
OkRateLow:
cmp dword ptr[PlayRate], 22000
jbe OkRateHigh
mov dword ptr[PlayRate], 22000
OkRateHigh:
ifndef SB16
ifdef SBPRO
mov dx, 07A1h
mov ax, 2000h ; dx:ax = 128000000
else
mov dx, 0F42h
mov ax, 4000h ; dx:ax = 256000000
endif
div word ptr[PlayRate] ; divide by PlayRate
neg ax
shr ax, 8
mov cx, ax ; cl = "Magic"
push ecx
ifdef SBPRO
mov dx, 07h
mov ax, 0A120h ; dx:ax = 500000
else
mov dx, 0Fh
mov ax, 4240h ; dx:ax = 1000000
endif
neg cl
div cx ; divide by "-Magic"
mov word ptr[PlayRate], ax ; write back PlayRate
endif
mov dx, word ptr[BASE_ADDR]
add dl, 6 ; reset port (offset 6)
mov al, 1 ; write 1
out dx, al
mov ah, 8 * 3 ; 4 * "in al, dx" = 1 microsec on std ISA bus (8 Mhz)
wait_io: in al, dx ; so 8 to be sure if 16 MHz !
dec ah ; kill the cat !
jnz short wait_io
xor al, al
out dx, al ; write 0
; now reset should be done..
add dl, 4 ; offset 0Ah
Next: add dl, 4 ; offset 0Eh
Wait_s: in al, dx
or al, al
jns Wait_s
sub dl, 4 ; offset 0Ah
in al, dx ; read if reset terminated
cmp al, RESET_TEST_CODE ; should be...
jne Next
ifdef SB16
sub dl, 6 ; offset 04h
mov al, 80h
out dx, al
inc dx ; offset 05h
xor eax, eax
in al, dx
and al, 0Fh ; mask reserved bit
bsf ax, ax
mov al, byte ptr[SB16_IRQ+eax]
mov dword ptr[IRQ_number], eax
dec dx ; offset 04h
mov al, 81h
out dx, al
inc dx ; offset 05h
in al, dx
and al, 11101011b ; mask reserved bit
ifdef SAMPLE16BIT
bsr ax, ax
else
bsf ax, ax
endif
mov dword ptr[DMA_number], eax
add dl, 7 ; offset 0Ch
WRITE_DSP DSP_RATE_CMD ; rate
mov cx, word ptr[PlayRate]
WRITE_DSP ch ;
WRITE_DSP cl ;
else
add dl, 02h ; offset 0Ch
WRITE_DSP DSP_ONSPK_CMD ; Turn speaker on
ifdef SBPRO
mov edx, offset InitIRQ ; Temporary IRQ handler
call InstallISR
mov dx, word ptr[BASE_ADDR]
add dl, 4 ; offset 4
mov al, 0Eh ; stereo switch & filter
out dx, al
inc dx ; offset 5
in al, dx
or al, 2 ; enable stereo
out dx, al
mov ecx, dword ptr[DMA] ; Point to DMAx
mov dx, word ptr[ecx + MASK_REG]
mov al, byte ptr[ecx + MASK2] ; mask channel
out dx, al
mov dx, word ptr[ecx + FF_REG]
out dx, al ; flip-flop
mov dx, word ptr[ecx + COUNT_REG]
xor al, al
out dx, al
out dx, al
mov eax, dword ptr[BUFFER_DMA] ; start offset
mov byte ptr[eax], 80h ; write a "0" into the buffer
mov dx, word ptr[ecx + ADDX_REG]
out dx, al
shr eax, 8
out dx, al
mov dx, word ptr[ecx + PAGE_REG]
shr eax, 8 ; page of DMA transfert
out dx, al
mov dx, word ptr[ecx + MODE_REG]
mov al, byte ptr[ecx + VOICE_OUT] ; output sample
out dx, al
mov dx, word ptr[ecx + MASK_REG]
mov al, byte ptr[ecx + MASK1] ; channel OK
out dx, al
mov dx, word ptr[BASE_ADDR]
add dl, 0Ch ; offset 0Ch
mov byte ptr[OkIRQ], 0
WRITE_DSP DSP_VO8S_CMD
WRITE_DSP 0
WRITE_DSP 0
WaitIRQ: cmp byte ptr[OkIRQ], 1
jne short WaitIRQ
sub dl, 8 ; offset 4
mov al, 0Eh ; stereo switch & filter
out dx, al
inc dx ; offset 5
in al, dx
mov byte ptr[Filter], al
or al, 20h ; disable filter
out dx, al
add dl, 7 ; offset 0Ch
endif
pop ecx
WRITE_DSP DSP_TIME_CMD ; "rate"
WRITE_DSP cl ; magic number !
endif
ret
ResetCard ENDP
;*--------------------------------------------------------------------------*
CloseCard PROC
mov dx, word ptr[BASE_ADDR] ; point to DSP
ifdef SB16
add dl, 0CH
ifdef SAMPLE16BIT
WRITE_DSP DSP_VO16S_CMD ; single-cycle 16 bit DMA
ifdef STEREO
WRITE_DSP DSP_16STEREO_MODE ; 16 bit stereo
else
WRITE_DSP DSP_16MONO_MODE ; 16 bit mono
endif
else
WRITE_DSP DSP_VO8S_4_CMD ; single-cycle 8 bit DMA
ifdef STEREO
WRITE_DSP DSP_8STEREO_MODE ; 8 bit stereo
else
WRITE_DSP DSP_8MONO_MODE ; 8 bit mono
endif
endif
WRITE_DSP 0 ; length of 1 to finish
WRITE_DSP 0
else
ifdef SBPRO
add dl, 6 ; reset port (offset 6)
mov al, 1 ; write 1
out dx, al
mov ah, 8 * 3 ; 4 * "in al, dx" = 1 microsec on std ISA bus (8 Mhz)
wait_io: in al, dx ; so 8 to be sure if 16 MHz !
dec ah ; kill the cat !
jnz wait_io
xor al, al
out dx, al ; write 0
; now reset should be done..
add dl, 4 ; offset 0Ah
Next: add dl, 4 ; offset 0Eh
Wait_s: in al, dx
or al, al
jns Wait_s
sub dl, 4 ; offset 0Ah
in al, dx ; read if reset terminated
cmp al, RESET_TEST_CODE ; should be...
jne Next
sub dl, 6 ; offset 4
mov al, 0Eh
out dx, al
inc dx ; offset 5
mov al, byte ptr[Filter] ; restore filter
out dx, al
dec dx
mov al, 0Eh
out dx, al
inc dx ; offset 5
in al, dx
and al, 11111101b ; turn off stereo
out dx, al
add dl, 7 ; offset 0Ch
WRITE_DSP DSP_OFFSPK_CMD ; Turn speaker off
else
add dl, 0CH
WRITE_DSP DSP_OFFSPK_CMD ; Turn speaker off
WRITE_DSP DSP_VO8S_CMD ; single-cycle 8 bit DMA
WRITE_DSP 0 ; length of 1 to finish
WRITE_DSP 0
endif
endif
ret
CloseCard ENDP
;----------------------------------------------------------------------------
AckIrq PROC
mov dx, word ptr[BASE_ADDR] ; DSP IRQ ACK
ifdef SB16
add dl, 4 ; offset 4
mov al, 82h
out dx, al
inc dx ; offset 5
in al, dx
ifdef SAMPLE16BIT
and al, 2
jz NoDMAIRQ
add dl, 10 ; offset Fh
else
and al, 1
jz NoDMAIRQ
add dl, 9 ; offset Eh
endif
in al, dx
ret
NoDMAIRQ:
stc
ret
else
irq_ok: add dl, 0Eh ; 8 bit Samples ACK
in al, dx
not_real:
ret
endif
AckIrq ENDP
;----------------------------------------------------------------------------
StartDMACard PROC
mov dx, word ptr[BASE_ADDR] ; DSP
add dl, 0Ch
ifdef STEREO
mov cx, BUFFER_SIZE * 2 - 1 ; half-buffer size - 1 for DMA
else
mov cx, BUFFER_SIZE - 1 ; half-buffer size - 1 for DMA
endif
ifdef SB16
ifdef SAMPLE16BIT
WRITE_DSP DSP_VO16_CMD ; auto-init 16 bit DMA
ifdef STEREO
WRITE_DSP DSP_16STEREO_MODE ; 16 bit stereo
else
WRITE_DSP DSP_16MONO_MODE ; 16 bit mono
endif
else
WRITE_DSP DSP_VO8_4_CMD ; auto-init 8 bit DMA
ifdef STEREO
WRITE_DSP DSP_8STEREO_MODE ; 8 bit stereo
else
WRITE_DSP DSP_8MONO_MODE ; 8 bit mono
endif
endif
WRITE_DSP cl
WRITE_DSP ch
elseifdef SBLASTER1
WRITE_DSP DSP_VO8S_CMD ; single-cycle 8 bit DMA
WRITE_DSP cl
WRITE_DSP ch
else
WRITE_DSP DSP_BSIZE_CMD ; Set block size
WRITE_DSP cl
WRITE_DSP ch
ifdef SBPRO
WRITE_DSP DSP_VO8H_CMD ; auto-init 8 bit high-speed DMA
else
WRITE_DSP DSP_VO8_CMD ; auto-init 8 bit DMA
endif
endif
ret
StartDMACard ENDP
endif
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
ifdef GOLD
SELECT_MIXER MACRO
local wait
cli
mov al, 0FFh
out dx, al
out dx, al
wait: in al, dx
and al, 11000000b
jnz wait
ENDM
LEAVE_MIXER MACRO
local wait
wait: in al, dx
and al, 11000000b
jnz wait
mov al, 0FEh
out dx, al
out dx, al
sti
ENDM
WRITE_MIXER MACRO PORT, VAL
local wait1, wait2
cli
mov al, PORT
out dx, al
wait1: in al, dx
and al, 11000000b
jnz wait1
inc dx
mov al, VAL
out dx, al
dec dx
wait2: in al, dx
and al, 11000000b
jnz wait2
sti
ENDM
READ_MIXER MACRO PORT
local wait1, wait2
cli
mov al, PORT
out dx, al
wait1: in al, dx
and al, 11000000b
jnz wait1
inc dx
in al, dx
dec dx
mov ah, al
wait2: in al, dx
and al, 11000000b
jnz wait2
mov al, ah
sti
ENDM
WRITE_MMA0 MACRO PORT, VAL
cli
mov al, PORT
out dx, al
inc dx
mov al, VAL
out dx, al
dec dx
in al, dx
in al, dx
sti
ENDM
READ_MMA0 MACRO PORT
cli
mov al, PORT
out dx, al
inc dx
in al, dx
dec dx
mov ah, al
in al, dx
in al, dx
mov al, ah
sti
ENDM
WRITE_MMA1 MACRO PORT, VAL
cli
mov al, PORT
out dx, al
add dx, 3
mov al, VAL
out dx, al
sub dx, 3
in al, dx
in al, dx
sti
ENDM
READ_MMA1 MACRO PORT
cli
mov al, PORT
out dx, al
add dx, 3
in al, dx
sub dx, 3
mov ah, al
in al, dx
in al, dx
mov al, ah
sti
ENDM
;*--------------------------------------------------------------------------*
ResetCard PROC
mov dx, word ptr[BASE_ADDR]
add dx, 2 ; MIXER
SELECT_MIXER
WRITE_MIXER 8h, 11001110b ; STEREO mode
WRITE_MIXER 11h, 00001000b ; filter on output, no mic input, no PC-speaker input
READ_MIXER 13h
mov byte ptr[Mixer_13], al
mov cl, al
and eax, 3
lea ebx, Gold_IRQ
mov al, byte ptr[ebx+eax]
mov dword ptr[IRQ_number], eax
mov al, cl
shr al, 4
and al, 3
mov dword ptr[DMA_number], eax
or cl, 10001000b ; enable DMA0, enable IRQ
WRITE_MIXER 13h, cl
READ_MIXER 14h
mov byte ptr[Mixer_14], al
mov cl, al
and cl, 01111111b
WRITE_MIXER 14h, cl
LEAVE_MIXER
add dx, 2 ; MMA
WRITE_MMA0 9, 80h ; reset channel 0
WRITE_MMA1 9, 80h ; reset channel 1
mov cx, 4
fillFIFO0: WRITE_MMA0 0Bh, 0
dec cx
jnz FillFIFO0
mov cx, 4
fillFIFO1: WRITE_MMA1 0Bh, 0
dec cx
jnz FillFIFO1
WRITE_MMA0 9, 00101110b ; 22.05 Khz, PCM, L, Play
WRITE_MMA1 9, 01001110b ; 22.05 Khz, PCM, R, Play
mov word ptr[PlayRate], 22050 ; 22.05 Khz
WRITE_MMA0 0Ch, 11000101b ; Interleave, 16 bit, 96 byte FIFO, DMA
WRITE_MMA1 0Ch, 01000011b ; 16 bit, no FIFO (use other channel), DMA
WRITE_MMA0 0Ah, 0FFh ; Maximum volume (volume will be controlled by mixer)
WRITE_MMA1 0Ah, 0FFh
mov cx, 100
fillFIFO: WRITE_MMA0 0Bh, 0
dec cx
jnz FillFIFO
ret
ResetCard ENDP
;*--------------------------------------------------------------------------*
CloseCard PROC
mov dx, word ptr[BASE_ADDR]
add dx, 4 ; MMA
WRITE_MMA1 0Ch, 01000010b ; 16 bit, no FIFO, no DMA
WRITE_MMA0 0Ch, 01000010b ; 16 bit, no FIFO, no DMA
WRITE_MMA0 9, 80h ; reset channel 0
WRITE_MMA1 9, 80h ; reset channel 1
sub dx, 2 ; MIXER
SELECT_MIXER
WRITE_MIXER 13h, Mixer_13
WRITE_MIXER 14h, Mixer_14
LEAVE_MIXER
ret
CloseCard ENDP
;----------------------------------------------------------------------------
AckIrq PROC
mov dx, word ptr[BASE_ADDR]
add dx, 4 ; MMA
in al, dx
and al, 1
jz short noDMA
mov ebx, dword ptr[DMA] ; Point to DMAx
mov dx, word ptr[ebx + FF_REG]
out dx, al ; flip-flop
mov dx, word ptr[ebx + COUNT_REG]
in al, dx
mov ah, al
in al, dx
xchg al, ah
or ax, ax
jz short OkDMA
inc ax
jnz short noDMA
OkDMA:
clc
ret
NoDMA:
stc
not_real:
ret
AckIrq ENDP
;----------------------------------------------------------------------------
StartDMACard PROC
mov dx, word ptr[BASE_ADDR]
add dx, 4 ; MMA
WRITE_MMA0 9, 00101111b ; 22.05 Khz, PCM, L, Play, GO
ret
StartDMACard ENDP
endif
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
ifdef GUS
extrn Nolanguage resetcard:PROC
;*--------------------------------------------------------------------------*
extrn Nolanguage CloseCard:PROC
;*--------------------------------------------------------------------------*
extrn Nolanguage StartDMACard:PROC
endif
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
END