基于汇编语言的音乐播放器

在功能选择未进行歌曲播放时:

按数字 “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


     


猜你喜欢

转载自blog.csdn.net/wangruoao/article/details/51830012