;***************************************************************************
;*	Driver pour le DAC avec des calculs 10bits
;*
;* Programm‚ par S‚bastien Granjoux
;* Commenc‚ le 03/01/95
;* Modification le 03/01/95

IDEAL
P386N

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

PUBLIC	USEDAC

BIOSSEG	EQU	40h
LPT1ADR	EQU	08h

SEGMENT CODE PARA PUBLIC USE16 'CODE'

ASSUME cs:CODE,ds:CODE

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

PROC	USEDAC

	call	USEDEVICE
	DEVICE <02h,'DACs=p$',OFFSET setdac,OFFSET startdac,OFFSET stopdac,OFFSET makedac,OFFSET defbpm,OFFSET peekdef,0,0,0>

ENDP

Counter 	DD	0
Count		DD	0
OtherCount	DW	0

;**************************************************************************
;*	Routine d'initialisation du DAC
;*
;* Entr‚e:
;*	DS:SI	adresse de la structure device (port de 1 … 4 inclus)
;*
;* Sortie:
;*	AX	code d'erreur si C=1

PROC	setdac

	mov	[(DEVICE PTR ds:si).irq],0
	mov	bx,[(DEVICE ptr ds:si).port]
	mov	ax,BIOSSEG
	mov	es,ax
	shl	bx,1
	mov	ax,[es:bx+LPT1ADR-2]
	or	ax,ax
	je	@@no_lpt
	mov	[cs:OFFSET port_dac+1],ax

	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

@@no_lpt:
	mov	ax,DAC_NOT_FOUND
	stc
	ret

ENDP

;***************************************************************************
;*	Cette routine permet de commencer l'envoit du son sur un DAC
;*
;* Entr‚e:
;*	DS:BX	adresse de la structure DEVICE

PROC	startdac

	cli
	mov	dx,cs
	mov	ax,OFFSET sounddac
	xor	bl,bl
	call	setirq

	mov	al,00110110b
	out     43h,al
	jmp	$+2
	jmp	$+2

	mov	dx,1
	mov	ax,0D216h

	div	[ds:MixRate]

	out     40h,al
	jmp	$+2
	jmp	$+2
	rol     ax,8
	out     40h,al
	jmp	$+2
	jmp	$+2
	rol	ax,8

	movzx	ecx,ax
	mov	eax,80000000h
	xor	edx,edx
	div	ecx
	add	eax,eax

	mov	[ds:Counter],eax
	shr	eax,16
	mov	[ds:OtherCount],ax
	mov	ax,[ds:VoicesLen]
	sub	[ds:OtherCount],ax
	mov	[ds:Count],1

;	call	setautoeoi

	sti

	ret
ENDP

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

PROC	makedac 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
	mov	[ds:di+OFFSET SoundBuf],ax
	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
	add	[ds:di+OFFSET SoundBuf],al
	adc	[byte ptr ds:di+OFFSET SoundBuf+BUF_LEN],0
	add	[ds:di+OFFSET SoundBuf+1],ah
	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
	add	al,[ds:di+OFFSET SoundBuf]
	adc	ah,[ds:di+OFFSET SoundBuf+BUF_LEN]
nbvoicediv1:
	shr	ax,2

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

	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

;***************************************************************************
;*      interruption 8 permettant d'envoyer le son sur un port parallŠle

PROC    sounddac FAR

	push	ax
	push	bx

	mov	bx,[cs:OFFSET SoundPtr]
	inc	bx
	and	bx,65535-BUF_LEN
	mov	[cs:OFFSET SoundPtr],bx
	mov	al,[cs:bx+OFFSET SoundBuf]

	mov	bx,dx
port_dac:
	mov	dx,378h
	out	dx,al
	mov	dx,bx

	pop	bx
	dec	[word cs:OFFSET Count+2]
irq_switch:
	jle	@@imakemod

	mov	al,60h
	out	20h,al

	pop	ax
	iret

@@int08:
	mov	ax,[word ptr cs:OFFSET Counter+2]
	xchg	ax,[cs:OtherCount]
	add     [cs:OFFSET Count+2],ax
	sub	[cs:OtherCount],ax
	add	[byte ptr cs:OFFSET irq_switch+1],OFFSET @@imakemod - OFFSET @@int08

	pop	ax
	jmp	[dword ptr cs:OldIrq]

@@imakemod:

	mov	al,60h
	out	20h,al

	mov	ax,[cs:VoicesLen]
	cmp	ax,[cs:OtherCount]
	jb	@@next_make
	xchg	ax,[cs:OtherCount]
	sub	[cs:OtherCount],ax
	mov	[cs:OFFSET Count+2],ax
	mov	ax,[word ptr cs:Counter]
	add	[cs:OFFSET Count],ax
	sub	[byte ptr cs:OFFSET irq_switch+1],OFFSET @@imakemod - OFFSET @@int08
	pop	ax

	jmp	IMAKEMOD

@@next_make:
	sub	[cs:OtherCount],ax
	add	[word ptr cs:OFFSET Count+2],ax
	pop	ax

	jmp	IMAKEMOD

ENDP

;***************************************************************************
;*	Cette routine permet d'arreter l'envoit du son sur un DAC

PROC	stopdac

	cli
	mov     al,00110110b
	out     43h,al
	xor	al,al
	out     40h,al
	out     40h,al

;	call	reseteoi

	ret

ENDP

ENDS

END