汇编语言实现音乐播放器

目标程序

用汇编语言实现一个音乐播放器,并支持点歌

Overview

乐曲是按照一定的高低、长短和强弱关系组成的音调,在一首乐曲中,每个音符的音高和音长与频率和节拍有关,因此我们要分别为3首要演奏的乐曲定义一个频率表和一个节拍时间表。

利用8253/54定时器来驱动扬声器,在8253/54中的43端口送一个控制字0B6H,该控制字对定时器2进行初始化,使定时器2准备接收计数初值。在8253/54中的42H端口装入一个16位的计数值,以建立将要产生的发声频率。把输出端口61H的0、1两位置1,发出声音。

输入不同的数字,要播放相应的音乐。因此我们要利用输入的数字来获取歌曲的频率表地址和节拍时间表地址来播放对应音乐,利用直接定址表即可迎刃而解。

在CMOS RAM中存放着当前的时间,秒、分、时、日、月、年分别存放在0,2,4,7,8,9的单元中。这些数据以BCD码的方式存放,因此我们若要输出时间还需将他们转换为ASCII码才可正确输出。

更改界面颜色。在内存地址空间中,B8000H~BFFFFH共32KB的空间,为80*25彩色字符模式的显示缓冲区。一个字符占两个字节的存储空间,低位字节存储字符的ASCII码,高位字节存储字符的属性。属性字节的格式:7:BL闪烁 6、5、4:RGB背景色 3:I高亮 2、1、0:RGB前景色。更改属性字节即可更改界面颜色。

效果预览

初始界面

开始播放

结束播放

流程图

源码

asm 复制代码
;点歌系统:
;输入不同的数字,播放相应的音乐。
;其中"1"代表《刚好遇见你》音乐,"2"代表《成都》音乐,"3"代表《暧昧》音乐。
;输入数字"0",则退出点歌系统。
;----------------------------------------------------
stack   segment para stack 'stack'
        db 100 dup ('?')
stack   ends
;----------------------------------------------------
data	segment para 'data'
tip0	db	'-----------------------------------','$'
tip1	db	'|  1: just met you-- Fei Yuqing   |','$' 
tip2	db	'|  2:    ChenDu   --  Zhao Lei    |','$' 
tip3	db	'|  3:   ambiguity -- Xue Zhiqian  |','$'
tip4	db	'|  0: exit                        |','$'
tip5	db	'  --please input your choice:      ','$'
tip		dw	tip0,tip1,tip2,tip3,tip4,tip0,tip5 ;界面
tip6	db	'music over!','$'
tip7	db	'begin:','$'
tip8	db	'end  :','$'
tip9	db	'You have exited successfully.','$'
tip10	db	'input error!please input again:','$'
time	db 'yy/mm/dd hh:mm:ss','$'				;输出时间的格式
table	db 9,8,7,4,2,0							;CMOS ROM中时间信息的存放单元

;----------------------------------------------------
;《刚好遇见你》
mus_freq1 dw 262,262,262
		  dw 262,220,524,440,440,440,392
		  dw 392,330,330,262,294,262,262
		  dw 262,220,524,587,524,524,440
		  dw 440,392,330,392,294,262,247
		  dw 262,220,524,440,440,440,392
		  dw 392,392,330,392,294,262,294
		  dw 262,247,262,262,262,294
		  dw 330,294,262,262,247,262,262
		  dw -1
mus_time1 dw 25,25,25
		  dw 25,25,25,25,50,25,25
		  dw 25,25,25,25,50,25,25
		  dw 25,25,25,25,50,25,25
		  dw 25,25,25,25,50,25,25
		  dw 25,25,25,25,50,25,25
		  dw 25,25,25,25,50,25,25
		  dw 25,12,12,100,25,25
		  dw 25,12,12,25,12,12,100
;---------------------------------------------------
;《成都》
mus_freq2 dw 196,262
		  dw 262,294,330
		  dw 392,330,330
		  dw 330,196
		  dw 262
		  dw 294,262,220
		  dw 196,196
		  dw 262,262,294,330
		  dw 440,330,392
		  dw 330,294
		  dw 262
		  dw 294,392
		  dw 330,294
		  dw 330,392
		  dw 392,330,392
		  dw 440,524,440
		  dw 330,294,262
		  dw 294,330,330
		  dw 196,392
		  dw 330,330
		  dw 294,262,262
		  dw 196,294,262
		  dw 330,294,262
		  dw 262
		  dw -1
mus_time2 dw 25,75
		  dw 50,12,12
		  dw 25,25,25
		  dw 25,50
		  dw 75
		  dw 25,25,25
		  dw 125,25
		  dw 75,50,12,12
		  dw 25,25,50
		  dw 25,25
		  dw 75
		  dw 50,25
		  dw 25,100
		  dw 25,75
		  dw 25,25,25
		  dw 25,25,75
		  dw 25,50,25
		  dw 50,25,125
		  dw 25,100
		  dw 25,25
		  dw 25,25,75
		  dw 25,50,25
		  dw 50,12,12
		  dw 200
