assume cs:codeseg, ds:dataseg, ss:stackseg
dataseg segment
mus_freq dw 220,392,330,262,294,131,294,262
dw 131,392,330,262,220,392,330,262
dw 294,131,294,262,131,392,330,262
dw -1 ;频率
mus_time dw 8 dup(50)
dw 8 dup(50)
dw 8 dup(50);节拍
dataseg ends
stackseg segment
db 100 dup (0)
stackseg ends
codeseg segment
start:
mov ax, stackseg
mov ss, ax;装载
mov sp, 100
mov ax, dataseg
mov ds, ax
lea si, mus_freq
lea di, mus_time;初始化,si频率,di节拍
play:
mov dx, [si]
cmp dx, -1
je end_play
call sound
add si, 2
add di, 2;指针移动
jmp play
end_play:
mov ax, 4c00h
int 21h
sound:
push ax
push dx
push cx
mov al,0b6h
out 43h,al
mov dx,12h
mov ax,34dch
div word ptr [si]
out 42h, al
mov al, ah
out 42h, al
in al,61h
mov ah,al
or al,3
out 61h,al ;调用端口
mov dx, [di]
wait1:
mov cx, 28000
delay:
nop
loop delay
dec dx
jnz wait1
mov al, ah
out 61h, al
pop cx
pop dx
pop ax
ret
codeseg ends
end start
其中:
mus_freq dw 220,392,330,262,294,131,294,262
dw 131,392,330,262,220,392,330,262
dw 294,131,294,262,131,392,330,262
dw -1 ;频率
前几行可以任意存放数值,数值大小对应着发声音频率的高低(可以在网上搜到数值对应表)
而最后一行不可以改,必须要是-1,这是发生截止条件
然后:
mus_time dw 8 dup(50)
dw 8 dup(50)
dw 8 dup(50);节拍
代表了节拍,
我第一行8个音符,8个音符都是同样节拍,就设置为 dw 8 dup(50),括号内的50,是比较优的数值,让每拍不长不短
数据段(dataseg)
- 定义了两个数组
mus_freq和mus_time。mus_freq包含了音符的频率(以赫兹为单位),mus_time定义了每个音符的持续时间。音符频率以-1结束,标志着曲目的结束。
堆栈段(stackseg)
- 分配了100字节的空间作为程序的堆栈。这个空间用于存储临时数据和地址,以支持程序的调用和返回操作。
代码段(codeseg)
- 初始化堆栈和数据段:程序首先设置堆栈段
ss和数据段ds,确保程序可以正确访问数据和使用堆栈。 - 音乐播放循环:通过
play标签处的循环,程序遍历mus_freq数组中的每个音符。使用cmp dx, -1和je end_play指令检查音符是否为结束标志(-1)。 - 生成声音:通过调用
sound过程,程序使用输入输出操作(out指令)来控制PC的计时器(PIT - Programmable Interval Timer),从而生成特定频率的声音。这个过程涉及到设置PIT的控制字,计算并设置计时器的计数值,以及开启扬声器。 - 节拍延时:在
sound过程中,使用wait1和delay循环实现延时,控制音符的持续时间。这是通过简单地执行大量的nop(无操作)指令实现的。 - 关闭声音和恢复环境:在每个音符播放完毕后,关闭扬声器,并在
sound过程的末尾恢复被保存的寄存器值。 - 结束程序:当所有音符播放完毕后,通过
mov ax, 4c00h和int 21h指令结束程序,返回操作系统。
关键点:
- 直接硬件控制:程序直接通过端口写操作控制计时器和扬声器,这是早期PC编程中常见的方式,允许程序直接与硬件交互。
- 音频生成:音频的生成依赖于修改计时器的频率,从而驱动扬声器产生不同频率的声音。
- 程序流程:程序流程清晰,首先通过初始化准备数据和堆栈环境,然后进入播放循环,对每个音符进行处理,最后结束程序。
该程序通过直接控制PC的计时器和扬声器,使用汇编语言生成特定频率的声音,实现音乐播放。数据段定义了音符频率和持续时间,堆栈段分配了内存供程序使用。代码段中,初始化堆栈和数据段后,通过循环播放音符并调整计时器实现节拍。程序以-1作为结束标志,利用NOP指令实现延迟,控制音符的持续时间。
1万+

被折叠的 条评论
为什么被折叠?



