在功能选择未进行歌曲播放时:
按数字 “1”, 播放歌曲“bei jing huan ying ni”
按数字 “2”, 播放歌曲“chun tian hua hui kai”
按数字 “3”, 播放歌曲“huan le song ”
按数字 “4”, 播放歌曲“dan yuan ren chang jiu”
按数字 “5”, 播放歌曲“qing fei de yi”
按数字 “6” 播放上一首歌曲
按数字 “7” 播放下一首歌曲
按 “ESC” 退出程序
按 “Enter” 退出程序
在歌曲播放时:
按u : Faster
按d : Slower
按p : Pause
按s : Start
按q : Quit
播放时同时打印音符
DATAS SEGMENT
SHOW DB 0AH,0DH
DB 20 DUP(' '),'*******************************************',0AH,0DH
DB 20 DUP(' '),'***LaLaLa! Welcome To The SongLibrary****',0AH,0DH
DB 0AH,0DH
DB 20 DUP(' '),'********************MENU*******************',0AH,0DH
DB 20 DUP(' '),'** 1: bei jing huan ying ni **',0AH,0DH
DB 20 DUP(' '),'** 2: chun tian hua hui kai **',0AH,0DH
DB 20 DUP(' '),'** 3: huan le song **',0AH,0DH
DB 20 DUP(' '),'** 4: dan yuan ren chang jiu **',0AH,0DH
DB 20 DUP(' '),'** 5: qing fei de yi **',0AH,0DH
DB 0AH,0DH
DB 20 DUP(' '),'*****************Function keys*************',0AH,0DH
DB 20 DUP(' '),'** 6 : last song 7 : next song **',0AH,0DH
DB 20 DUP(' '),'** u : Faster d : Slower **',0AH,0DH
DB 20 DUP(' '),'** p : Pause s : Start **',0AH,0DH
DB 20 DUP(' '),'** q : Quit Esc :exit **',0AH,0DH
DB 20 DUP(' '),'************Support @04th group************',0AH,0DH,'$'
WAIT_M DB 0AH,0DH
WAIT_M1 DB 'bei jing huan ying ni is singing','...',0AH,0DH,'$'
WAIT_M2 DB 'chun tian hua hui kai is singing','...',0AH,0DH,'$'
WAIT_M3 DB 'huan le song is singing','...',0AH,0DH,'$'
WAIT_M4 DB 'dan yuan ren chang jiu is singing','...',0AH,0DH,'$'
WAIT_M5 DB 'qing fei de yi is singing','...',0AH,0DH,'$'
flag DB ?
;flag1 DB '0'
ERROR_O DB 0AH,0DH,'Your order is error, please enter the right one:$'
Q DB 0AH,0DH,'The song is over, you can choose a song again.$'
P DB 0AH,0DH,'Have a rest, you can press s to start the song again.$'
S DB 0AH,0DH,'You has start the song again.',0AH,0DH,'$'
U DB 0AH,0DH,'You have made the beat shorter.',0AH,0DH,'$'
D DB 0AH,0DH,'You have made the beat longer.',0AH,0DH,'$'
OVER DB 0AH,0DH,'***************************************$'
DB 0AH,0DH,'this is a music program! please select!$'
DB 0AH,0DH,'***************************************$'
;****************************北京欢迎你*****************************
TONES_1 DW 659,2 DUP (659,784,659,587,659,587,659,659,587,440,523,659,587,587,523,440,523,587,659,784,587,659,880,784,440,587,523)
DW 587,523,440,523,587,659,784,587,659,880,784,784,659,587,659,587,523,784,880,587,440,659,587,587,523,-1
BEAT_1 DW 7 DUP(25*200),50*200,5 DUP(25*200),25*600,13 DUP(25*200),25*600,6 DUP(25*200),50*200,5 DUP(25*200),25*600,13 DUP(25*200),25*600
DW 12 DUP(25*200),50*400,6 DUP(25*200),50*200,4 DUP(25*200),50*200
;**************************春天花会开******************************
TONES_2 DW 392,392,392,392,440,392,330,294,262,262,262,220,294
DW 392,392,392,392,330,494,220,262,262,262,330,294,330,440,220,262,-1
BEAT_2 DW 25*200,3 DUP(25*200,50*200,25*200,50*200,50*200,50*400)
DW 25*200,50*200,25*200,50*200,50*200,50*200,50*200,4 DUP(25*200)
;****************************欢乐颂*****************************
TONES_3 DW 330,330,330,349,392,392,349,330,294,262,262,294,330,330,294,294
DW 330,330,349,392,392,349,330,294,262,262,294,330,294,262,262,-1
BEAT_3 DW 13 DUP(50*200),25*600,2 DUP(25*200)
DW 12 DUP(50*200),25*600,2 DUP(25*200)
;**************************但愿人长久******************************
TONES_4 DW 262,262,262,220,196,220,262,262,262,220,196,220,294
DW 330,262,220,330,262,220,294,262,220,349,349,220,262,294,294,196,247,220,247,262,-1
BEAT_4 DW 100,2 DUP(50*200,25*200,25*200,25*600,25*200,50*400)
DW 2 DUP(50*200,25*200,25*200),25*600,25*200,50*400,50*200,50*200,25*200,25*600,50*400,50*200,50*200,25*200,50*200,25*200,50*400
;***************************情非得已*****************************
TONES_5 DW 592,592,523,587,659,587,587
DW 4 DUP(523),784,784,659,784,3 DUP(659),587,659,698,659,659
DW 659,587,523,523,440,440,523,587
DW 4 DUP(392),440,523,523,440,659,523,523,587,587,523,523,-1
BEAT_5 DW 12 DUP(25*200),50*600,6 DUP(25*200),50*200,25*200,25*200,50*600
DW 6 DUP(25*200),50*200,25*200,25*200,50*600,12 DUP(25*200),50*600
BEAT DW ?
EXIT_BOX DB ?
SIDI DW 4 DUP(?)
DATAS ENDS
;数据段定义
STACKS SEGMENT
STACKS ENDS
;堆栈段定义
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
MAIN PROC FAR
MOV AX,DATAS
MOV DS,AX
LEA SI,SHOW
CALL DISPLAY ;显示菜单列表
CALL INPUT
DONE:
LEA SI,OVER
CALL DISPLAY ;显示结束菜单
MAIN ENDP
;************显示菜单列表*************
DISPLAY PROC NEAR
MOV DX,SI
MOV AH,09H
INT 21H
RET
DISPLAY ENDP
INPUT PROC FAR
PUSH AX
LEA BX,BEAT
MOV [BX],28010
LEA BX,EXIT_BOX
MOV [BX],0
MOV AH,01H
INT 21H ;输入字符
CMP AL,0DH ;回车退出
JZ EXIT
CMP AL,1BH ;ESC退出
JZ EXIT
CMP AL,'1' ;判断输入选择歌曲1,2,3,4,5
JZ SONG_1
CMP AL,'2'
JZ SONG_2
CMP AL,'3'
JZ SONG_3
CMP AL,'4'
JZ SONG_4
CMP AL,'5'
JZ SONG_5
CMP AL,'6'
JNE K7
CALL LAST
JMP K1
K7:
cmp al,'7'
jne INPUT
call nextT
JMP K1
JMP INPUT
K1: ;判断flag
;mov flag1,'0'
cmp flag,'1'
je SONG_1
cmp flag,'2'
je SONG_2
cmp flag,'3'
je SONG_3
cmp flag,'4'
je SONG_4
cmp flag,'5'
je SONG_5
SONG_1:
LEA SI,WAIT_M1 ;提示音乐播放中
CALL DISPLAY
call printf
LEA SI,TONES_1
LEA DI,BEAT_1 ;导入相应乐谱,音节存放地址
MOV SIDI,SI
MOV SIDI+2,DI ;用SIDI记录存放地址
CALL PLAY_MUSIC ;开启音乐播放程序
MOV flag,'1'
JMP INPUT
SONG_2:
LEA SI,WAIT_M2 ;提示音乐播放中
CALL DISPLAY
call printf
LEA SI,TONES_2
LEA DI,BEAT_2 ;导入相应乐谱,音节存放地址
MOV SIDI,SI
MOV SIDI+2,DI ;用SIDI记录存放地址
CALL PLAY_MUSIC ;开启音乐播放程
MOV flag,'2'
JMP INPUT
SONG_3:
LEA SI,WAIT_M3 ;提示音乐播放中
CALL DISPLAY
call printf
LEA SI,TONES_3
LEA DI,BEAT_3 ;导入相应乐谱,音节存放地址
MOV SIDI,SI
MOV SIDI+2,DI ;用SIDI记录存放地址
CALL PLAY_MUSIC ;开启音乐播放程序
MOV flag,'3'
JMP INPUT
SONG_4:
LEA SI,WAIT_M4 ;提示音乐播放中
CALL DISPLAY
call printf
LEA SI,TONES_4
LEA DI,BEAT_4 ;导入相应乐谱,音节存放地址
MOV SIDI,SI
MOV SIDI+2,DI ;用SIDI记录存放地址
CALL PLAY_MUSIC ;开启音乐播放程序
MOV flag,'4'
JMP INPUT
SONG_5:
LEA SI,WAIT_M5 ;提示音乐播放中
CALL DISPLAY
call printf
LEA SI,TONES_5
LEA DI,BEAT_5 ;导入相应乐谱,音节存放地址
MOV SIDI,SI
MOV SIDI+2,DI ;用SIDI记录存放地址
CALL PLAY_MUSIC ;开启音乐播放程序
MOV flag,'5'
JMP INPUT
;***************************************************
nextT proc near ;下一首
push ax
mov al,flag
cmp al,'5'
je L1
inc al
mov flag,al
jmp L2
L1: mov flag,'1'
L2: pop ax
ret
nextT endp
;***************************************************
last proc near ;上一首
push ax
mov al,flag
cmp al,'1'
je L3
dec al
mov flag,al
jmp L4
L3: mov flag,'5'
L4: pop ax
ret
last endp
;***************************************************
EXIT:
POP AX ;栈顶内容取出并存到目的操作数中,同时修正堆栈指针
MOV AH,4CH
INT 21H ;返回DOS系统
RET
INPUT ENDP
;******************音乐播放子函数*******************
PLAY_MUSIC PROC FAR
AGAIN:
CMP [SI],0FFFFH ;判断一段音乐是否结束
JZ CIRCLE ;若结束,则单曲循环
mov di,[si]
call printf
CALL KEY_C ;按键中断运行
LEA BX,EXIT_BOX
CMP BYTE PTR[BX],3 ;出错
JZ ERROR
CMP BYTE PTR[BX],2 ;退出
JZ RETURN
CMP BYTE PTR[BX],1 ;暂停
JZ AGAIN
CMP BYTE PTR[BX],0 ;开始
JZ NEXT
ERROR: ;错误控制
PUSH SI
LEA SI,ERROR_O
CALL DISPLAY
POP SI
JMP RETURN
NEXT:
MOV AL,0B6H ;计数器的控制字要写入控制寄存器
OUT 43H,AL ;输入控制字寄存器,选用方式2,工作在方式三,分频器
MOV DX,12H ;把给定频率的高八位送给DX
MOV AX,3280H ;把给定频率的低八位送给AX
DIV WORD PTR[SI] ;SI的内容为给定的频率,放入
OUT 42H,AL ;低八位写入计数器二
MOV AL,AH ;将高八位内容送到AL
OUT 42H,AL ;用两次计数器通道2用于发声
CALL SPK_ON ;启动蜂鸣器
MOV CX,[DI]
BEAT_M: ;节拍控制
PUSH CX
LEA BX,BEAT
MOV CX,[BX]
DELAY_M: ;延时控制
LOOP DELAY_M
POP CX
LOOP BEAT_M
INC SI
INC SI
INC DI
INC DI
CALL SPK_OFF ;关闭蜂鸣器
JMP AGAIN
CIRCLE:
MOV SI,SIDI
MOV DI,SIDI+2 ;将其地址送回SI、DI
JMP PLAY_MUSIC
RETURN:
RET ;返回系统
PLAY_MUSIC ENDP
;***************按键中断子函数*************
KEY_C PROC FAR
PUSH AX
MOV AH,0BH ;检验键盘状态
INT 21H
;XOR AH,AH
CMP AL,0FFH ;无输入时
jz OK
JMP OUT_K
OK: MOV AH,01H
INT 21H ;输入
CMP AL,0DH
JZ QUIT
CMP AL,1BH
JZ QUIT
CMP AL,'q' ;判断输入选择功能
JZ QUIT
CMP AL,'u'
JZ UP
CMP AL,'d'
JZ DOWN
CMP AL,'p'
JZ PAUSE
CMP AL,'s'
JZ START_K
JMP ERROR_W
START_K: ;暂停后开始
LEA BX,EXIT_BOX
MOV [BX],0
PUSH SI
LEA SI,S
CALL DISPLAY
POP SI
JMP OUT_K
PAUSE: ;暂停
LEA BX,EXIT_BOX
MOV [BX],1
PUSH SI
LEA SI,P
CALL DISPLAY
POP SI
JMP OUT_K
QUIT: ;退出程序
LEA BX,EXIT_BOX
MOV [BX],2
PUSH SI
LEA SI,Q
CALL DISPLAY
POP SI
JMP OUT_K
DOWN: ;减速
LEA BX,BEAT
MOV AX,[BX]
ADD AX,1000
MOV [BX],AX
PUSH SI
LEA SI,D
CALL DISPLAY
POP SI
JMP OUT_K
UP: ;加速
LEA BX,BEAT
MOV AX,[BX]
SUB AX,1000
MOV [BX],AX
PUSH SI
LEA SI,U
CALL DISPLAY
POP SI
JMP OUT_K
ERROR_W: ;程序出错
LEA BX,EXIT_BOX
MOV [BX],3
JMP OUT_K
OUT_K:
POP AX ;恢复AX的值
RET
KEY_C ENDP
;**************开蜂鸣器子函数***************
SPK_ON PROC NEAR
PUSH AX ;保存ax的值
IN AL,61H ;获取61h端口的当前值
OR AL,03H ;把61h端口低二位置1,即打开蜂鸣器
OUT 61H,AL ;输出数据到61h端口
POP AX ;恢复ax的值
RET
SPK_ON ENDP
;**************关蜂鸣器子函数***************
SPK_OFF PROC NEAR
PUSH AX ;保存ax的值
IN AL,61H ;获取61h端口的当前值
AND AL,0FCH ;把61h端口低二位置0,即关闭蜂鸣器
OUT 61H,AL ;输出数据到61h端口
POP AX ;恢复ax的值
RET
SPK_OFF ENDP
printf proc near ;音符打印子程序
cmp di,131
je t1
cmp di,147
je t2
cmp di,165
je t3
cmp di,175
je t4
cmp di,196
je t5
cmp di,221
je t6
cmp di,248
je t7
cmp di,262
je t1
cmp di,294
je t2
cmp di,330
je t3
cmp di,350
je t4
cmp di,393
je t5
cmp di,441
je t6
cmp di,495
je t7
cmp di,525
je t1
cmp di,589
je t2
cmp di,661
je t3
cmp di,700
je t4
cmp di,786
je t5
cmp di,882
je t6
cmp di,990
je t7
cmp al,'p' ;暂停
je again
ret
t1: mov dx,'1'
jmp tto3
t2: mov dx,'2'
jmp tto3
t3: mov dx,'3'
jmp tto3
t4: mov dx,'4'
jmp tto3
t5: mov dx,'5'
jmp tto3
t6: mov dx,'6'
jmp tto3
t7: mov dx,'7'
jmp tto3
ret
tto3: mov ah,02h
int 21h
ret
printf endp
CODES ENDS
END MAIN