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