;***************************************************************************
;*	Driver pour le PC speaker
;*
;* Programm‚ par S‚bastien Granjoux
;* Commenc‚ le 07/01/95
;* Modification le 07/01/95

IDEAL
P386N

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

PUBLIC	USESPK
PUBLIC	setspk
PUBLIC	startspk
PUBLIC	makespk
PUBLIC	stopspk
PUBLIC	defbpmspk

SEGMENT CODE PARA PUBLIC USE16 'CODE'

ASSUME cs:CODE,ds:CODE

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

PROC	USESPK

	call	USEDEVICE
	DEVICE <01h,'$',OFFSET setspk,OFFSET startspk,OFFSET stopspk,OFFSET makespk,OFFSET defbpmspk,OFFSET peekdef,0,0,0>

ENDP

Counter         DD      0
Count           DD      0
OtherCount      DW      0

;***************************************************************************
;*	routine permettant d'initialiser le speaker

PROC	setspk

        mov	[(DEVICE PTR ds:si).irq],0
	shr	[MixRate],1

	mov	cl,[NbVoice]
	call	calvoltab

	clc
	ret
ENDP

;***************************************************************************
;*	routine permettant de d‚marrer l'envoit du son sur le speaker

PROC	startspk

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

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

	mov	dx,1
	mov	ax,0D216h
	div	[ds:MixRate]
	shr	ax,1

	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

	mov	al,10010000b
	out     43h,al
	jmp	$+2
	jmp	$+2
	in      al,61h
	jmp	$+2
	jmp	$+2
	or      al,11b
	out     61h,al
	jmp	$+2
	jmp	$+2

;	call	setautoeoi
	sti

	ret

ENDP

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

PROC	makespk FAR

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


	mov	di,OFFSET Voice1
	mov     dx,[Voice1.effet]
	call    dx
	mov	di,[ds:OFFSET SoundPage]

	mov	bx,[Voice1.play]
	shl	bx,1
	xor	edx,edx
	mov	dx,[word ptr ds:bx+OFFSET Notes]
	ror	edx,10
	mov	cx,[Voice1.samplen]
	les	esi,[Voice1.adrvoc]
	mov	bx,[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,[Voice1.mute]
	mul	[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
	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 OFFSET 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]
	mov	bx,OFFSET VolumeTab
	mov	al,[MasterVol]
	and	al,[(VOICE PTR ds:di).mute]
	mul	[(VOICE ptr ds:di).volume]
	add	bh,ah
	mov	ax,[(VOICE ptr ds:di).replen]
	push	di
	les	esi,[(VOICE ptr ds:di).adrvoc]
	cmp	si,cx
	jbe	@@ok2
@@adjust2:
	sub	si,ax
	cmp	si,cx
	ja	@@adjust2
@@ok2:

	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
	add	[ds:di+OFFSET SoundBuf+1],ah
	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

	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]

@@voix4:
	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     al,[ds:di+OFFSET SoundBuf]
	add	ah,[ds:di+OFFSET SoundBuf+1]
	mov	[ds:di+OFFSET SoundBuf],ah
	mov	[ds:di+OFFSET SoundBuf+1],ah
	mov	ah,al
	mov	[ds:di+OFFSET SoundBuf+2],ax
	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

@@fin4voix:

	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 le speaker

PROC    soundspk FAR

	push      eax
	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,OFFSET AMPLI8
	xlat	[cs:bx]
	out	42h,al

	pop	bx

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

	mov	al,20h
	out	20h,al

	pop	eax
	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     eax
	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
        shl     eax,16
        mov     ax,[word ptr cs:Counter]
        add     [cs:OFFSET Count],eax
	sub     [byte ptr cs:OFFSET irq_switch+1],OFFSET @@imakemod - OFFSET @@int08
	pop     eax

        jmp     IMAKEMOD

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

	jmp     IMAKEMOD

ENDP

;***************************************************************************
;*	cette routine permet d'arreter l'envoit du son sur le speaker

PROC	stopspk

	in	al,61h
	and     al,11111100b
	out	61h,al

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

;	call	reseteoi

	ret

ENDP

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

PROC	defbpmspk

	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