組合語言程式二    趙元 B84204021 物理四


 

本程式是由三個.ASM檔所構成。除了有最基本的將鍵盤按鍵轉換成PC喇叭發音的功能外,還能將按鍵顯示在螢幕上琴鍵的相對位置上。並且能夠升高降低八度音,儲存以及讀取先前的按鍵等。

 

程式的方塊圖如下:

 

當使用者按下鍵盤後,piano.asm先做判斷,如果不是特殊功能的按鍵,則呼叫transf.asm將按鍵轉換成8253的計數值,再由transf.asm呼叫sound.asm將計數值寫到CNT2中並開啟喇叭發音。在發音0.3秒後,在呼叫sound.asm將喇叭關閉。若是按鍵為+/-,則將計數值除/乘以2,以升高或降低八度音。若是按下1鍵則將buffer中的按鍵存入磁碟中,按下2則由磁碟中讀取按鍵到buffer裡,並重播之。

 

暫停0.3秒,是利用系統每秒發生18.2次中斷時,於0000:046Ch0000:046Eh的值會被increase,因此當此值增加6時,即約為0.3秒,這就是wait3s這個副程式運作的原理。

 

以下便是piano.asm, transf.asm, sound.asm的原始碼。

INCLUDE \MASM61\INCLUDE\DOS.INC

INCLUDE \MASM61\INCLUDE\BIOS.INC

buf_size EQU 50

 

.MODEL SMALL

.DATA

logo DB 0Dh,0Ah,0Dh,0Ah

DB '========================',0Dh,0Ah

DB '*** Electric Piano ***',0Dh,0Ah

DB '========================',0Dh,0Ah,0Dh,0Ah,'$'

 

pia0 DB 196,220,196,220,196,194,196,220,196,220,196,220,196,194,196,220,196,220,196,194,196,220,196,220,196,220,196,194,196,220,196,0dh,0ah,'$'

pia1 DB 32,219,32,219,32,179,32,219,32,219,32,219,32,179,32,219,32,219,32,179,32,219,32,219,32,219,32,179,32,219,0dh,0ah,'$'

pia2 DB 32,179,32,179,32,179,32,179,32,179,32,179,32,179,32,179,32,179,32,179,32,179,32,179,32,179,32,179,32,179,0dh,0ah,'$'

pia3 DB 196,193,196,193,196,193,196,193,196,193,196,193,196,193,196,193,196,193,196,193,196,193,196,193,196,193,196,193,196,193,196,0dh,0ah,'$'

; a w s e d f t g y h u j A W S E D F T G Y H U J K

 

KEY DW 0

buffer DB buf_size DUP(0)

buf_off DB 0

handle DW ?

file DB 'notes.dat',0

 

.CODE

 

EXTRN transf:NEAR, nosound:NEAR ; External Lib.

 

begin: mov ax,@DATA

mov ds,ax

@SetCsrPos 0,0,0

mov dx,OFFSET logo ; print logo

mov ah,9

int 21h

show: ; print piano

@SetCsrPos 0,10,0

mov dx,OFFSET pia0

mov ah,9

int 21h

mov cx,3

show1: mov dx,OFFSET pia1

int 21h

loop show1

mov cx,3

show2: mov dx,OFFSET pia2

int 21h

loop show2

mov dx,OFFSET pia3

int 21h

 

 

 

wait_key:

mov ah,7 ; Resd Key

int 21h

cmp al,'*' ; "*" to quit

jz exit

 

.IF al=='-' && KEY >0

sub KEY,1

.ELSEIF al=='+'

add KEY,1

.ENDIF

 

.IF al=='1' ;save notes

@MakeFile file,00100000b

mov handle,ax

@Write buffer,buf_size,handle

@CloseFile handle

 

.ELSEIF al=='2' ;load'n'play

@OpenFile file

mov handle,ax

@Read buffer,buf_size,handle

@CloseFile handle

mov cx,buf_size

mov bx,0

playb: mov al,buffer[bx]

mov si,KEY ; the rising key

push cx

push bx

call transf ; sound

 

call wait3s ; pause for 0.3s

call nosound ; turn off sound

pop bx

pop cx

inc bx

loop playb

mov buf_off,0

.ENDIF

 

mov bh,0

mov bl,buf_off

mov buffer[bx],al

add buf_off,1

mov si,KEY ; rising key

call transf ; sound

 

call wait3s ; pause 0.3s

call nosound

jmp show ; refresh window

 

exit: call nosound

mov ah,4Ch

int 21h

 

 

;---------------------------------------------------------

wait3s PROC NEAR ; wait for 0.3 sec

mov dx,6

mov bx,0

mov es,bx

add dx,es:[46Ch]

adc bx,es:[46Eh]

 

wait1: mov bp,es:[46Ch]

mov ax,es:[46Eh]

sub bp,dx

sbb ax,bx

jc wait1

ret

wait3s ENDP

 

;----------------------------------------------------------

 

.STACK

 

 

END begin

 

 

 

 

;====================================

; transf -- transfer key to sound freq.

; parameterAL= input key

; SI= rising KEY

; returnnone

;====================================

INCLUDE \MASM61\INCLUDE\DOS.INC

INCLUDE \MASM61\INCLUDE\BIOS.INC

 

NOTES EQU 28 ; # of notes

 

.MODEL SMALL

.DATA

key_map DB 'awsedrftgyhujkAWSEDRFTGYHUJK' ; key mapping

count DW 1138/2,1205/2,1277/2,1353/2 ; to freq. counts

DW 1433/2,1519/2,1609/2,1705/2,1 ; reversed

DW 1806/2,1913/2,2027/2,2148/2,2275/2

DW 1138,1205,1277,1353

DW 1433,1519,1609,1705

DW 1,1806,1913,2027,2148,2275

 

.CODE

PUBLIC transf

EXTERN sound:NEAR, nosound:NEAR

transf PROC ; transf

mov bx,ds

mov es,bx

mov di,OFFSET key_map ; es:di->key_map

mov cx,NOTES ;

repnz scasb ;

jz tt ; if found call sound

call nosound ; else turn off

jmp exit

 

tt: push cx

mov bl,NOTES

mov bh,0

sub bl,cl

dec bl

mov dl,bl

@SetCsrPos ,17,0

@PutChar key_map[bx],,0,1 ;show key

 

pop cx

shl cx,1 ; x2 for 2 Byte

mov bx,cx ; bx as index

mov ax,count[bx] ; get count

 

mov cx,si

shr ax,cl ; rise sound key...

call sound

 

exit: ret

transf ENDP

 

.STACK

END

 

;==============================

; sound -- turn on PC speaker

; parameterAX= count

; returnnone

; nosound -- turn off

; parameternone

; returnnone

;==============================

 

CNT2 EQU 42h

CNT_CTR EQU 43h

ENA_CTR EQU 61h

 

.MODEL SMALL

.CODE

PUBLIC sound,nosound ; declare as public

sound PROC

push ax

mov al,10110110b

out CNT_CTR,al ; set mode

pop ax

push ax

out CNT2,al ; low byte

mov al,ah

out CNT2,al ; high byte

in al,ENA_CTR

or al,00000011b

out ENA_CTR,al ; turn on

pop ax

ret

sound ENDP

 

nosound PROC

push ax

in al,ENA_CTR

and al,11111100b

out ENA_CTR,al ; turn off

pop ax

ret

nosound ENDP

 

.STACK

END