汇编课设(电子钢琴:源代码)

实现结果


程序的启动有点像小霸王游戏机的游戏,喜欢汇编的朋友可以发信与我一起讨论,发声程序参考的是一本汇编教材,程序写作和上传相隔有点久远,记不太清,千行代码,算是学生时代一个比较得意的课设

编译器下载

编译器可在我的上传资源中查找,已注明:汇编编译器
https://download.csdn.net/download/m0_37772174/10837741

注意事项

输入严格区分大小写,启动时应输入大写来C启动复杂版钢琴

汇编代码

;作者:cclplus
;仅供学习交流使用
DATA   SEGMENT
MEM1	DW 200 DUP(0)
MEM2 DW 200 DUP(0);用于记录输入
Gao1   DB  0AH,  0DH,  'Hello User.THIS  IS  GMusic!'
	DB  0AH,  0DH,	'Enjoy music!$'
Gao2   DB  0AH,  0DH,  'INPUT  ERROR!$'
Gao3   DB  0AH,  0DH,  'PLEASE  INPUT AGAIN!$'
Cue_list    DB  0AH,  0DH,  '*****************************'            
             DB  0AH,  0DH,  'PressB   Begin your music lite'
                 DB  0AH,0DH,'PressC Begin your music Gao'
              DB  0AH,  0DH,  'PressP  Play back'
             DB  0AH,  0DH,  '*****************************'
	     DB  0AH,  0DH,  '$'
soundcolor dw 0     ;音色缓存,用于改变播放或弹奏时琴上音响和琴面上点阵的颜色 
key_tune dw 0      ;按键状态缓存,用于判断是否有手动按键,1为有,0为无
keynum dw 1       ;按键编号缓存,用于提取对应的按键位置
 delay_time dw 7000  ;延时缓存,用于播放时存入bx中来计数
  count dw 0;
	     ;------------------------------进度条字符-----------------------
st_load db 10                                               ;起始行
     db 4                                                 ;起始列
     db 0bh                                               ;字体颜色
     db 'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'
     db 00
;------------------------------字符定义-----------------------
start_col db ?                                              ;存储起始行
text db 14                                                 ;起始行
     db 2                                                ;起始列
     db 0fh                                              ;字体颜色
     db 'MUSIC    ^_^',0ffh,0ffh         ;显示字
     db '                HAVE A GOOD TIME!',0ffh         ;以0ffh来判断是否换行
     db ' [-1-2-3-4-5-6-7-8-]',0ffh
     db 'Press   p: replay',0ffh
     db 'Press   Esc: exit',0ffh
     db 00
d_text db 14                                                 ;起始行
     db 2                                                ;起始列
     db 0fh                                              ;字体颜色
     db 'MUSIC    ^_^',0ffh,0ffh         ;显示字
     db '                HAVE A GOOD TIME!',0ffh         ;以0ffh来判断是否换行
      db '  [-1-2-3-4-5-6-7-]',0ffh
     db 'g [ q w e r t y u ]  p:replay  ',0ffh
     db 'z [ a s d f g h j ]   enter: stop',0ffh
     db 'd [ z x c v b n m ]    Esc: exit',0ffh
     db 00
;------------------------------高级版白色琴键坐标-------------------
d_st_lx dw  50,61,72,83,94,105,116                            ;起点横坐标
      dw  127,138,149,160,171,182,193                       
      dw  204,215,226,237,248,259,270
d_st_y  dw  50                                            ;起点纵坐标
d_ed_lx dw  60,71,82,93,104,115,126                           ;终点横坐标
      dw  137,148,159,170,181,192,203            
      dw  214,225,236,247,258,269,280
d_ed_y  dw  90                                            ;终点纵坐标
;------------------------------高级版黑色琴键坐标--------------------------
d_bt_x  dw 57,68,90,101,112                                  ;起点横坐标
      dw 134,145,167,178,189 
      dw 211,222,244,254,265
d_bt_y  dw  50                                            ;起点纵坐标
d_bd_x  dw  64,75,97,108,119                                ;终点横坐标
      dw  141,152,174,185,196
      dw  218,229,251,262,273
d_bd_y  dw  70                                        
;----------------------------简版乐器白色琴键坐标-------------------
st_lx dw  50,80,110,140,170,200,230,260                          ;起点横坐标
st_y  dw  50                                            ;起点纵坐标
ed_lx dw 70,100,130,160,190,220,250,280   ;终点横坐标
ed_y  dw  90                                            ;终点纵坐标
;----------------------------简版乐器黑色琴键坐标--------------------------
bt_x  dw 71,101,131,161,191,221,251                                 ;起点横坐标
bt_y  dw  50                                            ;起点纵坐标
bd_x  dw  79,109,139,169,199,229 ,259                               ;终点横坐标
bd_y  dw  70                                            ;终点纵坐标
;频率列表
;---------------------------高级版音乐频率值----------------------------
d_tune  dw 220,247,278,294,330,371,416                        ;低音
      dw 441,495,556,589,661,742,833                       ;中音
      dw 882,990,1112,1178,1322,1484,1655                  ;高音
