一、要求
基本要求:
1、 将存储于内存中的音乐数据播出(格式自定义)。
2、 能够播出21个音阶(低音1~7、中音1~7、高音1~7)。
提高要求:
1、 可以播出长短音。(分长音、中音、短音)
2、 可从文件中读音乐数据(格式自定义)。
二、设计内容
利用PC机的键盘与扬声器电路, 用汇编语言设计简易电子音乐播放程序。
DATA SEGMENT
INFO1 DB 0DH,0AH,' WELCOME YOU TO COME HERE!',0dh,0ah,'$'
INFO2 DB 0DH,0AH,' this is a music program!','$'
INFO3 DB 0DH,0AH,' please select!',0dh,0ah,'$'
INFO4 DB 0DH,0AH,' INPUT ERROR!','$'
INFO5 DB 0DH,0AH,' PLEASE INPUT AGAIN!' ,0dh,0ah,'$'
MUSLIST db' ****************************************',0dh,0ah
db' * The music menu is that: * ',0dh,0ah
db' * 1:Christmas ring * ',0dh,0ah
db' * 2:MUSIC2 * ',0dh,0ah
db' * 3:MUSIC3 * ',0dh,0ah
db' * 4:ju hua tai * ',0dh,0ah
db' * 5:open file * ',0dh,0ah
db' * 6:exit * ',0dh,0ah
db' ****************************************',0dh,0ah,'$'
DATABUFF DB 1024 DUP(?)
FHANDLE DW ?
FNAME DB 255,30,255 dup(?)
biao1 db 52,58,66,70,78,88,99
biao2 db 100,200
MUS_FREG1 dw 7 dup(330),392,262,294,330,4 dup(349),2 dup(330),330,294,294,262,294,392
dw 7 dup(330),392,262,294,330,4 dup(349),2 dup(330),392,392,349,294,262,0
MUS_TIME1 dw 2 dup(25*400,25*400,50*400),4 dup(25*400),100*400,2 dup(25*400,25*400,50*400)
dw 4 dup(25*400),2 dup(50*400),2 dup(25*400,25*400,50*400)
dw 4 dup(25*400),100*400,2 dup(25*400,25*400,50*400),4 dup(25*400),100*400
MUS_FREG2 dw 262,262,392,392,440,440,392,349,349,330,330,294,294,262
dw 2 dup(392,392,349,349,330,330,294)
dw 262,262,392,392,440,440,392,349,349,330,330,294,294,262,0
MUS_TIME2 dw 3 dup(6 dup(25*400),50*400,6 dup(25*400),50*400)
MUS_FREG3 DW 262,262,294,262,349
DW 330,262,262,294,262
DW 392,349,262,262,523
DW 440,349,262,262,466
DW 466,440,262,392,349,0
MUS_TIME3 DW 10000,20000,20000,20000,20000
DW 20000,20000,10000,10000,20000
DW 20000,20000,20000,10000,10000
DW 20000,20000,20000,20000,20000
DW 10000,20000,20000,20000,20000
m4 dw 659,659,578,659,659,784,659,578,659,523,523,578,659,784,659,578,523,578
dw 659,784,659,880,784,880,784,784,659 ,392,0
mt4 dw 20000,15000,10000,25000,10000,10000,10000,10000,25000,15000,4 dup(10000),15000
dw 10000,2 dup(10000), 10000,25000
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
DB 200 DUP ('STACK')
STACK ENDS
CODE SEGMENT
ASSUME DS:DATA,SS:STACK,CS:CODE
MAIN PROC FAR
MOV AX,DATA ;数据段段地址送DS
MOV DS,AX
MOV aH, 0 ;BIOS调用设置显示方式640*480 16色图形
MOV AL,12h
INT 10H
MOV AH,0BH ;BIOS调用设置背景颜色
MOV BH,0
MOV BL,5
INT 10H
MOV AH,0BH ;BIOS调用设置调色板
MOV BH,01H
MOV BL,00
INT 10H
SHOW MACRO b ;字符串显示宏
LEA DX,b
MOV AH,9
INT 21H
ENDM
show INFO1
show INFO2
show INFO3
show MUSLIST
Inp: MOV AH,01H ;DOS调用从键盘输入字符
INT 21H
CMP AL,'6' ;输入6则退出
JZ retu
CMP AL,'1' ;输入1则演奏Christmas ring
JNZ B0
CALL MUSIC1
JMP EXIT1
B0: CMP AL,'2' ;输入2则演奏music2
JNZ C0
CALL MUSIC2
JMP EXIT1 ;输入3演奏music3
C0: CMP AL,'3'
JNZ d0
CALL MUSIC3
JMP EXIT1
d0: cmp al,'4' ;输入4演奏 菊花台
jnz e0
call music4
JMP EXIT1
e0: cmp al,'5' ;输入5 则转入文件输入演奏文件音乐
jnz exit
call wen
JMP EXIT1
EXIT1: show INFO5
JMP Inp
EXIT:
call clear
MOV aH, 0 ;BIOS调用设置显示方式640*480 16色图形
MOV AL,12h
INT 10H
MOV AH,0BH ;BIOS调用设置背景颜色
MOV BH,0
MOV BL,5
INT 10H
MOV AH,0BH ;BIOS调用设置调色板
MOV BH,01H
MOV BL,00
INT 10H
show INFO4 ;显示提示字符
show INFO5
show INFO1
show MUSLIST
jmp inp
RETU: MOV AH,4CH ;退出DOS
INT 21H
MUSIC1 PROC NEAR ;音乐1演奏子程序
LEA SI,MUS_FREG1 ;频率首地址装入SI
LEA BP,MUS_TIME1 ;持续时间首地址装入BP
F1: MOV DI,[SI] ;把频率值送DI
CMP DI,0 ; 判断乐谱是否结束0结束退出
JE END_MUS1
MOV bX,ds:[BP] ;把持续时间值送BX
CALL GENSOUND ;调用发音子程序
ADD SI,2 ;使地址指向下一个频率
ADD BP,2 ;使地址指向下一个时间
JMP F1 ;循环演奏
END_MUS1:
RET ;返回(music 2 3 4与1相似)
MUSIC1 ENDP
MUSIC2 PROC NEAR
LEA SI,MUS_FREG2
LEA BP,MUS_TIME2
F2: MOV DI,[SI]
CMP DI,0
JE END_MUS2
MOV bX,ds:[BP]
CALL GENSOUND
ADD SI,2
ADD BP,2
JMP F2
END_MUS2:
RET
MUSIC2 ENDP
MUSIC3 PROC NEAR
LEA SI,MUS_FREG3
LEA BP,MUS_TIME3
F3: MOV DI,[SI]
CMP DI,0
JE END_MUS3
MOV bX,ds:[BP]
CALL GENSOUND
ADD SI,2
ADD BP,2
JMP F3
END_MUS3:
RET
MUSIC3 ENDP
MUSIC4 PROC NEAR
LEA SI,M4
LEA BP,Mt4
F4: MOV DI,[SI]
CMP DI,0
JE END_MUS4
MOV bX,ds:[BP]
CALL GENSOUND
ADD SI,2
ADD BP,2
JMP F4
END_MUS4:
RET
MUSIC4 ENDP
GENSOUND PROC NEAR ;发音子程序
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH DI
MOV AL,0B6H ;向计数器写控制字
OUT 43H,AL ;方式3、双字节写和二进制计数方式写到控制口
MOV DX,12H ;设置被除数
MOV AX,533H*896
DIV DI ;其商ax为预置值
OUT 42H,AL ;先送LSB
MOV AL,AH
OUT 42H,AL ;后送MSB
IN AL,61H ;读端口原值
MOV AH,AL
OR AL,3
OUT 61H,AL ;接通扬声器
WAIT1: MOV CX,8FF0H ;设循环次数为8ff0h
DELAY1: LOOP DELAY1
DEC BX ;循环持续bx次,即传进来的节拍时间
JNZ WAIT1
MOV AL,AH
OUT 61H,AL ;关闭扬声器
POP DI
POP DX
POP CX
POP BX
POP AX
RET
GENSOUND ENDP
clear proc near ;清屏
push ax
push bx
push cx
push dx
mov ah,6
mov al,0
mov ch,0
mov cl,0
mov dh,24
mov dl,79
mov bh,7
int 10h
pop dx
pop cx
pop bx
pop ax
ret
clear endp
wen proc near ;文件播放子程序
MOV AX,DATA
MOV DS,AX
mov dx,offset fname
mov ah,0ah ;字符串(文件路径)输入到缓冲DOS调用
int 21h
mov fname[17],0 ;置文件结束标志
mov dx,offset fname
add dx,2
MOV AH,3DH ;DOS调用打开文件
MOV AL,2
INT 21H
MOV FHANDLE,AX ;文件句柄存FHANDLE
jc end_mus ;错误退出
MOV BX,AX ;文件句柄送BX
MOV AH,3FH ;读文件到数据缓冲区
MOV CX,1024
MOV DX,OFFSET DATABUFF
INT 21H
MOV DX,OFFSET databuff
MOV BX,FHANDLE ;关闭文件
MOV AH,3EH
INT 21H
lea di,databuff ;查找乐谱结束标志字母‘e’
mov al,'e'
mov cx,100
cld
repne scasb
push di ;DI入栈,DI 为演奏时间表首地址
mov si,offset databuff
add si,2 ;SI为乐谱频率表首地址
ll: mov bx,offset biao2 ;获得乐谱持续时间参数送AL
mov al,[di]
sub al,38h
xlat
push bx
mov bl,100
mul bl ;时间参数AL*100的持续时间
pop bx
mov bx,ax
push bx ;持续时间送BX
mov bx,offset biao1 ;查表获得乐谱对应频率参数送AL
mov al,ds:[si]
sub al,31h
xlat
push bx
mov bl,10 ;时间参数*10的频率值
mul bl
pop bx
mov di,ax ;频率值送DI
cmp di, 'e' ;结束则退出
je end_mus
pop bx
CALL GENSOUND ;调用发声子程序
pop di ;DI(时间表首地址) 出栈
ADD di,1 ;使DI指向下一个时间参数
ADD si,1 ; 使SI指向下一个频率参数
Jmp ll ;循环演奏
END_MUS: RET
wen ENDP
CODE ENDS
END MAIN