;***************************************************************************
;*	Driver pour la Sound Blaster Pro sortie 8 bits stereo
;*
;* Programm‚ par S‚bastien Granjoux
;* Commenc‚ le 11/01/95
;* Modification le 11/01/95

IDEAL
P386N

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

PUBLIC	USESP

SEGMENT CODE PARA PUBLIC USE16 'CODE'

ASSUME cs:CODE,ds:CODE

NO_FILTER	EQU	3600
LOW_FILTER	EQU	1800

;*************************************************************************
;*	Fonction de detection du driver

PROC	USESP

	call	USEDEVICE
	DEVICE <05h,'BLASTERs=ApIiDdTt45$',OFFSET setsp,OFFSET startsp,OFFSET stopsp,OFFSET makesp,OFFSET defbpmsp,OFFSET peekdef,0,0,1>

ENDP

Stereo	DB	80h	; 00 Stereo activ‚ 80h Stereo d‚activ‚
SbLen	DW ?
OldInt	DD	0
DspVer   DW 	0
Count	DW	0
DmaPage	DB	87h,83h,82h,81h

;***************************************************************************
;*	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,256	;compte des moutons pendant au moins 3æs
@@compte:
	loop	@@compte
	dec	al
	out	dx,al
	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

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

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

PROC	setsp

	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

	cmp	ax,300h		; Numero de version
	jae	@@sb_pro

	stc
	mov	ax,SB_NOT_FOUND
	ret

