250 lines
6.3 KiB
NASM
250 lines
6.3 KiB
NASM
name sound
|
|
title PC Scheme XLI interface to sound
|
|
page 84,120
|
|
|
|
|
|
comment ~
|
|
|
|
This program provides access to the PC's sound-generating devices.
|
|
It demonstrates an XLI interface written in assembly language.
|
|
|
|
User documentation is available under XLI\SOUND.DOC. SOUND.EXE is
|
|
already provided and can be used immediately by inserting its pathname
|
|
in your .XLI control file.
|
|
|
|
To generate SOUND.EXE yourself, do the following (substituting
|
|
directory names and setting the path as needed; Microsoft's
|
|
Macro Assembler version 4.0 was used):
|
|
|
|
masm sound;
|
|
link sound;
|
|
|
|
~
|
|
|
|
|
|
DATA segment byte public 'DATA'
|
|
assume DS:DATA
|
|
datastart = $
|
|
|
|
;-----------------------------------------------------------------------------
|
|
; Equates
|
|
;-----------------------------------------------------------------------------
|
|
ppi_port equ 61h ;Programmable Peripheral Interface port#
|
|
timer_port equ 42h ;timer chip port#
|
|
;reset timer is port# + 1
|
|
timer_mask equ 00000001b ;mask to extract timer bit 1=on
|
|
spkr_mask equ 00000010b ;mask to extract speaker bit 1=on
|
|
|
|
;-----------------------------------------------------------------------------
|
|
; XLI
|
|
;-----------------------------------------------------------------------------
|
|
;;; ----- Equates -----
|
|
; offsets into the PSP
|
|
term_addr equ 0Ah
|
|
fb_addr equ 5Ch
|
|
|
|
;;; ----- Data structures -----
|
|
|
|
; file block
|
|
file_block label word
|
|
dw 4252h
|
|
dw 0011b ;flags = 0,0,16-bit,near
|
|
dw offset lookup_table, seg lookup_table
|
|
dw offset parm_block, seg parm_block
|
|
dw 8 dup (0) ;reserved
|
|
|
|
; parameter block
|
|
parm_block label word
|
|
dw 0 ;selector
|
|
dw 0 ;ssr
|
|
dw 8 dup (0) ;ssr args
|
|
dw 8 dup (0) ;reserved
|
|
dw 0 ;return value type
|
|
dw 4 dup (0) ;return value
|
|
; begin arguments
|
|
over dw ? ;overlay the 2 sound sources? (you and timer)
|
|
; 0 - enable/disable sound commands
|
|
; 1 - timer only
|
|
; (processor-speed independent)
|
|
; 2 - manual control only
|
|
; (processor-speed dependent)
|
|
; 3 - overlay manual control with timer
|
|
; (processor-speed dependent)
|
|
; 4 - speaker off
|
|
freq dw ? ;timer chip set to this frequency
|
|
dura dw ? ;duration
|
|
pitch dw ? ;pitch (silent section)
|
|
pitch2 dw ? ;pitch (voiced section)
|
|
|
|
; lookup table
|
|
lookup_table label word
|
|
db 'sound//'
|
|
|
|
; other needed values
|
|
psp dw ? ;PSP segment address
|
|
psize dw ? ;size of program in paragraphs
|
|
xwait dw 2 dup (?) ;XLI wait address
|
|
xbye dw 2 dup (?) ;XLI bye address
|
|
|
|
;-----------------------------------------------------------------------------
|
|
; Local data
|
|
;-----------------------------------------------------------------------------
|
|
;;; ----- Constants -----
|
|
clock dd 1193180 ;main clock frequency (Hz)
|
|
;;; ----- Variables -----
|
|
tmask db ? ;reflects state of timer mask
|
|
enable dw 1 ;enabled flag; 0=no, 1=yes
|
|
|
|
datasize = $-datastart
|
|
DATA ends
|
|
|
|
|
|
STACK segment word stack 'STACK'
|
|
stackstart = $
|
|
dw 16 dup (?)
|
|
stacksize = $ - stackstart
|
|
STACK ends
|
|
|
|
|
|
PROG segment byte public 'PROG'
|
|
assume CS:PROG,DS:DATA
|
|
progstart = $
|
|
|
|
;-----------------------------------------------------------------------------
|
|
; The XLI interface.
|
|
;-----------------------------------------------------------------------------
|
|
|
|
main proc far ;this file's initial entry point
|
|
|
|
; Initialization
|
|
|
|
mov AX,data
|
|
mov DS,AX
|
|
mov psp,ES ;save PSP@
|
|
mov word ptr ES:fb_addr,offset file_block ;poke file block@
|
|
mov word ptr ES:fb_addr+2,seg file_block ;into PSP
|
|
mov AX,ES:term_addr ;calc ptrs in PCS to jump to
|
|
add AX,3
|
|
mov xwait,AX
|
|
add AX,3
|
|
mov xbye,AX
|
|
mov AX,ES:term_addr+2
|
|
mov xwait+2,AX
|
|
mov xbye+2,AX
|
|
mov psize,plen ;calc program size
|
|
|
|
; Suspend this program until an XCALL comes in, or until PCS terminates.
|
|
|
|
hloop: push psp
|
|
push psize
|
|
call dword ptr [xwait] ;connect to PCS
|
|
pop ax
|
|
pop ax
|
|
cmp ax,0
|
|
jnz case0
|
|
call dword ptr [xbye] ;disconnect from PCS
|
|
|
|
;-----------------------------------------------------------------------------
|
|
; The individual cases (just one, here).
|
|
;-----------------------------------------------------------------------------
|
|
|
|
case0:
|
|
cmp over,0 ;enable/disable sound?
|
|
jnz check ;no, jump
|
|
mov ax,freq ;set flag appropriately
|
|
mov enable,ax
|
|
mov dx,0
|
|
jmp short exit ;turn off sound before exiting
|
|
|
|
check: cmp enable,0 ;is sound enabled?
|
|
jz hloop ;no, exit
|
|
;
|
|
cmp over,4 ;silence?
|
|
jnz s1 ;no, jump
|
|
mov dx,freq
|
|
exit: in al,ppi_port ;turn off speaker bit
|
|
and al,not spkr_mask
|
|
out ppi_port,al
|
|
cmp dx,0 ;delay before returning?
|
|
jne timed ;yes, jump
|
|
jmp hloop ;no, return immediately to PC Scheme
|
|
|
|
s1: cmp over,1 ;timer only?
|
|
jnz s2 ;no, jump
|
|
call init_timer
|
|
in al,ppi_port
|
|
or al,spkr_mask OR timer_mask
|
|
out ppi_port,al
|
|
cmp dura,0 ;if duration=0,
|
|
jz hloop ;exit without turning sound off
|
|
timed: mov tmask,0 ;x (time filler)
|
|
mov bx,dura
|
|
again1: mov cx,pitch
|
|
nop ;x
|
|
nop ;x
|
|
nop ;x
|
|
here1a: loop here1a
|
|
nop ;x
|
|
nop ;x
|
|
nop ;x
|
|
or al,tmask ;x
|
|
mov cx,pitch2
|
|
here1b: loop here1b
|
|
dec bx
|
|
jnz again1
|
|
xor dx,dx ;clear DX for exiting
|
|
jmp exit
|
|
|
|
s2: cmp over,2 ;manual control only?
|
|
jnz s3 ;no, jump
|
|
mov tmask,0 ;reset timer-bit mask
|
|
merge: mov bx,dura ;BX is duration
|
|
in al,ppi_port
|
|
again2: and al,not (spkr_mask OR timer_mask) ;turn off speaker
|
|
out ppi_port,al
|
|
mov cx,pitch ;CX is first half of pitch half-cycle
|
|
here2a: loop here2a
|
|
or al,spkr_mask ;turn on speaker
|
|
or al,tmask ;include timer bit state
|
|
out ppi_port,al
|
|
mov cx,pitch2 ;CX is second half of pitch half-cycle
|
|
here2b: loop here2b
|
|
dec bx
|
|
jnz again2
|
|
xor dx,dx ;clear DX for exiting
|
|
jmp exit
|
|
|
|
s3: cmp over,3 ;both?
|
|
jnz error ;no, jump; error
|
|
call init_timer
|
|
mov tmask,timer_mask ;set timer-bit mask
|
|
jmp merge
|
|
|
|
error: jmp exit
|
|
|
|
main endp
|
|
|
|
init_timer proc
|
|
mov al,182 ;reset timer chip
|
|
out timer_port+1,al
|
|
mov ax,word ptr clock ;calc number to give to timer chip
|
|
mov dx,word ptr clock+2 ; = 1193180 / freq
|
|
mov bx,freq
|
|
mov cx,20 ;avoid underflow
|
|
cmp bx,cx ;(occurs for divisors <= 18)
|
|
jge it_10
|
|
mov bx,cx
|
|
it_10: div bx
|
|
out timer_port,al ;send number to timer chip
|
|
mov al,ah
|
|
out timer_port,al
|
|
ret
|
|
init_timer endp
|
|
|
|
progsize = $-progstart
|
|
plen equ (progsize+datasize+stacksize+100h+20h)/16
|
|
|
|
PROG ends
|
|
end main
|
|
|