⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 llsnd.asm

📁 [随书类]Dos6.0源代码
💻 ASM
📖 第 1 页 / 共 2 页
字号:
	TITLE	LLSND - multivoice music and sound interface
;***
; LLSND - multivoice music and sound interface
;
;	Copyright <C> 1986, Microsoft Corporation
;
;Purpose:
;
;       This module has the following support routines :
;
;       1. B$DONOTE
;       2. B$TICTOC.... The TIMER interrupt vectors here before
;                       updating the time of the day. Normal
;                       frequency of the timer interrupt is 18.2
;                       times per second. This frequency is changed
;                       so that it interrupts at 572.4 times per
;                       second (exactly 32 times faster). This increase
;                       in speed gives better music performance. The
;                       basic philosophy in handling music is described
;                       below :
;
;               Music is composed of notes and a note consists of:
;               1. Frequency
;               2. Duration
;                       The frequency is loaded into the 8253 timer
;               chip. The duration is saved in some memory location and each
;		time the timer interrupts, we decrement the duration by 1 and
;               when the duration becomes zero we are all done. It is
;               important to note that the 8253 operates in the mode
;               wherein it reloads itself each time it counts down to
;               zero.
;               We have to remember one important thing, since we
;               change the frequency of the TIMER interrupt whenever
;               music is playing, we should see to it that the actual
;               timer interrupt (one which updates the time of the day)
;               gets called once every 32 times our timer interrupt
;               gets called. The figure 32 comes from the fact that
;               the TIMER is 32 times as fast as what it used to be.
;               Also when music stops playing we SHOULD change the
;               timer frequency back to its original rate.
;               The figure below illustrates how the TIMER interrupt
;               ( INT 8H ) is handled :
;
;                 Timer INT
;                  vectors
;                ------------        IF MUSIC      --------------
;               |     -------|------------------->| B$TICTOC      |
;                ------------    |     ACTIVE     |    Interrupt |
;               |    CS      |   |                |   service    |
;                ------------    |                |   routine for|
;                                |                |   handling   |
;                                |                |   music      |
;                                |                |     _________|______
;                                | ELSE IF         --------------       |
;                                | MUSIC NOT                            |
;                                | ACTIVE                               |
;                                |                                      |
;                                |                 ------------         |
;                                 --------------->| ROM Timer  |        |
;                                                 | interrupt  |<-------
;                                                 | service    |
;                                                 | routine    |
;                                                 | updates    |
;                                                 | time of    |
;                                                 | day.       |
;                                                 |            |
;                                                 | (F000:FEA5)|
;                                                 |            |  INT 1CH
;                                                 |  -------------------
;                                                 |            |        |
;                                                  ------------         |
;                                                                       |
;                                                                       |
;                                                  ------------         |
;                                                 | CLOCK_INT  |        |
;                                                 |   This     |<-------
;                                                 |  routine   |
;                                                 |  checks for|
;                                                 |  timer, pen|
;                                                 |  and TRIG  |
;                                                 |  traps.    |
;                                                 |            |    JUMP TO
;                                                 |    --------|------------->
;                                                  ------------     OLD 1CH
;                                                                   VECTOR
;
;               The routine B$TICTOC calls on the following routines:
;
;               1. B$NXTSND.... This looks to see if any more entries
;                             are present in the sound queue and if so
;				gets the frequency and duration information,
;				and starts that note. It also check if any play
;                             event occured and if so sets the PLYFLG
;                             and the EVTFLG.
;
;******************************************************************************
	INCLUDE	switch.inc	;switch file
	INCLUDE rmacros.inc	

	UseSeg	_BSS		
	UseSeg	_DATA		
	UseSeg	EV_TEXT 	


	INCLUDE seg.inc 	
	INCLUDE	idmac.inc	
	INCLUDE	ibmunv.inc	; include control block & DONOTE input values
	INCLUDE	intmac.inc	
	INCLUDE event.inc 	

CLK_DELTA	EQU	8	; 8 = 256/32
QUE_BYTES	EQU	1+2+2	; Note + Duration + Frequency

sBegin	_BSS			

	globalB b$PLAFLG,,1	;play event flag
	globalB b$PLENBL,,1	;play trapping enabled or not flag
	globalW b$PLYCNT,,1	;# of notes specified in ON PLAY(n)
	globalW b$NOTES,,1	;keeps running total of the music notes
	globalW b$SNDTIM,,1	

	PUBLIC	b$SNDQCB	; Sound control block
b$SNDQCB QUE_CTRL_BLOCK <>	

	externB b$MUSIC		; defined in LLSCNIO.ASM
	externW b$SNQueSeg	;SNINIT - sound queue buffer segment

	staticB b$SNDFLG,,1	;flag set if music started
	staticB CLK_TICS,8,1	;Clock tic modulo counter at any time
	externW b$pTrapEvent	; pointer to B$TrapEvent if event code
				; present

sEnd	_BSS			


assumes CS,EV_TEXT		
sBegin	EV_TEXT 		


	externW  b$BASDSG	
	externNP B$INIQUE	
	externNP B$QUE 		
	externNP B$DQUE		

POPFF	MACRO			;; macro to insure that POPF instruction
LOCAL	L1,L2			;; is executed correctly on 286. It seems

	JMP	SHORT L2	;;to enable interrupts after POPF instruction
L1:	IRET			;; even if the stack image says 'disabled'
L2:	PUSH	CS
	CALL	L1

	ENDM

;***
;B$DONOTE - Support for sound
;OEM-interface routine
;
;Purpose:
;	This routine supports speaker activity.  The support is subdivided
;	into several subfunctions as follows:
;
;	a. Queue a note:
;          This function is passed a frequency and a duration. The note is
;	   queued, if the frequency is legal, otherwise nothing it put in
;	   in the queue. No attempt to start the speaker is made.
;
;	   The definition of a legal frequency are machine dependent.  For
;	   an IBM, a frequency must be within the range 37 <= f <= 32767.
;
;	b. Queue a rest:
;          This function is passed a duration. Stacatto and Normal mode notes
;	   are built from a note and a short pause. This function is used
;	   to play the fraction of a note that defines a short pause in case
;          of Stacatto and Normal notes.
;
;	c. Query if voice is active:
;          This function is used to test the current activity of the
;          sound queue. If queued items are currently being processed
;          in the sound queue, this function code should return
;          FF in [AL], else it should return 0 in [AL].
;
;	d. Start Music:
;	   This function requests that notes that have been queued are
;	   to start playing. Notes should be played until the queue is
;	   empty. This function can be called if notes are currently
;	   playing, in which case it simply returns.  Notes may be added
;	   to the queue while it is being played. No event other than
;	   this subfunction should start music.
;
;	e. Stop Music and flush the queue:
;          This function requests that the voice be stopped and that
;          queue for the voice be flushed.
;
;
;       Certain of the above functions must add queue entries. If no room
;       remains in the queue then the routine must return immediately to
;       specify that the queue is full. This event must not cause speaker
;       activity to begin.
;
;Entry:
;       [AL] = Function number
;               0: Queue rest
;                       [DX] = Duration ( 1 = 2.5 milliseconds )
;               1: Queue note
;                       [CX] = Frequency in Hz
;                       [DX] = Duration ( 1 = 2.5 milliseconds )
;               2: Query if voice is active
;                       Return in [AL]
;                         0 - voice is not currently active
;                        FF - voice is active
;              FE: Start music
;              FF: Stop music and flush queue
;
;Exit:
;       PSW.C set indicates that [AL] contains return information
;	[AL] =	1 - No room in the queue for this request
;		2 - Illegal function request
;               3 - Unsupported frequency
;	PSW.C reset indicates successful completion.
;
;
;Uses:
;	Per convention
;
;Preserves:
;	BX, CX, DX
;
;Exceptions:
;	None.
;****
;
;ALGORITHM:
;	case [AL] of
;	0,1 : begin
;		B$QNOTE (AX,CX,DX)
;		/* queues either the note or the rest */
;		end
;	  2 : B$QUERY
;		/* checks if the voice is active */
;	  3 : begin	/* in practice, this is ignored */
;		B$QSYNC()
;		end
;	4,5 : ENVELOPE SHAPE/DURATION
;		/* These functions are not supported */
;         6 : $MKNSE /* this function is not supported */
;         FC : SOUND ON/OFF /* this function is not supported */
;         FD : BEEP ON/OFF /* this function is not supported */
;         FE : B$QSTART
;              /* starts music */
;         FF : B$QFLUSH
;             /* stops music and flushes the queues */
;       endcase
;