@@sb_pro:
	mov	[DspVer],ax

	add	dx,4
	mov	[cs:OFFSET port_sb+1],dx
	mov	[cs:OFFSET port_sb2+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_irq2+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 autoinitialis‚

	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 soundbuf3b0+2],bx
	mov	[word ptr cs:OFFSET soundbuf8b0+2],bx
	mov	[word ptr cs:OFFSET soundbuf16b0+2],bx
	inc	bx
	mov	[word ptr cs:OFFSET soundbuf12b1+2],bx
	mov	[word ptr cs:OFFSET soundbuf22b1+2],bx
	inc	bx
	mov	[word ptr cs:OFFSET soundbuf6b2+2],bx
	mov	[word ptr cs:OFFSET soundbuf10b2+2],bx
	mov	[word ptr cs:OFFSET soundbuf19b2+2],bx
	inc	bx
	mov	[word ptr cs:OFFSET soundbuf14b3+2],bx
	mov	[word ptr cs:OFFSET soundbuf25b3+2],bx
	add	bx,BUF_LEN
	mov	[word ptr cs:OFFSET soundbuf5a3+2],bx
	mov	[word ptr cs:OFFSET soundbuf13a3+2],bx
	mov	[word ptr cs:OFFSET soundbuf24a3+2],bx
	mov	[word ptr cs:OFFSET soundbuf26a3+2],bx
	dec	bx
	mov	[word ptr cs:OFFSET soundbuf2a2+2],bx
	mov	[word ptr cs:OFFSET soundbuf9a2+2],bx
	mov	[word ptr cs:OFFSET soundbuf18a2+2],bx
	mov	[word ptr cs:OFFSET soundbuf20a2+2],bx
	dec	bx
	mov	[word ptr cs:OFFSET soundbuf4a1+2],bx
	mov	[word ptr cs:OFFSET soundbuf11a1+2],bx
	mov	[word ptr cs:OFFSET soundbuf21a1+2],bx
	mov	[word ptr cs:OFFSET soundbuf23a1+2],bx
	dec	bx
	mov    	[word ptr cs:OFFSET soundbuf1a0+2],bx
	mov	[word ptr cs:OFFSET soundbuf7a0+2],bx
	mov	[word ptr cs:OFFSET soundbuf15a0+2],bx
	mov	[word ptr cs:OFFSET soundbuf17a0+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  [Stereo],80h

	mov     cl,[NbVoice]
	inc	cl
	shr     cl,1
	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
	mov     [cs:OFFSET nbvoicediv1b+2],ah
	mov     [cs:OFFSET nbvoicediv2b+2],ah
	call    caloptvoltab

	clc

	ret

ENDP

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

PROC	startsp

	cmp	[DspVer],400h
	jae	@@no_setstereo
	cmp	[Stereo],0
	je	@@no_setstereo
	call	setstereo
@@no_setstereo:

	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	dx,cs
	mov	ax,OFFSET soundsp
	mov	bl,[(DEVICE PTR ds:si).irq]
	call	setirq

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

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

	mov	dx,[(DEVICE PTR ds:si).port]

	add	dx,04        	; mixer en mode stereo
	mov	al,0Eh
	out	dx,al
	inc	dx
	in	al,dx
	or	al,2
	out	dx,al

	dec	dx
	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,7
	call	waitsb
	mov	al,0d1h
	out	dx,al			; allume le haut parleur

	cmp	[DspVer],400h
	jae	@@sb16

	call	waitsb		; RŠgle la fr‚quence
	mov	al,40h
	out	dx,al
	call	waitsb
	mov  	al,ah
	out	dx,al

	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

@@sb16:
	call	waitsb
	mov	al,41h
	mov	ax,[ds:MixRate]
	lea	ax,[eax*4+eax]
	add	ax,ax
	xchg	al,ah
	out	dx,al
	call	waitsb
	mov	al,ah
	out	dx,al

	call	waitsb
	mov	al,0C6h
	out	dx,al

	call	waitsb
	mov     al,20h
	out	dx,al

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

	ret
ENDP

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

PROC	makesp FAR

	mov	cl,[NbVoice]
	sub	cl,4
	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
soundbuf1a0:
	mov	[ds:di+OFFSET SoundBuf],al
soundbuf2a2:
	mov	[ds:di+OFFSET SoundBuf+2],ah
soundbuf3b0:
	mov	[word ptr ds:di+OFFSET SoundBuf+BUF_LEN],0
	add	di,4

	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

	mov	di,OFFSET Voice1+SIZE VOICE
	mov     dx,[(VOICE PTR 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	@@ok1b
@@adjust1b:
	sub	si,bx
	cmp	si,cx
	ja	@@adjust1b
@@ok1b:

	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]
	push	ebp
@@voix1b:
	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
soundbuf4a1:
	mov	[ds:di+OFFSET SoundBuf+1],al
soundbuf5a3:
	mov	[ds:di+OFFSET SoundBuf+3],ah
soundbuf6b2:
	mov	[word ptr ds:di+OFFSET SoundBuf+BUF_LEN+2],0
	add	di,4

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

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

	pop	cx
	add	di,SIZE VOICE
	inc	cl
	shr	cl,1
	je	@@end_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
soundbuf7a0:
	add	[ds:di+OFFSET SoundBuf],al
soundbuf8b0:
	adc	[byte ptr ds:di+OFFSET SoundBuf+BUF_LEN],0
soundbuf9a2:
	add	[ds:di+OFFSET SoundBuf+2],ah
soundbuf10b2:
	adc	[byte ptr ds:di+OFFSET SoundBuf+BUF_LEN+2],0
	add	di,4

	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

	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	@@ok2b
@@adjust2b:
	sub	si,bx
	cmp	si,cx
	ja	@@adjust2b
@@ok2b:

	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]
@@voix2b:
	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
soundbuf11a1:
	add	[ds:di+OFFSET SoundBuf+1],al
soundbuf12b1:
	adc	[byte ptr ds:di+OFFSET SoundBuf+BUF_LEN+1],0
soundbuf13a3:
	add	[ds:di+OFFSET SoundBuf+3],ah
soundbuf14b3:
	adc	[byte ptr ds:di+OFFSET SoundBuf+BUF_LEN+3],0
	add	di,4

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


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

	pop	cx
	dec	cl
	jne	@@next_voice

@@end_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	@@ok4b
@@adjust4b:
	sub	si,bx
	cmp	si,cx
	ja	@@adjust4b
@@ok4b:

	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
	push	ebp
@@voix4b:
	add     esi,edx
	mov	al,[byte ptr es:si]
	adc	si,0
	xlat
soundbuf15a0:
	add	al,[ds:di+OFFSET SoundBuf]
soundbuf16b0:
	adc	ah,[ds:di+OFFSET SoundBuf+BUF_LEN]
nbvoicediv1b:
	shr	ax,2
soundbuf17a0:
	mov	[byte ptr ds:di+OFFSET SoundBuf],al
	add	esi,edx
	mov	al,[byte ptr es:si]
	adc	si,0
	xlat
soundbuf18a2:
	add	al,[ds:di+OFFSET SoundBuf+2]
soundbuf19b2:
	adc	ah,[ds:di+OFFSET SoundBuf+BUF_LEN+2]
nbvoicediv2b:
	shr	ax,2
soundbuf20a2:
	mov	[byte ptr ds:di+OFFSET SoundBuf+2],al
	add	di,4

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

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

	add	di,SIZE 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
soundbuf21a1:
	add	al,[ds:di+OFFSET SoundBuf+1]
soundbuf22b1:
	adc	ah,[ds:di+OFFSET SoundBuf+BUF_LEN+1]
nbvoicediv1:
	shr	ax,2

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

soundbuf26a3:
	mov	[byte ptr ds:di+OFFSET SoundBuf+3],al
	add	di,4

	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 5

PROC	soundsp

	push	ax
	push	dx

port_sb:
	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_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 permet d'arreter l'envoit du son sur une soundblaster

PROC	stopsp

	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		; enleve le mode stereo
	mov	al,0Eh
	out	dx,al
	inc	dx
	in	al,dx
	and	al,0FDh
	out	dx,al

	dec	dx
	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

;***********************************************************************
;*	Passe en mode stereo

PROC	setstereo

	mov	dx,cs
	mov	ax,OFFSET setstereoirq
	mov	bl,[(DEVICE PTR ds:si).irq]
	call	setirq

	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,48h		; choix du mode (transfert simple)
	out	0bh,al

	in	al,dx
	mov     bl,al
	in	al,dx
	mov	bh,al
	push	bx
	inc	dx
	in	al,dx
	mov	bl,al
	in	al,dx
	mov	bh,al
	push	bx
	push	dx
	mov    	bx,OFFSET DmaPage
	mov	al,[(DEVICE PTR ds:si).dma]
	xlat
	mov	dl,al
	in	al,dx
	pop	dx
	push	ax


	mov	ax,cs		; calcul l'adresse DMA
	mov     cx,ax
	shr	ch,4
	shl	ax,4
	add	ax,OFFSET Stereo
	adc	ch,0
	dec	dx
	out	dx,al		; place l'adresse de base
	mov	al,ah
	out	dx,al
	xor	al,al		; place la longueur du bloc-1
	inc	dx
	out	dx,al
	xor	al,al
	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	al,[(DEVICE PTR ds:si).dma]
	out	0ah,al		; autorise le canal

	mov	dx,[(DEVICE PTR ds:si).port]
	add	dx,0Ch

	call	waitsb		; RŠgle la fr‚quence
	mov	al,40h
	out	dx,al

	call	waitsb
     mov  al,0D2h
     out  dx,al

	mov	dx,[(DEVICE PTR ds:si).port]	; place le mode stereo
	add	dx,04
	mov	al,0Eh
	out	dx,al
	inc	dx
	in	al,dx
	or	al,2
	out	dx,al

	add	dx,7 		; met en marche le transfert
	call	waitsb
	mov	al,14h
	out	dx,al
	call	waitsb
	xor	al,al
	out	dx,al
	call	waitsb
	xor	al,al
	out	dx,al

@@wait:
	cmp	[Stereo],0
	jne	@@wait

	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

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

	ret

setstereoirq:
	push	ax
	push	dx

port_sb2:
	mov	dx,20Eh
	in	al,dx
	mov	[cs:Stereo],0
	mov	al,20h
	out	20h,al
port_irq2:
	out	20h,al
	pop	dx
	pop	ax
	iret

ENDP

;***************************************************************************
;*	Change la vitesse en BPM
;*
;* Entr‚e:
;*	AL	nouvelle vitesse

PROC	defbpmsp

	movzx	cx,al
	mov	ax,[MixRate]
	mov	dx,25
	mul	dx
	div	cx
	inc	ax
	and	ax,0fffch
	shl	ax,1
	mov	[VoicesLen],ax
	ret

ENDP


ENDS

END