1. 程式人生 > >彙編課設(電子鋼琴:原始碼)

彙編課設(電子鋼琴:原始碼)

實現結果


程式的啟動有點像小霸王遊戲機的遊戲,喜歡彙編的朋友可以發信與我一起討論,發聲程式參考的是一本彙編教材,程式寫作和上傳相隔有點久遠,記不太清,千行程式碼,算是學生時代一個比較得意的課設

編譯器下載

編譯器可在我的上傳資源中查詢,已註明:彙編編譯器
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