;---------简版
TUNE      DW  262,  294,  330,  347,  392,  440,  494,  523  
DATA   ENDS
STACK   SEGMENT   PARA  STACK  'STACK'                   
STA      DB  300 DUP('STACK')                          
STACK   ENDS
CODE    SEGMENT
ASSUME DS: DATA,  SS:  STACK,  CS: CODE,  ES: DATA
START: MOV DI ,0H
		MOV  AX, DATA                   
		MOV  DS, AX
          MOV  ES, AX
          MOV  AX, STACK                        
          MOV  SS, AX
SHOW    MACRO  B             
          MOV  DX, OFFSET  B                               
          MOV  AH, 09H                            
          INT  21H;显示字符串
ENDM
          SHOW  Gao1   ;显示Gao1中的内容                             
LOP:      SHOW  Cue_list;显示操作提示清单                            
          MOV  AH, 01H                                
          INT   21H;从键盘上输入一个字符,将其对应字符的ASCII码送入AL中
          			;并在屏幕上显示该字符                              
          CMP  AL, 42H ;判断键盘上的值是否为B(区分大小写)                                                                        
          JNZ   sc;如果键盘上的内容不是B,检查是否是C
          JMP LITE_v;如果输入了B,那么我们进入简版的音乐演奏器
SC:		cmp al,43h;判断键盘上的值是否是C,如果是C,进入高级音乐演奏器
		JNE LEXIT;
;高级音乐演奏器启动 
GAO_V:
;---依次调用:开场效果--初始化--键盘扫描--按键处理程序-------------
  call show_load                                       ;调用进度条显示程序
;---延时20*waitf----  
  push bx
  mov bx,20
d_del:  
  call waitf
  dec bx
  jnz d_del
  pop bx
;-----------不一样的重新开始-------  
d_restart:                  ;自动播放音乐时,按‘enter’键或音乐完全结束后会返回这里
PUSH AX
PUSH BX
PUSH CX
PUSH DX 
PUSH BP
  call d_init						;调用不一样的初始化程序
  POP BP
  POP DX
  POP CX
  POP BX
  POP AX
d_new_scan:  	              ;键盘扫描程序没有检测到功能键被按下时,会返回这里
  call d_scan_key				    ;调用键盘扫描程序,扫描所按下的键
  CALL REMEMBER
;-----------按键处理-------
  call d_do_key
;----重新扫描---
  jmp d_new_scan					  ;重新扫描有无键按下,直到按下esc键
;高级音乐演奏器程序截止
;-*-*-*-*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-*-*-*-*-*-*		
;简版音乐启动
LITE_v: CALL SHOW_LOAD

push bx
  mov bx,20
del:  
  call waitf
  dec bx
  jnz del
  pop bx
restart:                  ;自动播放音乐时,按‘enter’键或音乐完全结束后会返回这里  
  call init                      
 new_scan:  	              ;键盘扫描程序没有检测到功能键被按下时,会返回这里
  call scan_key				    ;调用键盘扫描程序,扫描所按下的键
  CALL REMEMBER
 call do_key;进行按键处理
  jmp new_scan	;----重新扫描---
replay proc near
push ax
push cx
PUSH SI
mov cx,count
mov di,0
 replay1:
 push ax
mov ax,700000
mov delay_time,ax
pop ax 
replay2:
 push di
 MOV si,MEM1[DI]
 mov ax,mem2[di]
 mov keynum,ax
call do_key
call waitf
pop di
 inc di
 inc di
 cmp CX,DI
JA replay2
POP SI
pop cx
pop ax
ret
replay endp
d_replay proc near
push ax
push cx
PUSH SI
mov cx,count
mov di,0
 dreplay1:
 push ax
mov ax,700000
mov delay_time,ax
pop ax 
dreplay2:
 push di
 MOV si,MEM1[DI]
 mov ax,mem2[di]
 mov keynum,ax
call d_do_key
call waitf
pop di
 inc di
 inc di
 cmp CX,DI
JA dreplay2
POP SI
pop cx
pop ax
JMP d_new_scan
d_replay endp
remember proc near
push cx
PUSH SI
push ax
mov cx,count
mov DI,CX
	MOV MEM1[DI],SI
	MOV AX,keynum
	MOV MEM2[DI],AX
	INC	CX
	inc cx
	mov count,cx
	pop ax
POP SI
pop cx
ret
remember endp
;**********************************矩形绘制宏*******************************
draw macro start_x,start_y,end_x,end_y,color
        local draw_next
;local :避免宏重复调用时,标号的重复
;功能:画填充的矩形
;使用条件:start_x < end_x ,start_y < end_y
       push ax                                          ;堆栈
       push bx
       push cx
       push dx
       
       mov ah,0ch                                       ;12号功能,写像素
       mov al,color                                      ;取颜色值
       mov bh,0                                         ;页号0
       mov cx,start_x                                    ;列起始点
       mov dx,start_y                                    ;行起始点
draw_next:
       int 10h                                           ;画点
       inc cx                                            ;画横线
       cmp cx,end_x                                     ;比较行是否画完
       jne draw_next                                     ;画另一行
       mov cx, start_x                                    ;另一行的起始点
       inc dx                                           ;下一行
       cmp dx,end_y                                     ;比较列是否画完
       jne draw_next                                     ;未完继续画
       
       pop dx                                           ;出栈
       pop cx
       pop bx
       pop ax
       endm
;********************************矩形点阵绘制宏****************************
draw_point macro start_x,start_y,end_x,end_y,color
        local draw_next
;local :避免宏重复调用时,标号的重复
;功能:画矩形点阵
;使用条件:start_x < end_x ,start_y < end_y
       push ax
       push bx
       push cx
       push dx
       
       mov ah,0ch                                       ;12号功能,写像素
       mov al,color                                      ;设置颜色
       mov bh,0                                         ;页号0
       mov cx,start_x                                    ;列起始点
       mov dx,start_y                                    ;行起始点
draw_next:
       int 10h                                           ;画点
       inc cx
       inc cx                                            ;隔一点
       cmp cx,end_x                                      ;比较行是否画完
       jne draw_next                                     ;画另一行
       mov cx, start_x                                    ;另一行的起始点
       inc dx
       inc dx                                            ;隔一行
       cmp dx,end_y                                     ;比较列是否画完
       jne draw_next                                     ;未完继续画
       
       pop dx
       pop cx
       pop bx
       pop ax
       endm

;****************************矩形框绘制宏****************************
drawsqre macro start_x,start_y,end_x,end_y,color
       local row_up,row_down,rank_left,rank_right
;--功能:画矩形框。
       push ax
       push bx
       push cx
       push dx
       push si
 
       mov ah,0ch                                       ;12号功能,写像素
       mov al,color
       mov bh,0
       mov cx,start_x
       mov dx,start_y
row_up:                                                  ;画上边
       int 10h
       inc cx
       cmp cx,end_x
       jne row_up
 
rank_right:                                              ;画右边
       int 10h
       inc dx
       cmp dx,end_y
       jne rank_right
 
       mov cx, start_x                                   ;下边起始点
       mov si,end_x
       inc si
row_down:                                              ;画下边
       int 10h
       inc cx
       cmp cx,si
       jne row_down
       
       mov dx,start_y                                    ;左边起始点
       mov cx,start_x
rank_left:                                               ;画左边
       int 10h
       inc dx
       cmp dx, end_y
       jne rank_left
       
       pop si
       pop dx
       pop cx
       pop bx
       pop ax
       endm
 

;*************************在屏幕上显示字符************************
;--功能:显示字符和说明。
show_text proc near
;--------------------初始化光标的位置----------  
   lea di,text						;载入字符串首地址
	mov dh,[di]						;2号功能,赋行值
	inc di								;取得列
	mov dl,[di]					        ;2号功能,赋列值
	mov start_col,dl				     ;保存开始列
	mov ah,2							   ;2号功能,设置光标位置,dh=行号;dl=列号;bh=页号
	mov bh,0							   ;0页
	int 10h
;---------------取颜色值-------------	
   inc di								;取得颜色值
	mov bl,[di]						;赋颜色值
;---------------显示字符--------------
char_write:
	inc di								;取得要显示的字符
	mov al,[di]
	cmp al,0ffh						;行结束否
	je bump_row						;下一行
	cmp al,0							     ;结束否
	jz end_text
	call show_char				     ;显示字符
	jmp char_write					;下一个字符
	end_text:
	ret
;---光标下移一行---
bump_row:
	inc dh								;2号功能,下一行
	mov dl,start_col					;2号功能,赋开始列值
	mov ah,2								;2号功能,设光标位置
	mov bh,0                  ;2号功能,页号
	int 10h
	jmp char_write
show_text endp
;*************************在高级演奏器屏幕上显示字符************************
;--功能:显示字符和说明。
show_d_text proc near
;--------------------初始化光标的位置----------  
   lea di,d_text						;载入字符串首地址
	mov dh,[di]						;2号功能,赋行值
	inc di								;取得列
	mov dl,[di]					        ;2号功能,赋列值
	mov start_col,dl				     ;保存开始列
	mov ah,2							   ;2号功能,设置光标位置,dh=行号;dl=列号;bh=页号
	mov bh,0							   ;0页
	int 10h
;---------------取颜色值-------------	
   inc di								;取得颜色值
	mov bl,[di]						;赋颜色值
