;***************************************************************************
;*	Driver pour la Sound Blaster (calcul 10bits)
;*
;* Programm‚ par S‚bastien Granjoux
;* Commenc‚ le 11/01/95
;* Modification le 11/01/95

IDEAL
P386N

INCLUDE "CRYSERR.INC"
INCLUDE "CRYSDEV.INC"
INCLUDE "CRYSLOAD.INC"

PUBLIC	USESB

SEGMENT CODE PARA PUBLIC USE16 'CODE'

ASSUME cs:CODE,ds:CODE

NO_FILTER	EQU	3600
LOW_FILTER	EQU	1800

;*************************************************************************
;*	Fonction de d‚tection du driver

PROC	USESB

	call	USEDEVICE
	DEVICE <03,'BLASTERs=ApIiDd!Tt13$',OFFSET setsb,OFFSET startsb,OFFSET stopsb,OFFSET makesb,OFFSET defbpm,OFFSET peekdef,0,0,1>

ENDP

SbLen	 DW	?
DspVer   DW	0
Count    DW	0
DmaPage  DB 	87h,83h,82h,81h

;***************************************************************************
;*	Attente d'une autorisation d'‚criture
;*
;* Entr‚e:
;*	DX	port d'‚criture 2XC
;*
;* Sortie:
;*	DX	port d'‚criture 2XC

PROC	waitsb

@@wait:
	in	al,dx
	or	al,al
	js	@@wait

	ret
ENDP

;***************************************************************************
;*	Attente d'une lecture sur un port de la SB
;*
;* Entr‚e:
;*	DX	adresse de port du status en lecture 2XE
;*
;* Sortie:
;*	AL	r‚sultat de la lecture
;*	DX	adresse de port de lecture 2XA

PROC	readsb

@@wait:
	in	al,dx
	or	al,al
	jns	@@wait
	sub	dx,4
	in	al,dx

	ret
ENDP


;***************************************************************************
;*	Reset de la Soundblaster (recupŠre l'adresse de port)
;*
;* Entr‚e:
;*	DS:SI	adresse de la structure device
;*
;* Sortie:
;*	DX	adresse de port du reset 2X6

PROC	resetsb

	mov	dx,[(DEVICE ptr ds:si).port]
	add	dx,6
	mov	al,1
	out	dx,al
	mov	cx,1024	;compte des moutons pendant au moins 3æs
@@compte:
	loop	@@compte
	dec	al
	out	dx,al
	ret

ENDP

;***************************************************************************
;*	routine permettant d'initialiser le son sur la soundblaster

PROC	setsb

	call	resetsb

	add	dx,8
	mov	cx,1024
@@wait:
	in	al,dx
	or	al,al
	js	@@test
	loop	@@wait

@@no_sb:
	stc
	mov	ax,SB_NOT_FOUND
	ret

@@test:
	sub	dx,4
	in	al,dx
	cmp	al,0aah
	jne	@@no_sb

	add	dx,2
	call	waitsb
	mov	al,0E1h
	out	dx,al

	add	dx,2
	call	readsb
	mov	ah,al
	add	dx,4
	call	readsb
	mov	[DspVer],ax

	add	dx,4
	mov	[cs:OFFSET port_sb+1],dx
	mov	[cs:OFFSET port_sb3+1],dx
	sub	dx,0eh
	mov	[(DEVICE ptr ds:si).port],dx

	mov	al,20h
	cmp	[(DEVICE ptr ds:si).irq],8
	jb	@@first_pic
	mov	al,0A0h
@@first_pic:
	mov	[cs:OFFSET port_irq+1],al
	mov	[cs:OFFSET port_irq3+1],al

	xor	al,al 		;efface la bascule interne
	out	0ch,al

	xor	dx,dx
	mov	al,[(DEVICE PTR ds:si).dma]
	mov	dl,al
	add	dl,al
	or	al,4  		;masque le canal DMA
	out	0ah,al

	and 	al,0FBh
	or	al,58h
	out	0bh,al		;choix du mode

	mov	ax,cs
	mov     cx,ax
	shr	ch,4
	shl	ax,4
	add	ax,OFFSET SoundBuf
	cmp	ax,65536-BUF_LEN
	jb	@@ok1
	add	ax,BUF_LEN
	adc	ch,0
	mov	bx,OFFSET SoundBuf
	mov	[word ptr cs:OFFSET soundbuf1b+2],bx
	mov	[word ptr cs:OFFSET soundbuf2b+2],bx
	mov	[word ptr cs:OFFSET soundbuf3b+2],bx
	inc	bx
	mov	[word ptr cs:OFFSET soundbuf4b+2],bx
	mov	[word ptr cs:OFFSET soundbuf5b+2],bx
	add	bx,BUF_LEN
	mov	[word ptr cs:OFFSET soundbuf4+2],bx
	mov	[word ptr cs:OFFSET soundbuf5+2],bx
	mov	[word ptr cs:OFFSET soundbuf7+2],bx
	dec	bx
	mov	[word ptr cs:OFFSET soundbuf1+2],bx
	mov	[word ptr cs:OFFSET soundbuf2+2],bx
	mov	[word ptr cs:OFFSET soundbuf3+2],bx
	mov	[word ptr cs:OFFSET soundbuf6+2],bx
@@ok1:

	out	dx,al		; place l'adresse de base
	mov	al,ah
	out	dx,al
	mov	ax,BUF_LEN
	dec	ax
	inc	dx
	out	dx,al		; place la longueur du bloc
	mov	al,ah
	out	dx,al
	mov    	bx,OFFSET DmaPage
	mov	al,[(DEVICE PTR ds:si).dma]
	xlat
	mov	dl,al
	mov	al,ch
	out	dx,al

	mov     cl,[NbVoice]
	mov     al,cl
	mov     ah,-1
@@find_msbit:
	inc     ah
	shr     al,1
	jne     @@find_msbit
	mov     [cs:OFFSET nbvoicediv1+2],ah
	mov     [cs:OFFSET nbvoicediv2+2],ah
	call    caloptvoltab

	clc

	ret

ENDP

;***************************************************************************
;*	routine permettant de d‚marrer l'envoit du son sur la soundblaster

PROC	startsb

	mov	ax,[VoicesLen]
	xor	cl,cl
@@search_msb:
	inc	cl
	shr	ax,1
	jne	@@search_msb
	sub    	cl,2
	mov	ax,1
	shl	ax,cl
	mov	[SbLen],ax

	mov	ax,OFFSET soundsing
	cmp	[DspVer],200h
	jbe	@@old_sb
	mov	ax,OFFSET soundauto
@@old_sb:
	mov	dx,cs
	mov	bl,[(DEVICE PTR ds:si).irq]
	call	setirq

	mov	al,[(DEVICE PTR ds:si).dma]
	out	0ah,al		; autorise le canal DMA

	mov     dx,1
	mov	ax,086A0h	;1000000/frequence
	div	[MixRate]
	neg	ax
	mov	ah,al

	mov	dx,[(DEVICE PTR ds:si).port]
	add	dx,04
	mov	al,0Eh		; Enleve le filtre de sortie pour f>36Khz
	out	dx,al
	inc	dx
	in	al,dx
	and	al,0DFh
	cmp	[ds:MixRate],NO_FILTER
	jbe	@@filter_on
	or	al,20h
@@filter_on:
	out	dx,al

	dec	dx	      	; regle la fr‚quence du filtre
	mov	al,0Ch
	out	dx,al
	inc	dx
	in	al,dx
	and	al,0F7h
	cmp	[ds:MixRate],LOW_FILTER
	jbe	@@filter32
	or	al,08h
@@filter32:
	out	dx,al

	add	dx,07h
	call	waitsb
	mov	al,0d1h
	out	dx,al			; allume le haut parleur

	call	waitsb
	mov	al,40h
	out	dx,al
	call	waitsb
	mov	al,ah
	out	dx,al		; regle la fr‚quence

     cmp  [DspVer],200h
     ja   @@new_sb

	call	waitsb
	mov	al,14h
	out	dx,al		; met en marche le transfert
	call	waitsb
	mov	ax,[ds:SbLen]
	dec	ax
	out	dx,al
	call	waitsb
	mov	al,ah
	out	dx,al

	ret

@@new_sb:

	call	waitsb
	mov	al,48h
	out	dx,al
	call	waitsb
	mov	ax,[cs:SbLen]
	dec	ax
	out 	dx,al
	call	waitsb
	mov	al,ah
	out	dx,al

	call	waitsb
	mov	al,90h
	out	dx,al

	ret

ENDP

;**************************************************************************
;*	cette proc‚dure est en fait un bloc que l'on doit mettre …
;*	l'adresse Voices

PROC	makesb FAR

	mov	cl,[NbVoice]
	sub	cl,2
	push	cx

	mov	di,OFFSET Voice1
	mov     dx,[(VOICE PTR di).effet]
	call    dx

	mov	di,[ds:OFFSET SoundPage]

	mov	bx,[(VOICE PTR Voice1).play]
	shl	bx,1
	xor	edx,edx
	mov	dx,[word ptr ds:bx+OFFSET Notes]

	ror	edx,10
	mov	cx,[(VOICE PTR Voice1).samplen]
	les	esi,[(VOICE PTR Voice1).adrvoc]
	mov	bx,[(VOICE PTR Voice1).replen]
	cmp	si,cx
	jbe	@@ok1
@@adjust1:
	sub	si,bx
	cmp	si,cx
	ja	@@adjust1
@@ok1:

	mov	bx,OFFSET VolumeTab
	mov	al,[MasterVol]
	and	al,[(VOICE PTR Voice1).mute]
	mul	[(VOICE PTR Voice1).volume]
	add	bh,ah

	push	ebp
@@voix1:
	add     esi,edx
	mov	al,[byte ptr es:si]
	adc	esi,edx
	xlat
	mov	ah,al
	mov	al,[byte ptr es:si]
	adc	si,0
	xlat
soundbuf1:
	mov	[ds:di+OFFSET SoundBuf],ax
soundbuf1b:
	mov	[word ptr ds:di+OFFSET SoundBuf+BUF_LEN],0
	add	di,2

	cmp	di,bp
	jne	@@voix1
	rol	ebp,16
	xor	di,di
	cmp	bp,BUF_LEN
	jne	@@voix1
	pop	ebp

	mov	[dword ptr ((VOICE PTR Voice1).adrvoc)],esi

	pop	cx
	mov	di,OFFSET Voice1+SIZE VOICE
@@next_voice:
	push	cx
	mov     dx,[(VOICE ptr ds:di).effet]
	call    dx

	mov	bx,[(VOICE ptr ds:di).play]
	shl	bx,1
	xor	edx,edx
	mov	dx,[word ptr ds:bx+OFFSET Notes]
	ror	edx,10
	mov	cx,[(VOICE ptr ds:di).samplen]
	les	esi,[(VOICE ptr ds:di).adrvoc]
	mov	bx,[(VOICE ptr ds:di).replen]
	cmp	si,cx
	jbe	@@ok2
@@adjust2:
	sub	si,bx
	cmp	si,cx
	ja	@@adjust2
@@ok2:

	mov	bx,OFFSET VolumeTab
	mov	al,[MasterVol]
	and	al,[(VOICE PTR ds:di).mute]
	mul	[(VOICE PTR ds:di).volume]
	add	bh,ah

	push	di

	push	ebp
	mov	di,[ds:OFFSET SoundPage]
@@voix2:
	add     esi,edx
	mov	al,[byte ptr es:si]
	adc	esi,edx
	xlat
	mov	ah,al
	mov	al,[byte ptr es:si]
	adc	si,0
	xlat
soundbuf2:
	add	[ds:di+OFFSET SoundBuf],al
soundbuf2b:
	adc	[byte ptr ds:di+OFFSET SoundBuf+BUF_LEN],0
soundbuf4:
	add	[ds:di+OFFSET SoundBuf+1],ah
soundbuf4b:
	adc	[byte ptr ds:di+OFFSET SoundBuf+BUF_LEN+1],0
	add	di,2

	cmp	di,bp
	jne	@@voix2
	rol	ebp,16
	xor	di,di
	cmp	bp,BUF_LEN
	jne	@@voix2
	pop	ebp


	pop	di
	mov	[dword ptr ((VOICE ptr ds:di).adrvoc)],esi
	add	di,SIZE VOICE
	pop	cx
	dec	cl
	jne	@@next_voice

	mov     dx,[(VOICE ptr ds:di).effet]
	call    dx

	mov	bx,[(VOICE ptr ds:di).play]
	shl	bx,1
	xor	edx,edx
	mov	dx,[word ptr ds:bx+OFFSET Notes]
	ror	edx,10
	mov	cx,[(VOICE ptr ds:di).samplen]
	les	esi,[(VOICE ptr ds:di).adrvoc]
	mov	bx,[(VOICE ptr ds:di).replen]
	cmp	si,cx
	jbe	@@ok4
@@adjust4:
	sub	si,bx
	cmp	si,cx
	ja	@@adjust4
@@ok4:

	mov	bx,OFFSET VolumeTab
	mov	al,[MasterVol]
	and	al,[(VOICE ptr ds:di).mute]
	mul	[(VOICE ptr ds:di).volume]
	add	bh,ah

	push	di
	mov	di,[ds:OFFSET SoundPage]
	xor	ah,ah
@@voix4:
	add     esi,edx
	mov	al,[byte ptr es:si]
	adc	si,0
	xlat
soundbuf3:
	add	al,[ds:di+OFFSET SoundBuf]
soundbuf3b:
	adc	ah,[ds:di+OFFSET SoundBuf+BUF_LEN]
nbvoicediv1:
	shr	ax,2

soundbuf6:
	mov	[byte ptr ds:di+OFFSET SoundBuf],al
	add	esi,edx
	mov	al,[byte ptr es:si]
	adc	si,0
	xlat
soundbuf5:
	add	al,[ds:di+OFFSET SoundBuf+1]
soundbuf5b:
	adc	ah,[ds:di+OFFSET SoundBuf+BUF_LEN+1]
nbvoicediv2:
	shr	ax,2

soundbuf7:
	mov	[byte ptr ds:di+OFFSET SoundBuf+1],al
	add	di,2

	cmp	di,bp
	jne	@@voix4
	rol	ebp,16
	xor	di,di
	cmp	bp,BUF_LEN
	jne	@@voix4

	pop	di
	mov	[dword ptr ((VOICE ptr ds:di).adrvoc)],esi

@@fin4voice:

	shr	ebp,16
	and	bp,65535-BUF_LEN
	mov	[word ptr ds:OFFSET SoundPage],bp
	mov	[byte ptr cs:OFFSET switch_makemod],1Eh

	pop	edi
	pop	esi
	pop	ebp
	pop	es
	pop	ds

	ret

ENDP

;***************************************************************************
;*	Cette routine remplace d'interruption de la sound blaster

PROC	soundsing

	push	ax
	push	dx

port_sb:
	mov	dx,22eh
	in	al,dx
	sub	dx,2

@@wait1:
	in	al,dx
	or	al,al
	js	@@wait1
	mov	al,14h
	out	dx,al

@@wait2:
	in	al,dx
	or	al,al
	js	@@wait2
	mov	ax,[cs:SbLen]
	add	[cs:SoundPtr],ax
	and     [cs:SoundPtr],65535-BUF_LEN
	dec	ax
	out 	dx,al

@@wait3:
	in	al,dx
	or	al,al
	js	@@wait3
	mov	al,ah
	out	dx,al

	mov	al,20h
	out	20h,al
port_irq:
	out	20h,al
	pop	dx

	mov	ax,[cs:SbLen]
	sub	[cs:Count],ax
	jle	@@imakemod
	pop	ax

	iret

@@imakemod:
	mov	ax,[cs:VoicesLen]
	add	[cs:Count],ax
	pop	ax

	jmp	IMAKEMOD

ENDP

;***************************************************************************
;*	Cette routine remplace d'interruption de la sound blaster

PROC	soundauto

	push	ax
	push	dx

port_sb3:
	mov	dx,22eh
	in	al,dx

	mov	ax,[cs:SbLen]
	add	[cs:SoundPtr],ax
	and     [cs:SoundPtr],65535-BUF_LEN

	mov	al,20h
	out	20h,al
port_irq3:
	out	20h,al
	pop	dx

	mov	ax,[cs:SbLen]
	sub	[cs:Count],ax
	jle	@@imakemod
	pop	ax

	iret

@@imakemod:
	mov	ax,[cs:VoicesLen]
	add	[cs:Count],ax
	pop	ax

	jmp	IMAKEMOD

ENDP

;***************************************************************************
;*	Cette routine permet d'arreter l'envoit du son sur une soundblaster

PROC	stopsb

	call	resetsb

	mov	al,[(DEVICE PTR ds:si).dma]      ; masque le canal DMA
	or	al,4
	out	0ah,al

	add	dx,6
	call	waitsb
	mov	al,0d3h
	out	dx,al		; ‚teint le haut parleur

	sub	dx,08
	mov	al,0Eh		; remet le filtre
	out	dx,al
	inc	dx
	in	al,dx
	and	al,0DFh
	out	dx,al

	dec	dx    		; remet le filtre … 3.2Khz
	mov	al,0Ch
	out	dx,al
	inc	dx
	in	al,dx
	and	al,0F7h
	out	dx,al

	ret

ENDP

ENDS

END