;-------------------------------------------------
;《暧昧》
mus_freq3 dw 262,262,262,294,262
		  dw 392,440,330,330,294
		  dw 247,247,247,262,247
		  dw 330,392,247,294,262
		  dw 220,247,220,247,220
		  dw 330,349,262,220,247
		  dw 196,262,294,294
		  dw 349,330,330,294,262,294
		  dw 330,262,262,262,294,262
		  dw 392,440,330,330,294
		  dw 294,247,247,247,262,247
		  dw 330,392,247,294,262
		  dw 220,247,220,247,220
		  dw 330,349,220,262,247
		  dw 247,330,392,294,262
		  dw -1
mus_time3 dw 25,25,25,25,25
		  dw 25,100,25,25,100
		  dw 25,25,25,25,25
		  dw 25,100,25,25,100
		  dw 25,25,25,25,25
		  dw 25,100,25,25,75
		  dw 25,50,50,25
		  dw 50,25,25,25,50,25
		  dw 75,25,25,25,25,25
		  dw 25,100,25,25,25
		  dw 75,25,25,25,25,25
		  dw 25,100,25,25,100
		  dw 25,25,25,25,25
		  dw 25,100,25,25,25
		  dw 100,50,25,50,75
;---------------------------------------------------
;直接定址表
mus_time  dw mus_time1,mus_time2,mus_time3
mus_freq  dw mus_freq1,mus_freq2,mus_freq3
data ends
;----------------------------------------------------
code    segment para 'code'
        assume cs:code,ss:stack,ds:data
music   proc far
			
        mov ax,data
        mov ds,ax
        
        call tips;打印界面
               
		mov bh,00;第0页
        mov dh,06;第7行
        mov dl,42;第42列
        mov ah,02
        int 10h;设置光标位置
        
		mov ah,01
		int 21h;键盘输入并回显
		
input:	cmp al,30h;和'0'比较
		jb	end_error;调用end_error处理错误输入
		cmp al,33h;和'3'比较
		ja	end_error;调用end_error处理错误输入
		cmp al,30h;判断输入是否为'0'
		je	end_exit;调用end_exit退出程序
		
		sub al,30h;ASCII码转换为对应数字
		dec al;减一,因为地址从0开始
		mov ah,0;ax寄存器高位置0
		shl ax,1;每个地址数据占两个字节,向左移位实现*2
		mov di,ax;相对位移赋值给变地寄存器实现寄存器相对寻址
		mov si,mus_freq[di]
		mov bp,mus_time[di]
		
		
		mov ah,02
		mov dh,08
		mov dl,20
		int 10h;设置光标位置
		
		mov ah,09
		lea dx,tip7
		int 21h;显示输出
		
		push dx
		mov dh,08
		mov dl,26
		call timer;调用timer子程序显示开始播放时间,dh设置显示行数,dl设置显示列数
		pop dx
		
freq:
        mov     di,[si]
        cmp     di,-1
        je      end_mus;遇到-1时中止乐曲
        mov     bx,ds:[bp]
        call    soundf;调用发声子程序
        add     si,2
        add     bp,2
        jmp     freq
end_mus:
		mov bh,00
		mov dh,10
		mov dl,26
		mov ah,2
		int 10h;设置光标位置
		
		mov	ah,09
		lea dx,tip6
		int 21h;显示输出

		mov ah,02
		mov dh,11
		mov dl,20
		int 10h;设置光标位置
		
		mov ah,09
		lea dx,tip8
		int 21h;显示输出

		push dx
		mov dh,11
		mov dl,26
		call timer;调用timer程序显示结束时间
		pop dx
		
		jmp music_end;

end_exit:
		mov bh,00
		mov dh,09
		mov dl,20
		mov ah,02
		int 10h;设置光标位置
		
		mov ah,09
		lea dx,tip9
		int 21h;显示输出
		
		jmp music_end
		
end_error:
		mov ax,0b800h
		mov es,ax
		mov si,7*160+44*2
		mov byte ptr es:[si],20h;将输入处清空,以处理第二次仍然是错误的情况

		mov bh,00
		mov dh,07
		mov dl,12
		mov ah,02
		int 10h;设置光标位置
		
		mov ah,09
		lea dx,tip10
		int 21h;显示输出
		
		mov bh,00;第0页
        mov dh,07;第7行
        mov dl,44;第44列
        mov ah,02
        int 10h;设置光标位置
        
		mov ah,01
		int 21h;键盘输入并回显
		
		jmp input
		
music_end:
        mov     ax,4c00h
        int     21h
music   endp
;-----------------------------------------------------
;发声程序
soundf	proc far
        push ax
        push bx
        push cx
        push dx
        push di
        
        mov al,0b6h
        out 43h,al;对定时器2进行初始化
        mov dx,12h
        mov ax,348Ch;12348CH/DI中存放的给定频率得到声音计数值
        div di
        out 42h,al
        mov al,ah
        out 42h,al;分两次先后装入低8位和高8位的声音计数值
        in al,61h
        mov ah,al
        or al,3
        out 61h,al;将61h端口的数据0、1位置1,发声
        
WAIT1:  mov cx,4971;4971*15.08=0.07s
        call waitf;调用延迟程序
        dec bx
        jnz WAIT1

        mov al,ah
        out 61h,al;恢复接口的值
        
        pop di
        pop dx
        pop cx
        pop bx
        pop ax
        ret
soundf endp
;----------------------------------------------------
;时间延迟
waitf	proc far
		push ax
waitf1:
		in	al,61h
		and	al,10h
		cmp	al,ah
		je	waitf1
		
		mov	ah,al
		loop waitf1
		
		pop	ax
		ret
waitf	endp
;------------------------------------------------------
;打印界面 按预先设定的tip中的内容输出并更改背景颜色
tips	proc far
		push ax
		push ds
		push si
		push cx
	
		mov si,offset tip
		sub si,2
		mov cx,7
		mov al,-1
tipsf:

		mov bh,0
		inc al
		mov dh,al
		mov dl,12
		mov ah,2
		int 10h
		
		push ax
		add si,2
		mov dx,[si]
		mov ah,09
		int 21h
		pop ax


		loop tipsf
		
		mov ax,0b800h
		mov es,ax
		mov bp,0
		mov si,25
colorf:;改背景颜色
		mov byte ptr es:[bp+si],00110000B;颜色属性
		add si,2
		cmp si,95;控制改色区域的列的范围
		jb colorf
		add bp,160
		mov si,25
		cmp bp,160*6;控制改色区域为1-6行
		jb colorf
		
		pop cx
		pop si
		pop ds
		pop ax
		ret
		
tips	endp
;------------------------------------------------------
;显示当前时间,dh设置输出所在的行数,dl设置列数
timer proc far
		push ax
		push ds
		push si
		push di
		push cx
		push bx
	
		mov ax,data
		mov ds,ax
start:	mov si,offset table
		mov di,offset time
		
		mov cx,6
s1:		push cx
		mov al,ds:[si]
		out 70h,al;向70h写入要访问的单元的地址
		in al,71h;从71h中得到指定单元的数据
		
		mov ah,al
		mov cl,4
		shr	ah,cl;十位数码值
		add ah,30h;转换位ASCII码
		and al,00001111b;个位数码值
		add al,30h;转换位ASCII码
		mov ds:[di],ah
		mov ds:[di+1],al
		add di,3
		inc si
		pop cx		
		loop s1
		
		mov bh,0
		mov ah,2
		int 10h;根据预先指定的dh,dl设定光标位置
		
		mov dx,offset time
		mov ah,9
		int 21h;显示输出
		
		pop bx
		pop cx
		pop di
		pop si
		pop ds
		pop ax
		ret
timer endp
;------------------------------------------------------
code    ends
;---------------------------------------------------------
        end     music 

11b;个位数码值
		add al,30h;转换位ASCII码
		mov ds:[di],ah
		mov ds:[di+1],al
		add di,3
		inc si
		pop cx		
		loop s1
		
		mov bh,0
		mov ah,2
		int 10h;根据预先指定的dh,dl设定光标位置
		
		mov dx,offset time
		mov ah,9
		int 21h;显示输出
		
		pop bx
		pop cx
		pop di
		pop si
		pop ds
		pop ax
		ret
timer endp
;------------------------------------------------------
code    ends
;---------------------------------------------------------
        end     music 
相关推荐
Crossoads15 小时前
【汇编语言】端口 —— 「从端口到时间:一文了解CMOS RAM与汇编指令的交汇」
android·java·汇编·深度学习·网络协议·机器学习·汇编语言
雪碧透心凉_3 天前
8086汇编(16位汇编)学习笔记00.DEBUG命令使用解析及范例大全
汇编
C66668886 天前
C#多线程
开发语言·汇编·c#
傻童:CPU6 天前
汇编源程序的理解
汇编
木槿717 天前
软件包git没有可安装候选
汇编·git
ok0607 天前
各种开源汇编、反汇编引擎的非专业比较
汇编·开源
roboko_7 天前
MIPS指令集(一)基本操作
汇编
Crossoads7 天前
【汇编语言】内中断(三) —— 中断探险:从do0到特殊响应的奇妙旅程
android·开发语言·javascript·网络·汇编·单片机·机器学习
染指11108 天前
49.第二阶段x86游戏实战2-鼠标点击call深追二叉树
汇编·c++·windows·游戏安全·反游戏外挂·游戏逆向
程序leo源10 天前
深入理解指针
android·c语言·开发语言·汇编·c++·青少年编程·c#