home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Dr. CD ROM (Annual Premium Edition)
/
premium.zip
/
premium
/
MUSICLAB
/
DIGVOIVE.ZIP
/
VRMOD.ASM
< prev
next >
Wrap
Assembly Source File
|
1989-06-24
|
17KB
|
731 lines
page 58,132
.286c
.MODEL LARGE
;**********************************************************************
;* *
;* Equates *
;* *
;**********************************************************************
tccount equ 72 ;reload count to produce 16572 Hz
countmax_18hz equ 910 ;ratio of new timer rate to old rate
tcaddrc equ 43h ;timer/counter control register address
tcaddrd equ 40h ;timer/counter data register zero
tcmode equ 34h ;mode control byte for timer/counter
ppiaddr equ 61h ;programmable peripheral interface address
;**********************************************************************
;* *
;* Macros *
;* *
;**********************************************************************
ljz macro dest
local skip
jnz skip
jmp dest
skip:
endm
;**********************************************************************
;* *
;* Global variables *
;* *
;**********************************************************************
.DATA
even ;don't put these on an odd boundary
blockaddr dd 0 ;beginning of memory block
blocksize dd 0 ;size of memory block
blockend dd 0 ;last address of memory block + 1
currentaddr dd 0 ;pointer to current record position in memory
datacount dd 0 ;number of data bytes already recorded
fwrtaddr dd 0 ;address of next byte to be written to disk
fwrtcount dd 0 ;number of bytes already written to disk
goflag dw 0 ;indicates whether recording is in progress
fileflag dw 0 ;indicates whether data is written to a file
filehandle dw 0 ;handle of file to receive voice data
hookedflag dw 0 ;indicates whether the interrupt is hooked
countfor_18hz dw 0 ;counter to determine when to call BIOS
comaddr dw 0 ;the address of the COM port
comlist dw 3FEh ;needed addresses of all COM ports
dw 2FEh
dw 3EEh
dw 2EEh
shiftcount db 0 ;current bit position within byte
;**********************************************************************
;* *
;* Code *
;* *
;**********************************************************************
.CODE
bios_timer_routine dd 0 ;we keep this in the code segment
; for access through the CS register
; since the other segment registers
; will contain unknown values when
; this is needed
assume ds:DGROUP
;**********************************************************************
;* Speed up the timer tick and set "goflag" *
;**********************************************************************
startvoice proc near
pushf
cli
mov al,tcmode
out tcaddrc,al
mov ax,tccount
out tcaddrd,al
mov al,ah
out tcaddrd,al
mov shiftcount,0
mov countfor_18hz,countmax_18hz
mov goflag,1
popf
ret
startvoice endp
;**********************************************************************
;* Slow the timer tick to normal and clear "goflag" *
;**********************************************************************
stopvoice proc near
pushf
cli
mov al,tcmode
out tcaddrc,al
mov al,0
out tcaddrd,al
out tcaddrd,al
mov goflag,0
popf
ret
stopvoice endp
;**********************************************************************
;* Interrupt service routine *
;**********************************************************************
timer_tick proc far
push ds
push bx
push es
push ax
push cx
push dx
mov ax,DGROUP
mov ds,ax
cmp goflag,0
je chain_exit
les bx,currentaddr
mov ah,es:[bx]
mov dx,comaddr
in al,dx
rcl al,4
rcl ah,1
mov es:[bx],ah
inc shiftcount
and shiftcount,07h
jnz exit_decide
mov ax,es
inc bx
jnz check_wrap
add ax,1000h
check_wrap:
cmp bx,word ptr blockend
jne save_cur_addr
cmp ax,word ptr blockend+2
jne save_cur_addr
mov bx,word ptr blockaddr
mov ax,word ptr blockaddr+2
save_cur_addr:
mov word ptr currentaddr,bx
mov word ptr currentaddr+2,ax
add word ptr datacount,1
adc word ptr datacount+2,0
exit_decide:
dec countfor_18hz
jnz nochain_exit
mov countfor_18hz,countmax_18hz
chain_exit:
pop dx
pop cx
pop ax
pop es
pop bx
pop ds
jmp cs:bios_timer_routine
nochain_exit:
mov al,20h
out 20h,al
pop dx
pop cx
pop ax
pop es
pop bx
pop ds
iret
timer_tick endp
;**********************************************************************
;* Initialization procedure *
;**********************************************************************
;This routine should be called exactly one time before any of the other
; routines in this package are called. It takes no parameters, but returns
; a value indicating success or failure as follows:
;Return value Meaning
;------------ -------
; 0 success
; 1 voice package already initialized
; 2 wrong CPU, won't run on 8088 or 8086
public RVOICE_INIT
RVOICE_INIT proc far
push sp
pop ax
cmp ax,sp
je vi_test
mov ax,2
ret
vi_test:
cmp hookedflag,0
je vi_hook
mov ax,1
ret
vi_hook:
enter 0,0
push si
push di
push ds
lea dx,RVOICE_CBREAK
mov ax,seg RVOICE_CBREAK
mov ds,ax
mov ax,2523h
int 21h
pop ds
push ds
mov ax,3508h
int 21h
mov word ptr cs:bios_timer_routine,bx
mov word ptr cs:bios_timer_routine+2,es
lea dx,timer_tick
mov ax,seg timer_tick
mov ds,ax
mov ax,2508h
int 21h
pop ds
pop di
pop si
mov hookedflag,1
sub ax,ax
leave
ret
RVOICE_INIT endp
;**********************************************************************
;* Cleanup procedure *
;**********************************************************************
;This will restore the interrupt 8 vector to its original state. This
; routine MUST be called before the main program exits to DOS, unless:
; (a) the program has never called RVOICE_INIT, or (b) the program is
; becoming memory-resident.
;There are no parameters. The return values are 0 for success or 1 if
; the interrupt vector was not in fact hooked.
public RVOICE_CLEANUP
RVOICE_CLEANUP proc far
cmp hookedflag,1
je vc_unhook
mov ax,1
ret
vc_unhook:
enter 0,0
push si
push di
call stopvoice
push ds
lds dx,cs:bios_timer_routine
mov ax,2508h
int 21h
pop ds
pop di
pop si
mov hookedflag,0
sub ax,ax
leave
ret
RVOICE_CLEANUP endp
;**********************************************************************
;* Vector restore for Control-Break *
;**********************************************************************
public RVOICE_CBREAK
RVOICE_CBREAK proc far
pusha
push ds
push es
mov ax,DGROUP
mov ds,ax
call stopvoice
call RVOICE_CLEANUP
pop es
pop ds
popa
stc
ret
RVOICE_CBREAK endp
;**********************************************************************
;* "File write catch-up" procedure *
;**********************************************************************
;This must be called frequently from the main program if file writing is
; being used and the length of the data to be recorded is longer than the
; length of the memory block. The routine checks the progress of the
; address pointer in use by the interrupt service routine and writes
; new data to the file as it becomes available.
;There are no parameters. The return values are 0 for success 1 if there
; was no new data to write, or 2 if an error occurred while writing the file.
vcat_temp1l equ [bp-4] ;current address from ISR
vcat_temp1h equ [bp-2]
vcat_temp2l equ [bp-8] ;<unused>
vcat_temp2h equ [bp-6]
;the three stopping points:
vcat_temp3l equ [bp-12] ;current address - fill address
vcat_temp3h equ [bp-10]
vcat_temp4l equ [bp-16] ;block end - fill address
vcat_temp4h equ [bp-14]
vcat_temp5l equ [bp-20] ;(boundary) - fill address
vcat_temp5h equ [bp-18]
vcat_templength equ 20
public RVOICE_CATCHUP
RVOICE_CATCHUP proc far
enter vcat_templength,0
;should we even be doing this?
cmp fileflag,0
ljz vcat_exit0
;grab a stable value from currentaddr
; since it is changing all the time
cli
mov ax,word ptr currentaddr
mov vcat_temp1l,ax
mov ax,word ptr currentaddr+2
mov vcat_temp1h,ax
sti
;calculate the forward distance to each of the
; three possible stopping points
vcat_getgap:
mov ax,vcat_temp1l
sub ax,word ptr fwrtaddr
mov vcat_temp3l,ax
pushf
mov ax,vcat_temp1h
sub ax,word ptr fwrtaddr+2
sar ax,12
popf
sbb ax,0
mov vcat_temp3h,ax
vcat_getclearance:
mov ax,word ptr blockend
sub ax,word ptr fwrtaddr
mov vcat_temp4l,ax
pushf
mov ax,word ptr blockend+2
sub ax,word ptr fwrtaddr+2
sar ax,12
popf
sbb ax,0
mov vcat_temp4h,ax
mov ax,word ptr fwrtaddr
neg ax
mov vcat_temp5l,ax
mov word ptr vcat_temp5h,0
jnz vcat_cmp2
inc word ptr vcat_temp5h
;select the stopping point which will be
; encountered soonest
;Since we are not interested in the negative
; values, doing unsigned compares in a search
; for the smallest number will give the
; desired result.
vcat_cmp2:
mov ax,vcat_temp3h
mov cx,vcat_temp3l
vcat_cmp3:
cmp ax,vcat_temp4h
jb vcat_cmp5
ja vcat_cmp4
cmp cx,vcat_temp4l
jb vcat_cmp5
vcat_cmp4:
mov ax,vcat_temp4h
mov cx,vcat_temp4l
vcat_cmp5:
cmp ax,vcat_temp5h
jb vcat_cmp7
ja vcat_cmp6
cmp cx,vcat_temp5l
jb vcat_cmp7
vcat_cmp6:
mov ax,vcat_temp5h
mov cx,vcat_temp5l
vcat_cmp7:
;Now the smallest number is in AX:CX.
; However, AX:CX may be 65536 or 0FFFFh
; (illegal), so we must test for these
; possibilities.
cmp ax,1
je vcat_fixcx
cmp cx,0FFFFh
jne vcat_writefile
vcat_fixcx:
mov cx,0FE00h
vcat_writefile:
or cx,cx
jz vcat_exit1
mov bx,filehandle
push ds
lds dx,fwrtaddr
mov ah,40h
int 21h
pop ds
jc vcat_error2
cmp ax,cx
jne vcat_error2
;update global varibles to show the current
; situation
add word ptr fwrtcount,cx
adc word ptr fwrtcount+2,0
add word ptr fwrtaddr,cx
jnc vcat_fillwrap
add word ptr fwrtaddr+2,1000h
vcat_fillwrap:
mov bx,word ptr blockend
cmp bx,word ptr fwrtaddr
jne vcat_exit0
mov ax,word ptr blockend+2
cmp ax,word ptr fwrtaddr+2
jne vcat_exit0
mov bx,word ptr blockaddr
mov ax,word ptr blockaddr+2
mov word ptr fwrtaddr,bx
mov word ptr fwrtaddr+2,ax
jmp short vcat_exit0
;return code exit points
vcat_error2:
mov ax,2
jmp short vcat_exit
vcat_exit1:
mov ax,1
jmp short vcat_exit
;normal exit point
vcat_exit0:
;don't leave until at least one bit has been played
; if goflag is not zero
mov ax,word ptr currentaddr
cmp vcat_temp1l,ax
jne vcat_exitloop
cmp goflag,0
jne vcat_exit0
vcat_exitloop:
sub ax,ax
vcat_exit:
leave
ret
RVOICE_CATCHUP endp
;**********************************************************************
;* "Start recording" procedure *
;**********************************************************************
;Accepts the following parameters with PASCAL parameter-passing convention:
;Position Size Description
;-------- ---- -----------
; 1 4 A far pointer to the memory block used for voice data.
; 2 4 A dword indicating the length of the memory block.
; 3 2 A flag word. If this is 1, then data will be written to
; a file. If it is 0, no file operations will be performed.
; 4 2 An open file handle. This is ignored if the flag word
; is 0.
; 5 2 A word containing the number of the COM port to be used
; for input (1 thru 4).
; 6 4 A dword indicating the offset within the memory block
; where recording is to begin.
;Return value Meaning
;------------ -------
; 0 success
; 1 block size is too small (blocklen < 8192 and
; file write = yes)
; 2 voice recording is already in progress
; 3 a COM port number not within the range of 1 thru 4
; was specified
; 4 starting position is not less than block length
min_blocksize equ 8192
vs_parm1 equ [bp+20] ;length = 4
vs_parm2 equ [bp+16] ;length = 4
vs_parm3 equ [bp+14] ;length = 2
vs_parm4 equ [bp+12] ;length = 2
vs_parm5 equ [bp+10] ;length = 2
vs_parm6 equ [bp+6] ;length = 4
vs_parmlength equ 18
public RVOICE_START
RVOICE_START proc far
cmp goflag,0
je vs_begin
mov ax,2
ret vs_parmlength
vs_begin:
enter 0,0
mov word ptr datacount,0
mov word ptr datacount+2,0
mov word ptr fwrtcount,0
mov word ptr fwrtcount+2,0
les bx,dword ptr vs_parm1
mov word ptr blockaddr,bx
mov word ptr blockaddr+2,es
les bx,dword ptr vs_parm6
mov ax,es
add bx,word ptr blockaddr
adc ax,0
shl ax,12
add ax,word ptr blockaddr+2
mov word ptr currentaddr,bx
mov word ptr currentaddr+2,ax
mov word ptr fwrtaddr,bx
mov word ptr fwrtaddr+2,ax
les bx,dword ptr vs_parm2
mov word ptr blocksize,bx
mov word ptr blocksize+2,es
mov ax,es
add bx,word ptr blockaddr
adc ax,0
shl ax,12
add ax,word ptr blockaddr+2
mov word ptr blockend,bx
mov word ptr blockend+2,ax
cmp ax,word ptr currentaddr+2
jb vs_error4
ja vs_gethandle
cmp bx,word ptr currentaddr
jbe vs_error4
vs_gethandle:
mov ax,vs_parm4
mov filehandle,ax
mov bx,vs_parm5
cmp bx,1
jb vs_error3
cmp bx,4
ja vs_error3
dec bx
shl bx,1
lea ax,comlist
add bx,ax
mov ax,[bx]
mov comaddr,ax
mov ax,vs_parm3
mov fileflag,ax
or ax,ax
jz vs_exit0
mov ax,word ptr blocksize
sub ax,min_blocksize
mov ax,word ptr blocksize+2
sbb ax,0
jnc vs_exit0
mov ax,1
jmp short vs_exit
vs_error3:
mov ax,3
jmp short vs_exit
vs_error4:
mov ax,4
jmp short vs_exit
vs_exit0:
call startvoice
sub ax,ax
vs_exit:
leave
ret vs_parmlength
RVOICE_START endp
;**********************************************************************
;* "Stop recording" procedure *
;**********************************************************************
;Call this to stop the voice recording operation.
;This routine accepts no parameters and has no return information.
public RVOICE_STOP
RVOICE_STOP proc far
call stopvoice
sub ax,ax
ret
RVOICE_STOP endp
;**********************************************************************
;* "Get status" procedure *
;**********************************************************************
;This will report the status of voice operations.
;The first parameter is a far pointer to a dword which will receive the
; number of bytes which have already been recorded.
;The second parameter is a far pointer to a dword which will receive a
; value indicating the offset within the memory block of the next byte
; to be filled by the recording operation.
;There is no return value.
vst_parm1 equ [bp+10] ;length = 4
vst_parm2 equ [bp+6] ;length = 4
vst_parmlength equ 8
public RVOICE_STATUS
RVOICE_STATUS proc far
enter 0,0
les bx,vst_parm1
cli
mov ax,word ptr datacount
mov dx,word ptr datacount+2
mov es:[bx],ax
mov es:[bx+2],dx
les bx,vst_parm2
mov ax,word ptr currentaddr
mov dx,word ptr currentaddr+2
sti
shr dx,12 ;we can cheat here because we
; know it's incremented by 1000h units
mov cx,word ptr blockaddr+2
shr cx,12
sub ax,word ptr blockaddr
sbb dx,cx
mov es:[bx],ax
mov es:[bx+2],dx
sub ax,ax
leave
ret vst_parmlength
RVOICE_STATUS endp
end