;---------------显示字符--------------
d_char_write:
	inc di								;取得要显示的字符
	mov al,[di]
	cmp al,0ffh						;行结束否
	je d_bump_row						;下一行
	cmp al,0							     ;结束否
	jz end_text
	call show_char				     ;显示字符
	jmp d_char_write					;下一个字符
	end_text:
	ret
;---光标下移一行---
d_bump_row:
	inc dh								;2号功能,下一行
	mov dl,start_col					;2号功能,赋开始列值
	mov ah,2								;2号功能,设光标位置
	mov bh,0                  ;2号功能,页号
	int 10h
	jmp d_char_write
show_d_text endp
;***********************显示字符************************
;--功能:横向显示字符。
show_char proc near
push ax
push bx
push cx
   mov ah,9							 ;9号功能,显示字符bl=字符属性,bh=页号;al=字符ASCII码;cx=写入字符数
	mov bh,0							 ;0页
	mov cx,1                  ;写入一个字符
	int 10h
	
   inc dl								;2号功能,赋列值,这里为光标右移一个字符位
	
   mov ah,2					      ;设置光标位置
	mov bh,0							;0页
	int 10h
pop cx
pop bx
pop ax
	ret
show_char endp
;***********************初始化*****************************
;--功能:初始化屏幕和显示,显示字符说明,绘制出电子琴。
init proc near
    mov ax,data
    mov ds,ax  
;------------屏幕以及显示初始化-------------
    mov ah,0 						;0号功能,设置屏幕
    mov al,0dh            ;文本分辨率40*25;像素框8*8;像素分辨率320*200;颜色16
	 int 10h
    
    mov ah,0bh            ;11号功能,设置背景颜色,bh=0时,设置背景颜色
    mov bh,0
    mov bl,00h						;背景色
    int 10h
;------------------显示字符说明------------------    
	 call show_text					;显示字符串
;------------------绘制电子琴------------------
    call draw_dzq			    ;绘制琴身和底座

	 ret 
init endp


;************绘制电子琴***************
;--功能:绘制琴身和底座,黑白键,效果灯
draw_dzq	 proc near
  draw_point 40,52,44,92,07h      ;调用矩形点阵宏,绘制音响孔左
  draw_point 288,52,292,92,07h    ;调用矩形点阵宏,绘制音响孔右

  drawsqre 38,50,292,92,07h       ;调用矩形框绘制宏,绘制音响框
  drawsqre 44,30,286,93,07h       ;调用矩形框绘制宏,绘制底框1
  draw 45,30,285,94,08h	         ;调用矩形绘制宏,绘制琴身颜色
  drawsqre 45,30,285,94,07h       ;调用矩形框绘制宏,绘制底框2

  draw_point 150,34,282,38,07h    ;调用矩形点阵宏,绘制正面音孔  

  drawsqre 46,31,284,32,00h       ;调用矩形框绘制宏,绘制琴上边 
  drawsqre 49,48,280,49,00h       ;调用矩形框绘制宏,绘制琴挡
	
  draw 55,38,60,41,0ah				  ;调用矩形绘制宏,绘制灯1
  draw 65,38,70,41,07h				  ;调用矩形绘制宏,绘制灯2


  draw 271,42,275,46,07h         ;调用矩形绘制宏,绘制5个指示灯
  draw 265,42,269,46,07h
  draw 259,42,263,46,07h
  draw 253,42,257,46,07h
  draw 247,42,251,46,07h
  ;----绘制白键----
	 lea si,st_lx					       ;画8个白色键
    lea di,ed_lx
    mov cx,8
init_draw:
    draw [si],st_y,[di],ed_y,0fh     ;调用矩形绘制宏,绘制白色矩形作为白键
    draw [si],90,[di],93,07h		;调用矩形绘制宏,绘制灰色矩形作为阴影
    add si,2
    add di,2
    loop init_draw	

;----绘制黑键----
    lea si,bt_x							;画7个黑色键
    lea di,bd_x
    mov cx,7
init_block:
    draw [si],bt_y,[di],bd_y,00h  ;调用矩形绘制宏,绘制黑色矩形作为黑键
    add si,2
    add di,2
    loop init_block	
    RET
draw_dzq ENDP



;*************************进度条显示程序************************
;---功能:程序启动时,显示动态进度条,快慢与waitf子程序有关
show_load proc near
    mov ax,data
    mov ds,ax  
 
    mov ah,0 						;0号功能,设置屏幕
    mov al,0dh            ;文本分辨率40*25;像素框8*8;像素分辨率320*200;颜色16
	 int 10h
    
    mov ah,0bh            ;11号功能,设置背景颜色,bh=0时,设置背景颜色
    mov bh,0
    mov bl,00h						 ;背景色
    int 10h