DONOTE_TABLE	LABEL	WORD	; Dispatch table

	DW	B$QSTART	; start the music
	DW	B$QFLUSH	; stop the music & flush the queue
	DW	B$QNOTE	; queue a rest
	DW	B$QNOTE	; queue a note
	DW	B$QUERY	; query if voice is active or not

MAX_DONOTE	EQU	($ - DONOTE_TABLE)/2 ; Permissible entry value in AL
	
cProc	B$DONOTE,<PUBLIC,NEAR>,<BX,CX,DX,SI>	
cBegin				

	MOV	BX,OFFSET DGROUP:b$SNDQCB ; get addr of music queue in BX
	CMP	b$SNDFLG,0	;initialization been done?
	JNZ	DONOT1		;jump if already initialized
	INC	b$SNDFLG	;mark as initialized

	PUSH	AX
	XOR	AX,AX		;music queue starts at zero
	MOV	[BX].QUEBOT,AX	; set the bottom
	cCALL	B$INIQUE	; set put, get, num, note..
	MOV	AX,QLENTH	;    get length
	MOV	[BX].QUELEN,AX	; and set it in the block
	MOV	[BX].QUETOP,AX	;    to set the top of queue.
	POP	AX

DONOT1:
	CBW			; AH = 0/-1
	MOV	SI,AX		; SI will be used to point to the dispatcher
	INC	SI		; Add 2 to SI to make it 0-relative
	INC	SI		
	CMP	SI,MAX_DONOTE	; Check if arg within range
	JA	DONOTE_ERR	; Brif no - issue error

	SHL	SI,1		; Make it a word index
	CLD
	cCALL	DONOTE_TABLE[SI] ; Invoke respective handler
	JNC	DONOTE_EXIT	; No error - else error code is in DL
	XCHG	AX,DX		; Else get error code in AL

DONOTE_EXIT:			; Common exit point

cEnd				; End of B$DONOTE

DONOTE_ERR:			; Error case
	MOV	AL,2		; Issue voice-id invalid
	STC			; CF = 1 indicates error
	JMP	SHORT DONOTE_EXIT ; Exit...

	PAGE

;***
;B$QNOTE
;
;PURPOSE:
;       This routine queues either a note or a rest. By rest we mean
;       the short pause that goes to make Stacatto and Normal notes.
;       This routine calls a number of device dependent routines. These
;       device dependent routines check for the validity of frequency and
;       duration. They also output these quantities to the 8253 timer chip.
;       It either queues in the whole note or does'nt queue at all.
;
;ENTRY:
;	[BX] = QUEUE BLOCK BASE ADDR
;       [CX] = Frequeuncy
;       [DX] = Duration
;       [AL] = 0 OR 1 depending on whether it is a rest or
;               a music note respectively.
;
;EXIT:
;	[DL] = Error codes as specified by the routine B$DONOTE
;
;MODIFIED:
;       None
;
;****
cProc	B$QNOTE,<NEAR>,<AX,ES>	

localV	QBLK,QUE_BYTES 		; This block is used to temporarily
				; queue the note as it is processed
cBegin				

	OR	AL,AL		; was it a note ?
	JNZ	QNOTE		; brif so
	SUB	CX,CX		; Else queue in very high frequency

QNOTE:
	CMP	[BX].QUENUM,QLENTH-QUE_BYTES	; Is there enough space?
	JA	QUE_ERR1	; Brif not
	LEA	SI,QBLK 	; [si] = address of qblk
	MOV	BYTE PTR [SI],AL; temporarily queue the attribute

CHECK_DURATION:

;       [DX] = duration (1 = 2.5 millisecs)
;       [AX] = [AX] * 1.5
	
	MOV	AX,DX		;copy duration for adjustment
	SHR	AX,1		;divide by 2
	ADD	AX,DX		;duration = 1.5 * original duration
	JNC	DUROK		;Brif no overflow
	SBB	AX,AX		; else use maximum duration

DUROK:
	MOV	WORD PTR [SI+1],AX ; temporarily queue the duration

CHECK_FREQ:

; check for valid frequency and convert it to tics

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -