📄 gwsound.asm
字号:
TITLE GWSOUND - GW BASIC 2.0 NOISE, SOUND, & BEEP support
;***
; GWSOUND - GW BASIC 2.0 NOISE, SOUND, & BEEP support
;
; Copyright <C> 1986, Microsoft Corporation
;
;Purpose:
;
; BASIC Syntax mapping to included runtime entry points:
;
;
; - SOUND Statement:
;
; SOUND freq, duration
; |
; |
; B$SOND
;
;******************************************************************************
include switch.inc
INCLUDE rmacros.inc ; Runtime Macro Defintions
.xall
.radix 10
useSeg SN_TEXT
useSeg _BSS
useSeg _DATA
include seg.inc
INCLUDE ibmunv.inc ; EQUates for B$DONOTE
sBegin _BSS
DURATION DW 1 DUP(?)
FREQUENCY DW 1 DUP(?)
DURASHN DW 2 DUP(?) ; need two words to store s.p. duration
sEnd _BSS
sBegin SN_TEXT
assumes CS,SN_TEXT
externNP B$FrameAFE ; advanced function error + frame setup
externNP B$ftolrnd
externNP B$fmldw
externNP B$STRTSD
externNP B$SNDWAT
externNP B$DONOTE
externNP B$ERR_AFE ; advanced function error
externNP B$ERR_FC ; function error
cProc B$NOI,<FAR,PUBLIC>
cBegin
JMP B$FrameAFE ; sets up frame for error recovery
cEnd <nogen>
SUBTTL BEEP and SOUND Statements
PAGE
PUBLIC B$BP0
PUBLIC B$BP1 ; BEEP ON/OFF
PUBLIC B$SO0
PUBLIC B$SO1 ; SOUND ON/OFF
B$BP0:
B$BP1:
B$SO0:
PUBLIC B$SND
B$SND:
cProc B$SO1,<FAR>
cBegin
JMP B$FrameAFE ; sets up frame for error recovery
cEnd <nogen>
;***
;B$STOPSD
;Purpose:
; Signal background task to flush voice queues and stop playing
; music.
;Input:
; none
;Output:
; Preserves all registers
;****
cProc B$STOPSD,<NEAR>,<AX>
cBegin
MOV AL,STPSND ;Function code to stop sound
cCALL B$DONOTE ;Pass command to the OEM
JC FC_ERR ; function call error if B$DONOTE complains
cEnd ; End of B$STOPSD
;***
;B$SOND - accept parms 1&2 to sound statement
;
; Purpose:
; Runtime Entry Point.
; accept parms 1&2 to sound statement
; Syntax: SOUND x,y[,[volume][,voice]]
;
; Where: x is the Frequency in Hertz.
; y is the Duration in Clock ticks. (currently 18.2/sec).
;
; Frequency must be at least 37 Hz.
; If Duration is 0, then just turn off current sound...
;
; Input:
; parm1 = frequency [6]
; parm2 = duration (s.p.) [6]
; Output:
;****
cProc B$SOND,<FAR,PUBLIC>,<ES,SI,DI> ;[7]
parmW freq
parmD dur
cBegin
;
; When converting the duration into a real time quantity, the sound duration on
; the statement is specified in 55ms increments, but the B$DONOTE interface
; specifies it in 2.5ms increments. So we need to multiply the duration by 22,
; and then check for overflow. (error only if duration .gt. 64k)
;
MOV BX,[freq]
MOV [FREQUENCY],BX ; save frequency
LEA SI,[dur] ; [si] points to SP duration
MOV DI,OFFSET DGROUP:DURASHN ; [di] points to save area
PUSH DS
POP ES ; set ES=DS
PUSH DI ; save ptr to DURASHN
MOVSW ; move first word of duration
LODSW ; get second word of duration
STOSW ; now we've moved s.p. duration, plus we've
; got second word in AX for testing below
POP BX ; restore ptr to s.p. DURASHN
XCHG AX,CX ; [CX] = second word of s.p. duration
SHL CX,1 ; test duration - -
JC FC_ERR ; illegal function call if duration negative
JZ HLTSND ; stop sound & return if zero duration given
FLD DWORD PTR [BX] ; ST0 = duration (load from DS:BX to ST0)
FLD ST(0) ; copy for destructive compare
CALL B$ftolrnd ; pop copy from ST0, put in DX:AX as integer
OR DX,DX ; max. legal value of duration is 65535
JZ DUR_OK ; brif duration is legal
FC_ERR:
JMP B$ERR_FC ; function call error - doesn't return
DUR_OK:
MOV BX,22D
CALL B$fmldw ; ST1 = duration, ST0 = 22D
FMULP ST(1),ST ; ST0 = 22 * duration
CALL B$ftolrnd ; DX:AX = 22 * duration
MOV CX,0FFFFH ; cache in register to save a couple bytes
OR DX,DX
JZ LODDUR ; brif 22 * duration <= 64K
MOV AX,CX ;[3] put max value in AX (0FFFFH)
LODDUR:
MOV [DURATION],AX ; [duration] = [ax]
MOV DX,CX ;[2]default voice (0FFFFH)
MOV BX,DX ;default volume
SETVOI:
; at this point, BX = volume
; DX = voice
MOV AH,DL ; assume user specified voice
INC DL
JNZ SNDES1 ; go make noise if he did
MOV AH,DL ; he didnt so use 0
; Get the sound parameters from the first call and send them to the OEM
; routines.
SNDES1: ; [bx] = volume
MOV DX,[DURATION] ; [dx]=duration
MOV CX,[FREQUENCY] ; [cx]=frequency
OR DX,DX ; if duration=0 then sound already
JZ SNDRET ; turned off -- exit
CALL B$SNDWAT ; wait until other sounds are done
DNT:
MOV AL,QUENOT ; function code to queue a note
cCALL B$DONOTE ;start new sound.
JNC START ; brif no carry
DEC AL
JZ DNT ; try queuing again
JMP SHORT FC_ERR ; else function call error
START:
CALL B$STRTSD ;start sound
SNDRET:
cEnd
HLTSND:
; range for B$SOND, below
MOV [DURATION],CX ; subsequent calls to B$SND use
; zero duration!
cCALL B$STOPSD ; stop sound & exit
JMP SNDRET ; Exit gracefully
sEnd SN_TEXT
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -