;°±²ÛßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÛ²±°
;°±²Û  ASIO package				   Driver for StereoThing  Û²±°
;°±²Û  (C)opyright 1992 by FRIENDS software	      All rights reserved  Û²±°
;°±²ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ²±°

		.186

Driver          Segment Byte
                Assume  cs:Driver, ds:Driver
                ORG     65*256-20-20-2-2-2-26

; Driver header. Note that it isn't loaded into memory and must be ignored
; by driver itself.
DriverDescr     db      'Stereo Thing/9 bit',0,0
Programmer	db	'Andrew Zabolotny',0,0,0,0
DeviceFlags     dw      1000000000000010b       ; Two voices
MemoryNeed	dw	offset DriverEnd
StartOffset     dw      65*256                  ; Preserve 16k of memory for
                                                ; volume table.
OffsetTable     dw      offset Init
                dw      offset SetPorts
                dw      offset SetTempo
                dw      offset StartPlay
                dw      offset SetFreq
                dw      offset SetVolume
                dw      offset SetSample
                dw      offset SetGlobalVolume
                dw      offset GetSamples
		dw	offset Dummy
		dw	offset Dummy
                dw      offset Dummy
                dw      offset Dummy

VolTable        equ     0                       ; Offset of volume table

TimerFreq       dw      04Bh                    ; Frequence of IRQ0
Samples 	dw	0,0			; Four pointers
		dw	0,0			; to samples for
		dw	0,0			; each voice.
		dw	0,0
CFreq		dw	0,0,0,0
InsFB		dw	0,0,0,0 		; Offset of first byte
						; in loop for each sample
InsLB		dw	0,0,0,0 		; 0FFFFh if no loop or offset
						; of last byte in loop.
ShutDown        dw      0,0                     ; Pointer to a array of flags
                                                ; that mean that sample are
                                                ; finished.
GVolume         db      64                      ; Global volume
Temp		dw	0
DecTemp 	dw	0
;Û Offsets of variables in self-modifying code Û
;Û     Segment of this variables is CS:        Û
FreqOfs 	dw	offset Freq1,offset Freq2
		dw	offset Freq3,offset Freq4
InsEOfs 	dw	offset InsE1,offset InsE2
		dw	offset InsE3,offset InsE4
HWordOfs	dw	offset HiWord1,offset HiWord2
		dw	offset HiWord3,offset HiWord4
VolumeOfs	dw	offset Volume1,offset Volume2
		dw	offset Volume3,offset Volume4

Init            proc    far
                pusha
                push    es
                mov     word ptr cs:ShutDown,bx ; Save pointer to array of
                mov     word ptr cs:ShutDown+2,es; flags...
                call    InitTable
                clc                             ; StereoThing can't be detected,
                pop     es                      ; so,assume that it's all right.
                popa
                ret
Init		endp

SetPorts        proc    far
                mov     cs:LeftDAC,bx
                mov     cs:RightDAC,dx
                retf
SetPorts	endp

SetTempo        proc    far
                mov     byte ptr cs:TimerFreq,al
                mov     cs:Temp,cx
                mov     cs:DecTemp,cx
                retf
SetTempo	endp

StartPlay       proc    far
                mov     cs:DecTemp,1
                mov     word ptr cs:Handler,dx
                mov     word ptr cs:Handler+2,es
		call	TimerInit
                retf
StartPlay	endp

SetFreq         proc    far
                push    bx
                push    di
                xor     bh,bh
		shl	bx,1
                mov     di,cs:FreqOfs[bx]
                mov     cs:[di],cx
                mov     di,cs:HWordOfs[bx]
                mov     cs:[di],dx
                pop     di
                pop     bx
                retf
SetFreq 	endp

SetVolume       proc    far
                push    ax
                push    bx
                xor     bh,bh
		shl	bx,1
                mov     al,cs:GVolume
		mul	dl
		shr	ax,6
                cmp     al,40h
                jbe     @SV1
                mov     al,040h
@SV1:           mov     bx,cs:VolumeOfs[bx]
                mov     cs:[bx],al
@SVret:         pop     bx
                pop     ax
                retf
SetVolume	endp

SetSample       proc    far
                push    ax
                push    bx
                push    si
                push    ds
                mov     ax,cs
                mov     ds,ax
                xor     bh,bh
		shl	bx,1
                mov     si,HWordOfs[bx]         ; Better dont't touch
                mov     word ptr [si],0         ; this sequence
                mov     si,FreqOfs[bx]          ; because on low-speed
                mov     word ptr [si],0         ; machines can appear
                shl     bx,1                    ; some truobles.
                mov     Samples[bx],di
                mov     Samples[bx+2],es
                shr     bx,1
                mov     InsLB[bx],cx
		mov	InsFB[bx],dx
                cmp     dx,0FFFFh
                jne     @@O1
                mov     InsLB[bx],dx
@@O1:           mov     si,InsEOfs[bx]
                mov     [si],cx
                pop     ds
                pop     si
                pop     bx
                pop     ax
                retf
SetSample	endp

SetGlobalVolume proc    far
                mov     cs:GVolume,al
                retf
SetGlobalVolume endp

GetSamples      proc
                push    cx
                push    di
                push    si
                push    ds
                push    cs
                pop     ds
                cld
                mov     si,offset Samples
                mov     cx,4*4
                rep     movsb
                pop     ds
                pop     si
                pop     di
                pop     cx
                retf
GetSamples      endp

Dummy		proc
		retf
Dummy           endp

Int08Entry      proc    far
@DoHandler:	mov	ax,Temp
                mov     DecTemp,ax
                db      09Ah
Handler         dw      0,0
		jmp	@Play

@ResetV1:	cmp	word ptr InsLB[0],0FFFFh
                je      @C1
                mov     bx,word ptr InsFB[0]
                mov     word ptr Samples[0],bx
                jmp     @L1
@C1:            xor     bx,bx
                mov     byte ptr Volume1,bl
                mov     word ptr Samples[0],bx
                les     bx,dword ptr ShutDown
                mov     byte ptr es:[bx],0
                jmp     @L1

@ResetV2:	cmp	word ptr InsLB[2],0FFFFh
                je      @C2
                mov     bx,word ptr InsFB[2]
                mov     word ptr Samples[4],bx
                jmp     @L2
@C2:            xor     bx,bx
                mov     byte ptr Volume2,bl
                mov     word ptr Samples[4],bx
                les     bx,dword ptr ShutDown
                mov     byte ptr es:[bx+1],0
                jmp     @L2

IntProc:	push	ax
                push    bx
                push    dx
		push	ds
		push	es
                mov     ax,cs
		mov	ds,ax
		dec	word ptr DecTemp
                jz      @DoHandler
@Play:
;	      Û Voice 1 Û
		add	word ptr CFreq[0],0DEADh
Freq1		equ	word ptr $-2
		adc	word ptr Samples[0],0DEADh
HiWord1 	equ	word ptr $-2
                les     bx,dword ptr Samples[0]
                cmp     bx,0DEADh
InsE1		equ	word ptr $-2
		jae	@ResetV1
@L1:            mov     bl,byte ptr es:[bx]
                mov     bh,00h
Volume1 	equ	byte ptr $-1
                mov     al,[bx]

;	      Û Voice 2 Û
		add	word ptr CFreq[2],0DEADh
Freq2		equ	word ptr $-2
		adc	word ptr Samples[4],0DEADh
HiWord2 	equ	word ptr $-2
                les     bx,dword ptr Samples[4]
                cmp     bx,0DEADh
InsE2		equ	word ptr $-2
		jae	@ResetV2
@L2:            mov     bl,byte ptr es:[bx]
                mov     bh,00h
Volume2 	equ	byte ptr $-1
                add     al,[bx]
                xor     al,80h
                mov     dx,5FE0h
LeftDAC         equ     word ptr $-2
                out     dx,al

;	      Û Voice 3 Û
		add	word ptr CFreq[4],0DEADh
Freq3		equ	word ptr $-2
		adc	word ptr Samples[8],0DEADh
HiWord3 	equ	word ptr $-2
                les     bx,dword ptr Samples[8]
                cmp     bx,0DEADh
InsE3		equ	word ptr $-2
		jae	@ResetV3
@L3:            mov     bl,byte ptr es:[bx]
                mov     bh,00h
Volume3 	equ	byte ptr $-1
                mov     al,[bx]

;	      Û Voice 4 Û
		add	word ptr CFreq[6],0DEADh
Freq4		equ	word ptr $-2
		adc	word ptr Samples[12],0DEADh
HiWord4 	equ	word ptr $-2
                les     bx,dword ptr Samples[12]
                cmp     bx,0DEADh
InsE4		equ	word ptr $-2
		jae	@ResetV4
@L4:            mov     bl,byte ptr es:[bx]
                mov     bh,00h
Volume4 	equ	byte ptr $-1
                add     al,[bx]

                xor     al,80h
                mov     dx,5FE2h
RightDAC        equ     word ptr $-2
                out     dx,al
		pop	es
		pop	ds
                pop     dx
                pop     bx
                mov     al,020h
                out     020h,al
                pop     ax
                iret

@ResetV3:	cmp	word ptr InsLB[4],0FFFFh
                je      @C3
                mov     bx,word ptr InsFB[4]
                mov     word ptr Samples[8],bx
                jmp     @L3
@C3:            xor     bx,bx
                mov     byte ptr Volume3,bl
                mov     word ptr Samples[8],bx
                les     bx,dword ptr ShutDown
                mov     byte ptr es:[bx+2],0
                jmp     @L3

@ResetV4:       cmp     word ptr InsLB[6],0FFFFh
                je      @C4
                mov     bx,word ptr InsFB[6]
                mov     word ptr Samples[12],bx
                jmp     @L4
@C4:            xor     bx,bx
                mov     byte ptr Volume4,bl
                mov     word ptr Samples[12],bx
                les     bx,dword ptr ShutDown
                mov     byte ptr es:[bx+3],0
                jmp     @L4
Int08Entry      endp

TimerInit	proc	near
                push    es
		cli
		mov	al,036h
		out	43h,al
                mov     al,byte ptr cs:TimerFreq
		out	40h,al
		mov	al,0
		out	40h,al
                xor     ax,ax
                mov     es,ax
                mov     word ptr es:[8*4],offset IntProc
                mov     word ptr es:[8*4+2],cs
                pop     es
                sti
		retn
TimerInit	endp

InitTable	proc	near
                mov     di,VolTable
		cld
                push    cs
		pop	es
		mov	ch,0
@M1:		mov	cl,0
@M2:		mov	al,cl
		cmp	al,0
		jge	@M3
		cmp	al,-125
		jl	@M3
		sub	al,3
@M3:		imul	ch
                shr     ax,7
		stosb
		inc	cl
		jne	@M2
		inc	ch
                cmp     ch,65
		jb	@M1
		retn
InitTable	endp

DriverEnd       label   near
Driver          ends
		end
