📄 zuoqu.asm
字号:
CURSE MACRO OP1,OP2 ;设置光标位置
PUSH AX
PUSH DX
MOV AH,02H
MOV DH,OP1
MOV DL,OP2
INT 10H
POP DX
POP AX
ENDM
LINE1 MACRO X1,Y1,LONG1 ;画横线
LOCAL AA
MOV CX,X1
MOV DX,Y1
MOV BX,LONG1
ADD BX,CX
MOV AH,0CH
AA: INT 10H
INC CX
CMP CX,BX
JNE AA
ENDM
LINE2 MACRO X2,Y2,LONG2 ;画竖线
LOCAL AAA
MOV CX,X2
MOV DX,Y2
MOV BX,LONG2
ADD BX,DX
MOV AH,0CH
AAA: INT 10H
INC DX
CMP DX,BX
JNE AAA
ENDM
XIE1 MACRO COL1,ROW1,COLE1 ;画正斜线
LOCAL EE,FF
PUSH AX
MOV CX,COL1
MOV DX,ROW1
MOV AH,0CH
EE: CMP CX,COLE1
JAE FF
INT 10H
INC CX
INC DX
JMP EE
FF: POP AX
ENDM
XIE2 MACRO COL2,ROW2,COLE2 ;画反斜线
LOCAL EEE,FFF
PUSH AX
MOV CX,COL2
MOV DX,ROW2
MOV AH,0CH
EEE: CMP CX,COLE2
JAE FFF
INT 10H
INC CX
SUB DX,1
JMP EEE
FFF: POP AX
ENDM
DATA SEGMENT
freq dw 2 dup(262,294,330,262)
dw 2 dup(330,349,392)
dw 2 dup(392,440,392,349,330,262)
dw 2 dup(294,196,262),0
MTIM dw 10 dup(5000),10000,5000,5000,10000
dw 2 dup(2500,2500,2500,2500,5000,5000)
dw 2 dup(5000,5000,10000)
BUFF1 DB ' Welcome you to run this programme! Please input time:$'
BUFF2 DB 'E: finish composing P: play$'
BUFF3 DB 'P: play S: save R: compose again Q: exit$'
BUFF4 DB 'Please input file name:$'
BUFF5 DB 'Error Press S to try again:$'
BUFF6 DB 'Music had been saved$'
NAM DB 30 DUP(''),'$'
FILEHAN DW ?
JPAI DB 4 ;记录输入的节拍(一小节总节拍数)
RM DB 4 ;剩余节拍数
NOT2 EQU 2 ;二分音符所占的拍子数
NOT1 EQU 4 ;全音符所占的拍子数
COL DW ? ;音符在屏幕上的位置
ROW DW ?
HEIGHT DW ? ;当前音符音高
TIME DB ? ;当前音符时值
NUM DW ? ;用来计数
FREQ_T DW 196,220,247,262,294,330,349,392,440,494,523,587,659,698,784
FREQ_R DB '196 ','220 ','247 ','262 ','294 ' ;低音sol到中音re的频率
db '330 ','349 ','392 ','440 ','494 ' ;中音mi到中音xi的频率
db '523 ','587 ','659 ','698 ','784 ' ;高音do到高音sol的频率
TIM_R DB '0.5s','1s ','2s '
ZZHEN DW ?
STO DB 320 DUP('')
DATA ENDS
stak segment para stack 'stack'
dw 100 dup(?)
stak ends
CODE SEGMENT
MAIN PROC FAR
ASSUME CS:CODE,DS:DATA
PUSH AX
MOV AX,DATA
MOV DS,AX
MOV ES,AX
MOV AX,0004H ;设置显示模式为320*200彩色图形方式
INT 10H
MOV AH,0BH ;设置背景为蓝色
MOV BH,00
MOV BL,1
INT 10H
OK: CURSE 0,0
MOV DX,OFFSET BUFF1 ;显示提示信息
MOV AH,09
INT 21H
CALL INPUT
MOV COL,34 ;参数恢复
MOV ROW,78
MOV NUM,0
MOV HEIGHT,4
MOV TIME,1
CURSE 2,2
MOV DX,OFFSET BUFF2
MOV AH,09H
INT 21H
CALL YUEPU
CALL COM
CURSE 2,2
MOV DX,OFFSET BUFF3
MOV AH,09H
INT 21H
SSS: MOV AH,08
INT 21H
CMP AL,'P'
JE PPP
CMP AL,'S'
JE STOR
CMP AL,'R'
JE AGAIN
CMP AL,'Q'
JE QUIT
JMP SSS
PPP:
CALL PLAY
JMP SSS
STOR: CALL STORE
JMP SSS
AGAIN: CALL CLEALL ;重头开始
JMP OK
QUIT: POP AX
MOV AX,4C00H
INT 21H
MAIN ENDP
INPUT PROC NEAR ;输入节拍
PUSH AX
PUSH BX
MOV BX,0
CC: MOV AH,01H
INT 21H
CMP AL,0DH ;回车?
JE BB
CMP BX,0 ;只存第一个输入的数
JNE JJ
MOV STO[0],AL
MOV STO[1],'/'
MOV STO[2],'4'
MOV STO[3],' '
MOV ZZHEN,4
AND AL,0FH ;ASCLL转化为数字
MOV JPAI,AL
MOV RM,AL
JJ: INC BX
CMP BX,3
JNA CC
BB: POP BX
POP AX
INPUT ENDP
YUEPU PROC NEAR ;显示乐谱
MOV AL,2
LINE1 0,50,320
LINE1 0,56,320
LINE1 0,62,320
LINE1 0,68,320
LINE1 0,74,320
LINE1 0,110,320
LINE1 0,116,320
LINE1 0,122,320
LINE1 0,128,320
LINE1 0,134,320
MOV AL,5 ;高音谱号
LINE1 13,62,6
LINE1 10,74,9
LINE1 8,84,5
LINE1 13,57,3
LINE2 15,43,39
LINE2 22,66,5
LINE2 10,65,5
LINE2 5,65,5
LINE2 20,47,6
XIE1 6,82,8
XIE1 5,69,10
XIE1 16,43,20
XIE1 18,62,22
XIE2 18,74,22
XIE2 13,83,15
XIE2 10,65,14
XIE2 16,56,21
XIE2 5,64,13
RET
YUEPU ENDP
NOTE PROC NEAR ;显示音符
PUSH AX
PUSH SI
PUSH DI
CMP RM,0 ;剩余节拍数是否为零,是否画小节线
JNE KK
MOV AH,JPAI ;还原小节剩余节拍数
MOV RM,AH
MOV AL,5
MOV SI,COL
SUB SI,6
MOV DI,ROW
SUB DI,28
LINE2 SI,DI,25
KK: CMP HEIGHT,5 ;是否下加一线
JAE NN
MOV AL,2
MOV SI,COL
SUB SI,5
CMP NUM,19
JB FAI
MOV DI,140
JMP YOUA
FAI: MOV DI,80
YOUA: LINE1 SI,DI,13
CMP HEIGHT,3 ;是否下加二线
JAE NN
ADD DI,6
LINE1 SI,DI,13
NN: MOV AL,7 ;拼出音符头
MOV SI,COL
MOV DI,ROW
CMP TIME,2
JAE PP
LINE1 SI,DI,2 ;实心头
ADD DI,4
LINE1 SI,DI,2
SUB SI,1
SUB DI,1
LINE1 SI,DI,4
SUB DI,2
LINE1 SI,DI,4
SUB SI,1
ADD DI,1
LINE1 SI,DI,6
JMP QQ
PP: MOV AH,0CH ;空心头
MOV CX,SI
MOV DX,DI
SUB SI,2
ADD DI,2
INT 10H
ADD CX,1
INT 10H
ADD DX,4
INT 10H
SUB CX,1
INT 10H
SUB CX,1
SUB DX,1
INT 10H
ADD CX,3
INT 10H
SUB DX,2
INT 10H
SUB CX,3
INT 10H
SUB CX,1
ADD DX,1
INT 10H
ADD CX,5
INT 10H
QQ: CMP TIME,4 ;画音符尾巴
JE OO
CMP HEIGHT,9
JA MM
ADD SI,5
SUB DI,20
MM: LINE2 SI,DI,21
OO: POP DI
POP SI
POP AX
RET
NOTE ENDP
CLEAR PROC NEAR ;清除音符
PUSH SI
PUSH DI
PUSH BP
MOV SI,COL
SUB SI,5
CMP NUM,19
JB TAI
MOV DI,105
MOV BP,153
JMP LL
TAI: MOV DI,45
MOV BP,93
LL: CMP DI,50
JE COLOR
CMP DI,56
JE COLOR
CMP DI,62
JE COLOR
CMP DI,68
JE COLOR
CMP DI,74
JE COLOR
CMP DI,110
JE COLOR
CMP DI,116
JE COLOR
CMP DI,122
JE COLOR
CMP DI,128
JE COLOR
CMP DI,134
JE COLOR
MOV AL,0
JMP HEHE
COLOR: MOV AL,2
HEHE: LINE1 SI,DI,14
INC DI
CMP DI,BP
JNE LL
POP BP
POP DI
POP SI
RET
CLEAR ENDP
CLEALL PROC NEAR ;清屏
PUSH AX
PUSH CX
PUSH DX
MOV AX,0C00H
MOV CX,0
MOV DX,0
HANG: INT 10H
INC CX
CMP CX,320
JNE HANG
MOV CX,0
INC DX
CMP DX,200
JNE HANG
POP DX
POP CX
POP AX
RET
CLEALL ENDP
COM PROC NEAR ;作曲
PUSH AX
HH: CALL CLEAR
CALL NOTE
MOV AH,10H ;从键盘接收字符
INT 16H
CMP AH,48H ;上?
JE UP
CMP AH,50H ;下?
JE DOWN
CMP AH,4BH ;左?
JE LEFT
CMP AH,4DH ;右?
JE RIGHT
CMP AL,0DH ;回车?
JE XING
CMP AX,1245H ;按下"E"结束作曲
JE II
CMP AX,1950H ;按下"P"演奏
JE III
JMP HH
UP: MOV DI,0
CALL YINGAO
JMP HH
DOWN: MOV DI,1
CALL YINGAO
JMP HH
LEFT: MOV DI,2
CALL TIM
JMP HH
RIGHT: MOV DI,3
CALL TIM
JMP HH
XING: CALL ONE
JMP HH
III: CALL PLAY
JMP HH
II: MOV AH,JPAI ;不能从小节中间结束
CMP RM,AH
JNE HH
CALL CLEAR ;结束,画结束线
MOV AL,5
MOV SI,COL
SUB SI,4
CMP NUM,19
JB FASE
MOV DI,110
JMP YOEH
FASE: MOV DI,50
YOEH: LINE2 SI,DI,25
POP AX
RET
COM ENDP
ONE PROC NEAR
PUSH DI
PUSH BX
PUSH AX
PUSH CX
MOV BX,NUM ;保存设置音符
MOV DI,HEIGHT
SUB DI,1
MOV DX,FREQ_T[DI]
MOV FREQ[BX],DX
MOV AL,4
MUL DI
MOV DI,AX
MOV BX,ZZHEN
MOV CX,4
QWER: MOV DL,FREQ_R[DI]
MOV STO[BX],DL
INC DI
INC BX
LOOP QWER
MOV ZZHEN,BX
;MOV CX,TIME
;MOV MUTIM[BX],CX
;SHL BX,02
MOV AH,RM ;参数更新
SUB AH,TIME ;计算一小节内的剩余节拍
MOV RM,AH
ADD NUM,1
CMP NUM,19 ;是否超出第一行
JB BUCUO
JA HAOLE
MOV COL,4
HAOLE: MOV ROW,138
JMP HENHAO
BUCUO: MOV ROW,78
HENHAO: ADD COL,15
MOV HEIGHT,4
MOV TIME,1
POP CX
POP AX
POP BX
POP DI
RET
ONE ENDP
YINGAO PROC NEAR ;改变音高
PUSH AX
CMP DI,1
JZ DOWN1
CMP HEIGHT,15
JAE EXITY
SUB ROW,3
ADD HEIGHT,1
JMP EXITY
DOWN1: CMP HEIGHT,1
JBE EXITY
ADD ROW,3
SUB HEIGHT,1
EXITY: POP AX
RET
YINGAO ENDP
TIM PROC NEAR ;改变音符时值
PUSH AX
CMP DI,2 ;表明是按左键还是右键的标志
JZ LEFT1
MOV AL,RM ;根据剩余节拍数限制可用音符
MOV AH,1 ;先假定只能放入4分音符,时值为1
CMP AL,NOT2 ;本小节节拍剩余数和2分音符时长作比较
JB XX
INC AH ;剩余数大于等于2,AH加为2
CMP AL,NOT1 ;本小节节拍剩余数和全音符时长作比较
JB XX
ADD AH,2 ;剩余数大于等于4,AH加为4
XX: CMP TIME,AH ;AH来限制TIME的上限
JAE EXITT
CMP TIME,2 ;如果是2分音符变全音符,TIME必须加2
JNE WW
ADD TIME,1
WW: ADD TIME,1 ;其他请况TIME加1
JMP EXITT
LEFT1: CMP TIME,1 ;按左键时,TIME值减小,下限是1
JBE EXITT
CMP TIME,4 ;如果是全音符变2分音符,TIME必须减2
JNE VV
SUB TIME,1
VV: SUB TIME,1 ;其他请况TIME减1
EXITT: POP AX ;退出
RET
TIM ENDP
STORE PROC NEAR ;保存文件
PUSH AX
PUSH CX
PUSH DX
CALL CLE
CURSE 20,2
MOV DX,OFFSET BUFF4
MOV AH,09
INT 21H
MOV BX,0
SET: MOV NAM[BX],00H ;存储清零
INC BX
CMP BX,30
JB SET
MOV FILEHAN,0
MOV AH,1 ;输入文件名
MOV BX,0
DLL: INT 21H
CMP AL,0DH
JE DLLL
MOV NAM[BX],AL
INC BX
JMP DLL
DLLL: LEA DX,NAM ;新建
MOV AH,3CH
MOV CX,00
INT 21H
JC ERROR
MOV FILEHAN,AX
JMP B90
ERROR: CALL CLE
CURSE 20,2 ;出错处理,重试
MOV DX,OFFSET BUFF5
MOV AH,09
INT 21H
JMP B100
B90: MOV AH,40H ;写入数据
MOV BX,FILEHAN
MOV CX,320
LEA DX,STO
INT 21H
JC ERROR
MOV AH,3EH ;关闭文件
INT 21H
JC ERROR
CALL CLE
CURSE 20,2 ;成功提示
MOV DX,OFFSET BUFF6
MOV AH,09
INT 21H
B100: POP DX
POP CX
POP AX
RET
STORE ENDP
CLE PROC NEAR
MOV AX,0C00H
MOV CX,0
MOV DX,155
HANG1: INT 10H
INC CX
CMP CX,320
JNE HANG1
MOV CX,0
INC DX
CMP DX,200
JNE HANG1
RET
CLE ENDP
PLAY proc near ;演奏
push di
push si
push bp
push bx
mov si,offset FREQ
mov bp,offset MTIM
repts: mov di,[si]
cmp di,0
je endsing
mov bx,ds:[bp]
call sound
add si,2
add bp,2
JMP repts
endsing:
pop bx
pop bp
pop si
pop di
ret
PLAY endp
sound proc near ;发音
push ax
push bx
push cx
push dx
push di
mov al,0b6h
out 43h,al
mov dx,12h
mov ax,0ffffh
div di
out 42h,al
mov al,ah
out 42h,al
in al,61h
mov ah,al
or al,3
out 61h,al
delay: mov cx,0ffffh ;延迟
dl10ms: loop dl10ms
dec bx
jnz delay
mov al,ah
out 61h,al
pop di
pop dx
pop cx
pop bx
pop ax
ret
sound endp
CODE ENDS
END MAIN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -