📄 c06_07.asm
字号:
; 演奏乐曲的程序
.model small
.386
DATA SEGMENT
MUS_FREG DW 330,294,262,294,3 DUP (330)
DW 3 DUP (294),330,392,392
DW 330,294,262,294,4 DUP (330)
DW 294,294,330,294,262,-1
MUS_TIME DW 6 DUP (4),9
DW 2 DUP (4,4,9)
DW 12 DUP (4),18
FLAG1 DB ? ; 保存中断屏蔽字
FLAG2 DB ? ; 保存61H口内容
DATA ENDS
STACK SEGMENT PARA STACK
DB 200 DUP (0)
STACK ENDS
CODE SEGMENT
ASSUME DS:DATA,SS:STACK,CS:CODE
OLD_INT DW ?,?
MAIN PROC FAR
MOV AX, 3508H
INT 21H
MOV OLD_INT, BX
MOV OLD_INT+2, ES
LEA DX, NEW08H
MOV AX, SEG NEW08H
MOV DS, AX
MOV AX, 2508H
INT 21H
MOV AX,DATA
MOV DS,AX
CALL PLAY_MUSIC ; 演奏指定的曲目
LDS DX, DWORD PTR OLD_INT
MOV AX, 2508H
INT 21H
MOV AH,4CH
INT 21H
MAIN ENDP
PLAY_MUSIC PROC NEAR
IN AL, 61H
MOV FLAG2, AL
IN AL, 21H
MOV FLAG1, AL
AND AL, 0FEH ; 开定时器中断
out 21H, AL
LEA SI,MUS_FREG ; SI: 频率表的起始地址
LEA BP,MUS_TIME ; BP: 节拍时间表的起始地址
A_FREG: MOV DI,[SI] ; DI: 音符的频率
CMP DI,-1 ; -1 为一个曲目的结束标志
JE END_MUSIC
MOV CX,DS:[BP] ; 由节拍换算出的中断次数
CALL GENSOUND
DELAY: CMP CX, 0
JNE DELAY
ADD SI,2
ADD BP,2
JMP A_FREG
END_MUSIC:
MOV AL, FLAG1
OUT 21H, AL
MOV AL, FLAG2
OUT 61H, AL ; 恢复61H端口内容
RET
PLAY_MUSIC ENDP
GENSOUND PROC NEAR
PUSH AX
PUSH DX
PUSH DI
MOV AL,0B6H
OUT 43H,AL
MOV DX,12H
MOV AX,348CH
DIV DI
OUT 42H,AL ; 计数初值=1193100/给定的频率DI
MOV AL,AH
OUT 42H,AL
IN AL,61H
MOV AH,AL
OR AL,3
OUT 61H,AL
POP DI
POP DX
POP AX
RET
GENSOUND ENDP
NEW08H PROC FAR
PUSHF
CALL DWORD PTR OLD_INT
DEC CX
IRET
NEW08H ENDP
CODE ENDS
END MAIN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -