Assembly 组件8086-DOSBOX-如何产生蜂鸣音?
我正在组装一个“西蒙”游戏。每当按钮打开时,我需要发出嘟嘟声,嘟嘟声应该彼此不同。 谢谢您可以使用保持设计简单。Assembly 组件8086-DOSBOX-如何产生蜂鸣音?,assembly,x86,dos,x86-16,dosbox,Assembly,X86,Dos,X86 16,Dosbox,我正在组装一个“西蒙”游戏。每当按钮打开时,我需要发出嘟嘟声,嘟嘟声应该彼此不同。 谢谢您可以使用保持设计简单。 扬声器可以让你播放不同频率的方波,但这更复杂 扬声器只是一个电磁铁,当电流流过时,它会被拉回,否则它会保持在默认位置。 通过前后移动扬声器,可以产生声波 可以手动或使用的频道2移动扬声器。 端口61h的位0控制扬声器源(0=手动,1=PIT),使用PIT时,同一端口的位1为“扬声器启用”位(不使用PIT时为扬声器“位置”) 以下是缺少手动驱动部分的示意图(由此可知): PIT通过端
扬声器可以让你播放不同频率的方波,但这更复杂 扬声器只是一个电磁铁,当电流流过时,它会被拉回,否则它会保持在默认位置。
通过前后移动扬声器,可以产生声波 可以手动或使用的频道2移动扬声器。
端口61h的位0控制扬声器源(0=手动,1=PIT),使用PIT时,同一端口的位1为“扬声器启用”位(不使用PIT时为扬声器“位置”) 以下是缺少手动驱动部分的示意图(由此可知): PIT通过端口40h-43h进行控制,我们将使用模式3(方波发生器)设置,每次两个字节的分频器都进行设置。
PIT有一个运行频率约为1.193180 MHz的振荡器,分频器用于控制方波的周期。
不涉及内部构件:在PIT振荡器的每个刻度处,加载的分压器减小。方波的周期等于凹坑将分频器减小到零所需的时间 产生声音只需使用所需的分频器对PIT进行编程并启用扬声器即可。
稍后,我们需要禁用它。
一种简单的方法是使用每秒18.2次的 通过在第一次播放声音时将持续时间保存在变量中,在int 1ch的每一个滴答声时将其递减,并在计数为零时禁用扬声器,可以控制嘟嘟声的持续时间 使用int 1ch需要设置功能(
beep_setup
)和拆卸功能(beep_teardown
)
特别感谢您修复了原始代码中的一个缺陷
您可以使用beep\u play
播放蜂鸣音,使用的单位是上述硬件配置的“自然”单位。如果您的频率和持续时间是固定的,那么这些单元可以免费简化代码 嘟嘟声在给定的持续时间后停止,您可以使用
beep_stop
强制停止
一次播放多个声音是不可能的(如果不使用PWM技术,甚至混音也是不可能的)。当另一个蜂鸣音正在播放时,调用
beep\u play
,将产生停止当前蜂鸣音并启动新蜂鸣音的效果。可能重复您是否参考了DOS中断参考?这是一个很好的答案+1但是beep_isr中断服务程序有一个重要问题!不能只使用AX
寄存器而不保留它。如果您编写:cmp单词[cs:sound\u counter],0
je\u bi\u stop
dec单词[cs:sound\u counter]
。根本不需要使用AX。非常感谢@SepRoland!我正在用学分更新答案:)
BITS 16
ORG 100h
__start__:
;Setup
call beep_setup
;Sample beep of ~2sec
mov ax, 2000
mov bx, 36
call beep_play
;Wait for input
xor ax, ax
int 16h
;Tear down
call beep_teardown
mov ax, 4c00h
int 21h
;-------------------------------------------------
;
;Setup the beep ISR
;
beep_setup:
push es
push ax
xor ax, ax
mov es, ax
;Save the original ISR
mov ax, WORD [es: TIMER_INT * 4]
mov WORD [cs:original_timer_isr], ax
mov ax, WORD [es: TIMER_INT * 4 + 2]
mov WORD [cs:original_timer_isr + 2], ax
;Setup the new ISR
cli
mov ax, beep_isr
mov WORD [es: TIMER_INT * 4], ax
mov ax, cs
mov WORD [es: TIMER_INT * 4 + 2], ax
sti
pop ax
pop es
ret
;
;Tear down the beep ISR
;
beep_teardown:
push es
push ax
call beep_stop
xor ax, ax
mov es, ax
;Restore the old ISR
cli
mov ax, WORD [cs:original_timer_isr]
mov WORD [es: TIMER_INT * 4], ax
mov ax, WORD [cs:original_timer_isr + 2]
mov WORD [es: TIMER_INT * 4 + 2], ax
sti
pop ax
pop es
ret
;
;Beep ISR
;
beep_isr:
cmp BYTE [cs:sound_playing], 0
je _bi_end
cmp WORD [cs:sound_counter], 0
je _bi_stop
dec WORD [cs:sound_counter]
jmp _bi_end
_bi_stop:
call beep_stop
_bi_end:
;Chain
jmp FAR [cs:original_timer_isr]
;
;Stop beep
;
beep_stop:
push ax
;Stop the sound
in al, 61h
and al, 0fch ;Clear bit 0 (PIT to speaker) and bit 1 (Speaker enable)
out 61h, al
;Disable countdown
mov BYTE [cs:sound_playing], 0
pop ax
ret
;
;Beep
;
;AX = 1193180 / frequency
;BX = duration in 18.2th of sec
beep_play:
push ax
push dx
mov dx, ax
mov al, 0b6h
out 43h, al
mov ax, dx
out 42h, al
mov al, ah
out 42h, al
;Set the countdown
mov WORD [cs:sound_counter], bx
;Start the sound
in al, 61h
or al, 3h ;Set bit 0 (PIT to speaker) and bit 1 (Speaker enable)
out 61h, al
;Start the countdown
mov BYTE [cs:sound_playing], 1
pop dx
pop ax
ret
;Keep these in the code segment
sound_playing db 0
sound_counter dw 0
original_timer_isr dd 0
TIMER_INT EQU 1ch