;--------------------初始化光标的位置----------  
   lea di,st_load 					;载入字符串首地址
	mov dh,[di]						  ;2号功能,赋行值
	inc di								  ;取得列
	mov dl,[di]					    ;2号功能,赋列值
	mov start_col,dl				 ;保存开始列
	mov ah,2							;2号功能,设置光标位置,dh=行号;dl=列号;bh=页号
	mov bh,0							;0页
	int 10h
;---------------取颜色值-------------	
   inc di								 ;取得颜色值
	mov bl,[di]						 ;赋颜色值
;-----------绘制矩形载入外框------------ 
drawsqre 31,78,296,88,08h   ;调用矩形框绘制宏,绘制载入框 内,灰色
drawsqre 29,76,298,90,0fh   ;调用矩形框绘制宏,绘制载入框 外,纯白
;---------------显示字符--------------
load_write:
	inc di								 ;取得要显示的字符
	mov al,[di]
	cmp al,0							  ;结束否
	jz end_load
	call show_char				 ;调用显示字符程序,行显示
   call waitf
	jmp load_write				 ;下一个字符
	end_load:
	ret
show_load endp
;********************简版琴键处理程序********************
do_key proc near
;---显示按下---
	push bx			                                        ;bx入栈
	mov bx,keynum	                                     ;取按键编号缓存值,存入bx
	call key_down				                                ;在屏幕上显示按下状态
;----按下时琴身点阵颜色改变--纯白--
draw_point 40,52,44,92,0fh                      ;调用矩形点阵宏,绘制音响孔左点阵
draw_point 288,52,292,92,0fh                    ;调用矩形点阵宏,绘制音响孔右点阵
draw_point 150,34,282,38,0fh                    ;调用矩形点阵宏,绘制正面音孔点阵 
	pop bx                                    ;bx出栈   
;---发出声音---	
   lea bx,tune                                ;装入对应频率段地址到bx中
   push si                                   ;si入栈
	mov si,keynum                             ;取按键编号缓存值,存入si
	mov di,[bx+si]                              ;取对应编号的音符频率值,存入di
	call play_hand				 ;调用手动发声程序
	pop si                                     ;出栈
;---显示弹起---		
   push bx
	mov bx,keynum				                    ;在屏幕上显示弹起状态
	call key_up
;----按下时琴身点阵颜色恢复--灰色--
draw_point 40,52,44,92,07h                     ;调用矩形点阵宏,绘制音响孔左
draw_point 288,52,292,92,07h                   ;调用矩形点阵宏,绘制音响孔右
draw_point 150,34,282,38,07h                   ;调用矩形点阵宏,绘制正面音孔 
	pop bx

  mov key_tune,0	                           ;恢复按键状态缓存,
;-------	
   ret
do_key endp
;*****高级版本琴键处理
d_do_key proc near
;---显示按下---
	push bx			                                        ;bx入栈
	mov bx,keynum	                                     ;取按键编号缓存值,存入bx
	call d_key_down				                                ;在屏幕上显示按下状态
;----按下时琴身点阵颜色改变--纯白--
draw_point 40,52,44,92,0fh                      ;调用矩形点阵宏,绘制音响孔左点阵
draw_point 288,52,292,92,0fh                    ;调用矩形点阵宏,绘制音响孔右点阵
draw_point 150,34,282,38,0fh                    ;调用矩形点阵宏,绘制正面音孔点阵 
	pop bx                                    ;bx出栈   
;---发出声音---	
   lea bx,d_tune                                ;装入对应频率段地址到bx中 
   push si                                   ;si入栈
	mov si,keynum                             ;取按键编号缓存值,存入si
	mov di,[bx+si]                              ;取对应编号的音符频率值,存入di
	call play_hand				 ;调用手动发声程序
	pop si                                     ;出栈
;---显示弹起---		
   push bx
	mov bx,keynum				                    ;在屏幕上显示弹起状态
	call d_key_up
;----按下时琴身点阵颜色恢复--灰色--
draw_point 40,52,44,92,07h                     ;调用矩形点阵宏,绘制音响孔左
draw_point 288,52,292,92,07h                   ;调用矩形点阵宏,绘制音响孔右
draw_point 150,34,282,38,07h                   ;调用矩形点阵宏,绘制正面音孔 
	pop bx
  mov key_tune,0	                           ;恢复按键状态缓存,
;-------	
   ret
d_do_key endp
;************************任意时间延时程序************************

;************************任意时间延时程序************************
waitf proc near
push ax                      ;ax入栈
push cx
mov cx,delay_time             ;t=delay_time*15.08us
;-----------15.08us硬件延时------------
waitf1:
	in al,61h				
	and al,10h						;检查pb4口
	cmp al,ah						;判断al变化否
	je waitf1						;等待al变化
	mov ah,al						;保存pb4的新状态(al中)
	loop waitf1                 ;cx-1不为0则回到waitf
	pop cx
	pop ax                     ;ax出栈
;----------------	 
   ret
waitf endp

;*************返回dos程序***************
exit proc near
   mov ah,4ch
	int 21h
   ret
exit endp


scan_key proc near

mov ah,0						;读键盘,键盘扫描码存入ah,ASCII码存入al
int 16h

mov dl,al                    ;al中的ASCII码存入dl,为了便于修改,通过ASCII码来检测
;--------------检测是否为结束键--------------
cmp ah,01h					;是否是结束键,Esc键作为结束键,其扫描码为01h
jne flag_scan				;若不是继续检测
call exit					;若是则退出
;----------扫描琴键--------
flag_scan:
									
dkey_l1:
	cmp dl,'1'						;是否是0
	jne dkey_l2						;不是则继续扫描
	mov keynum,0					;是则改变按键编号缓存
   mov key_tune,1          ;改变按键状态缓存
	jmp scan_end					;键扫描结束
dkey_l2:	
	cmp dl,'2'					   ;是否是2
	jne dkey_l3
	mov keynum,2
   mov key_tune,1
	jmp scan_end
dkey_l3:
	cmp dl,'3'					     ;是否是3
	jne dkey_l4
	mov keynum,4
   mov key_tune,1
	jmp scan_end
dkey_l4:	
	cmp dl,'4'					     ;是否是4
	jne dkey_l5
	mov keynum,6
   mov key_tune,1
	jmp scan_end
dkey_l5:
	cmp dl,'5'						;是否是5
	jne dkey_l6
	mov keynum,8
   mov key_tune,1
	jmp scan_end
dkey_l6:
   cmp dl,'6'    				;是否是6
	jne dkey_l7
	mov keynum,10
   mov key_tune,1
	jmp scan_end
dkey_l7:
   cmp dl,'7'    				;是否是7
	jne dkey_1
	mov	keynum,12
   mov key_tune,1
	jmp scan_end

dkey_1:
	cmp dl,'8'						;是否是8
	jne scan_end					
	mov keynum,14
   mov key_tune,1				
	jmp scan_esc
scan_esc:
	cmp dl,27
	jne scan_end
	jmp Lexit						
scan_end:
   cmp dl,'p'              ;判断是否按下了自动播放键
   JE REPLAY
	jnz  hand_play				;若不是,继续扫描
   jmp restart				    ;演奏结束,返回restart
hand_play:
  cmp key_tune,1				;取按键状态缓存值,判断是否手动演奏,1为有,0为无
  jnz  again					;若不是,重新扫描有无键按下
  ret                    ;若是音键,则返回并继续进行音键处理
again:
jmp new_scan
scan_key endp
;***************************按下显示程序************************
;--功能:显示按下键盘时相应键盘状态。
key_down proc near
push si
push di

lea si,st_lx			             ;载入音键起始坐标首地址
lea di,ed_lx				           ;载入音键结束坐标首地址

draw [si+bx],90,[di+bx],92,0fh   ;调用矩形绘制宏,bx为按键标号缓存值,画一小块琴键色方块
draw [si+bx],92,[di+bx],94,07h   ;调用矩形绘制宏,bx为按键标号缓存值,画一小块琴键阴影色方块
pop di
pop si
ret
key_down endp
;***************************按下显示程序(为高级乐器准备)************************
;--功能:显示按下键盘时相应键盘状态。
d_key_down proc near
push si
push di

lea si,d_st_lx			             ;载入音键起始坐标首地址
lea di,d_ed_lx				           ;载入音键结束坐标首地址

draw [si+bx],90,[di+bx],92,0fh   ;调用矩形绘制宏,bx为按键标号缓存值,画一小块琴键色方块
draw [si+bx],92,[di+bx],94,07h   ;调用矩形绘制宏,bx为按键标号缓存值,画一小块琴键阴影色方块
pop di
pop si
ret
d_key_down endp
;******************************手动演奏发声程序**************************
;在8253中的43H端口送入一个控制字0B6H,该控制字对定时器2进行初始化,使定时器2准备接收计数初值
;在8253中的42H端口(Timer2)装入一个16位的计数值533H*896/频率,以建立将要产生的声音的频率
;把输出端口61H的0、1两位置1发出声音
;--功能:当手动按键时,播放相应键的声音,只要不放开,就会一直播放。
;--在di中存放发声频率。
play_hand proc near
;-----------	
   push ax
	push bx
	push cx
	push dx
	push di
;-----------
	mov al,0b6h		   ;在8253的43端送出一个控制字0b6h(10110110b)
	out 43h,al         ;从而对定时器2初始化,准备接收计数初值
	
   mov dx,12h       ;1.1931Mhz/给定频率=12348h/给定频率=计数初值
	mov ax,348ch      ;12348h存入DX:AX中,作32位运算,商存入AX,余数存入DX 
	div di             ;di中存放给定频率
	out 42h,al			 
	in al,61h			      ;开扬声器
	mov al,ah          ;给定时器2写入AX中存放的计数初值
	out 42h,al     
	
   in al,61h         
	mov ah,al          ;把8255输出端的61h的0、1两位置1,并把端口状态存入ah
	or al,3             ;打开扬声器
	out 61h,al        


;----------------按键等待------------
wait2:  
	call waitf				;调用延时
   in al,60h         	;读取键盘扫描码,按下和放开都有相应的扫描码,放开码=按下码+80h>80h	
   test al,80h     	   ;al和80h相与,影响标志位
   jz wait2			;未放开则继续延时
	
   mov al,ah				;恢复8255端口61h的状态,关扬声器
	out 61h,al
;----------------
	pop di            ;恢复寄存器状态
	pop dx 
	pop cx
	pop bx
	pop ax
;----------
   ret
play_hand endp
;***************************弹起显示程序************************
;--功能:显示按下键盘后相应键盘恢复以前状态。
key_up proc near
push si
push di

lea si,st_lx			              ;载入音键起始坐标首地址
lea di,ed_lx				            ;载入音键结束坐标首地址

draw [si+bx],90,[di+bx],93,07h   ;调用矩形绘制宏,恢复阴影
draw [si+bx],93,[di+bx],94,08h   	;调用矩形绘制宏,恢复背景色
pop di
pop si
ret
key_up endp
;----------------高级音乐编辑器子程序区顶部---
d_scan_key proc near
PUSH AX
mov ah,0						;读键盘,键盘扫描码存入ah,ASCII码存入al
int 16h

mov dl,al                    ;al中的ASCII码存入dl,为了便于修改,通过ASCII码来检测
;--------------检测是否为结束键--------------
cmp ah,01h					;是否是结束键,Esc键作为结束键,其扫描码为01h
jne flag_scan				;若不是继续检测
call exit	
;----------扫描琴键--------
;     do re mi fa so la xi
;低音:z  x  c  v  b  n  m
;中音:a  s  d  f  g  h  j
;高音:q  w  e  r  t  y  u

flag_scan:								
key_l1:
	cmp dl,'z'						;是否是z
	jne key_l2						;不是则继续扫描
	mov keynum,0					;是则改变按键编号缓存
   mov key_tune,1          ;改变按键状态缓存
	jmp d_scan_end					;键扫描结束
key_l2:	
	cmp dl,'x'					   ;是否是x
	jne key_l3
	mov keynum,2
   mov key_tune,1
	jmp d_scan_end
key_l3:
	cmp dl,'c'					     ;是否是y
	jne key_l4
	mov keynum,4
   mov key_tune,1
	jmp d_scan_end
key_l4:	
	cmp dl,'v'					     ;是否是v
	jne key_l5
	mov keynum,6
   mov key_tune,1
	jmp d_scan_end
key_l5:
	cmp dl,'b'						;是否是b
	jne key_l6
	mov keynum,8
   mov key_tune,1
	jmp d_scan_end
key_l6:
   cmp dl,'n'    				;是否是n
	jne key_l7
	mov keynum,10
   mov key_tune,1
	jmp d_scan_end
key_l7:
   cmp dl,'m'    				;是否是m
	jne key_1
	mov keynum,12
   mov key_tune,1
	jmp d_scan_end

key_1:
	cmp dl,'a'						;是否是a
	jne key_2						
	mov keynum,14
   mov key_tune,1				
	jmp d_scan_end					
key_2:	
	cmp dl,'s'					      ;是否是s
	jne key_3
	mov keynum,16
   mov key_tune,1
	jmp d_scan_end
key_3:
	cmp dl,'d'					      ;是否是d
	jne key_4
	mov keynum,18
   mov key_tune,1
	jmp d_scan_end
key_4:	 
	cmp dl,'f'					      ;是否是f
	jne key_5
	mov keynum,20
   mov key_tune,1
	jmp d_scan_end
key_5:
	cmp dl,'g'						;是否是g
	jne key_6
	mov keynum,22
   mov key_tune,1
	jmp d_scan_end
key_6:
   cmp dl,'h'    				;是否是h
	jne key_7
	mov keynum,24
   mov key_tune,1
	jmp d_scan_end
key_7:
	cmp dl,'j'					      ;是否是j
	jne key_h1
	mov keynum,26
   mov key_tune,1
  jmp d_scan_end

key_h1:
	cmp dl,'q'						;是否是q
	jne key_h2						
	mov keynum,28				
   mov key_tune,1
	jmp d_scan_end					
key_h2:	
	cmp dl,'w'					   ;是否是w
	jne key_h3
	mov keynum,30
   mov key_tune,1
	jmp d_scan_end
key_h3:
	cmp dl,'e'					   ;是否是e
	jne key_h4
	mov keynum,32
   mov key_tune,1
	jmp d_scan_end
key_h4:	
	cmp dl,'r'					   ;是否是r
	jne key_h5
	mov keynum,34
   mov key_tune,1
	jmp d_scan_end
key_h5:
	cmp dl,'t'						;是否是t
	jne key_h6
	mov keynum,36
   mov key_tune,1
	jmp d_scan_end
key_h6:
   cmp dl,'y'    				;是否是y
	jne key_h7
	mov keynum,38
   mov key_tune,1
	jmp d_scan_end
key_h7:
   cmp dl,'u'    				;是否是u
	jne d_scan_end
	mov keynum,40
   mov key_tune,1
d_scan_end:
   cmp dl,'p'              ;判断是否按下了自动播放键
	 JE d_REPLAY				;若不是,继续扫描
   jmp hand_play				   
hand_play:
  cmp key_tune,1				;取按键状态缓存值,判断是否手动演奏,1为有,0为无
  jnz  again					;若不是,重新扫描有无键按下
POP AX
  ret                    ;若是音键,则返回并继续进行音键处理
again:
jmp d_new_scan
d_scan_key endp
;***********************高级音乐播放器的初始化*****************************
;--功能:初始化屏幕和显示,显示字符说明,绘制出电子琴。
d_init proc near
    mov ax,data
    mov ds,ax  
;------------屏幕以及显示初始化-------------
    mov ah,0 						;0号功能,设置屏幕
    mov al,0dh            ;文本分辨率40*25;像素框8*8;像素分辨率320*200;颜色16
	 int 10h
    
    mov ah,0bh            ;11号功能,设置背景颜色,bh=0时,设置背景颜色
    mov bh,0
    mov bl,00h						;背景色
    int 10h
;------------------显示字符说明------------------    
	 call show_d_text					;显示字符串
;------------------绘制电子琴------------------
    call d_draw_dzq			    ;绘制琴身和底座

	 ret 
d_init endp

;************绘制高级电子琴***************
;--功能:绘制琴身和底座,黑白键,效果灯
d_draw_dzq	 proc near
  draw_point 40,52,44,92,07h      ;调用矩形点阵宏,绘制音响孔左
  draw_point 288,52,292,92,07h    ;调用矩形点阵宏,绘制音响孔右

  drawsqre 38,50,292,92,07h       ;调用矩形框绘制宏,绘制音响框
  drawsqre 44,30,286,93,07h       ;调用矩形框绘制宏,绘制底框1
  draw 45,30,285,94,08h	         ;调用矩形绘制宏,绘制琴身颜色
  drawsqre 45,30,285,94,07h       ;调用矩形框绘制宏,绘制底框2

  draw_point 150,34,282,38,07h    ;调用矩形点阵宏,绘制正面音孔  

  drawsqre 46,31,284,32,00h       ;调用矩形框绘制宏,绘制琴上边 
  drawsqre 49,48,280,49,00h       ;调用矩形框绘制宏,绘制琴挡
	
  draw 55,38,60,41,0ah				  ;调用矩形绘制宏,绘制灯1
  draw 65,38,70,41,07h				  ;调用矩形绘制宏,绘制灯2


  draw 271,42,275,46,07h         ;调用矩形绘制宏,绘制5个指示灯
  draw 265,42,269,46,07h
  draw 259,42,263,46,07h
  draw 253,42,257,46,07h
  draw 247,42,251,46,07h

;----绘制白键----
	 lea si,d_st_lx					       ;画21个白色键
    lea di,d_ed_lx
    mov cx,21
d_init_draw:
    draw [si],d_st_y,[di],d_ed_y,0fh     ;调用矩形绘制宏,绘制白色矩形作为白键
    draw [si],90,[di],93,07h		;调用矩形绘制宏,绘制灰色矩形作为阴影
    add si,2
    add di,2
    loop d_init_draw	

;----绘制黑键----
    lea si,d_bt_x							;画15个黑色键
    lea di,d_bd_x
    mov cx,15
d_init_block:
    draw [si],d_bt_y,[di],d_bd_y,00h  ;调用矩形绘制宏,绘制黑色矩形作为黑键
    add si,2
    add di,2
    loop d_init_block	
	ret
d_draw_dzq	 endp
;***************************弹起显示程序************************
;--功能:显示按下键盘后相应键盘恢复以前状态。
d_key_up proc near
push si
push di

lea si,d_st_lx			              ;载入音键起始坐标首地址
lea di,d_ed_lx				            ;载入音键结束坐标首地址

draw [si+bx],90,[di+bx],93,07h   ;调用矩形绘制宏,恢复阴影
draw [si+bx],93,[di+bx],94,08h   	;调用矩形绘制宏,恢复背景色
pop di
pop si
ret
d_key_up endp

;------------高级音乐编辑器子程序区底部---*-*-*

LEXIT:     SHOW  Gao2                                           
          SHOW  Gao3                                          
          JMP   LOP
       
CODE     ENDS
END   START

猜你喜欢

转载自blog.csdn.net/m0_37772174/article/details/84900288