组装 8086 - DOSBOX - 如何产生蜂鸣声? [英] Assembly 8086 - DOSBOX - How to produce beep sound?

查看:41
本文介绍了组装 8086 - DOSBOX - 如何产生蜂鸣声?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在组装一个西蒙"游戏,我需要在按钮打开时发出哔哔声,哔哔声也应该彼此不同.谢谢

解决方案

您可以使用

PIT 是通过端口 40h-43h 控制的,我们将在每次分频器的两个字节时使用模式 3(方波发生器)设置.
PIT有一个运行在1.193180 MHz左右的振荡器,分频器用于控制方波的周期.
不处理内部结构:在 PIT 振荡器的每个滴答声中,加载的分频器都会递减.方波的周期等于 PIT 将分频器递减到零所需的时间.

产生声音只是使用所需的分频器对 PIT 进行编程并启用扬声器的问题.
稍后,我们需要禁用它.
一个简单的方法是使用 int 1ch,它被称为 18.2 次 a第二个.

通过在第一次播放声音时将持续时间保存在变量中,通过在 int 1ch 的每个滴答声中递减它并在计数达到零时禁用扬声器,可以控制哔声的持续时间.

使用 int 1ch 需要设置函数 (beep_setup) 和拆卸函数 (beep_teardown).

BITS 16组织 100 小时__开始__:;设置呼叫 beep_setup;示例蜂鸣声约 2 秒mov ax, 2000mov bx, 36呼叫 beep_play;等待输入异或斧头,斧头整数 16 小时;拆除呼叫 beep_teardownmov ax, 4c00h21 小时;-------------------------------------------------;;设置哔声ISR;beep_setup:推es推斧异或斧头,斧头移动,斧头;保存原来的ISRmov ax, WORD [es: TIMER_INT * 4]mov WORD [cs:original_timer_isr], axmov ax, WORD [es: TIMER_INT * 4 + 2]mov WORD [cs:original_timer_isr + 2], ax;设置新的ISR命令行mov ax, beep_isrmov WORD [es: TIMER_INT * 4], axmov ax, csmov WORD [es: TIMER_INT * 4 + 2], ax性病流行斧教皇回复;;拆下哔声ISR;beep_teardown:推es推斧呼叫 beep_stop异或斧头,斧头移动,斧头;恢复旧的ISR命令行mov ax, WORD [cs:original_timer_isr]mov WORD [es: TIMER_INT * 4], axmov ax, WORD [cs:original_timer_isr + 2]mov WORD [es: TIMER_INT * 4 + 2], ax性病流行斧教皇回复;;哔声ISR;beep_isr:cmp 字节 [cs:sound_playing], 0je_bi_endcmp WORD [cs:sound_counter], 0je _bi_stop十二月字 [cs:sound_counter]jmp_bi_end_bi_stop:呼叫 beep_stop_bi_end:;链jmp FAR [cs:original_timer_isr];;停止哔声;哔声停止:推斧;停止声音在 al, 61h和 al, 0fch ;清除位 0(PIT 到扬声器)和位 1(扬声器启用)出 61h, al;禁用倒计时mov BYTE [cs:sound_playing], 0流行斧回复;;嘟;;AX = 1193180/频率;BX = 18.2 秒的持续时间beep_play:推斧推dxmov dx, ax移动, 0b6h出 43h, almov ax, dx出 42h, al移动,啊出 42h, al;设置倒计时mov WORD [cs:sound_counter], bx;开始声音在 al, 61hor al, 3h ;设置位0(PIT到扬声器)和位1(扬声器启用)出 61h, al;开始倒计时mov BYTE [cs:sound_playing], 1流行音乐流行斧回复;将这些保留在代码段中sound_playing db 0sound_counter dw 0original_timer_isr dd 0TIMER_INT EQU 1ch

特别感谢 Sep Roland 用于修复原始代码中的一个缺陷!

您可以使用 beep_play 来播放哔哔声,使用的单位是上述硬件配置的自然"单位.
如果您的频率和持续时间是固定的,这些单位可以免费简化代码.

在给定的持续时间后蜂鸣停止,您可以使用beep_stop强行停止.

一次播放多个声音是不可能的(如果不采用 PWM 技术,即使混合它们也是不可能的).
在另一个哔声正在播放时调用 beep_play 将停止当前的哔声并开始新的哔声.

I am working on a "simon" game in assembly I need to make a beep sound whenever a button turns on, the beeps should be different from each other as well. thanks

解决方案

You can use the speaker to keep your design simple.
The speaker lets you play square waves at different frequencies, it can actually be used to reproduce digital audio but that's more involved.

The speaker is just an electromagnet, when the current flows through it, it is pulled back otherwise it stays in its default position.
By moving the speaker back and forth it's possible to create sound waves.

The speaker can be moved manually or by using the PIT's channel 2.
Bit 0 of port 61h controls the speaker source (0 = manual, 1 = PIT) and the bit 1 of the same port is the "speaker enable" bit when using the PIT (the speaker "position" when not).

Here's a schematic (from this page) missing the manual driving part:

The PIT is controlled via port 40h-43h, we will use Mode 3 (Square Wave generator) setting each time both bytes of the divider.
The PIT has an oscillator running at about 1.193180 MHz, the divider is used to control the period of the square wave.
Without dealing with internals: at each tick of the PIT oscillator the divider loaded is decremented. The period of the square wave is equal to the time needed by the PIT to decrement the divider down to zero.

Producing a sound is just a matter of programming the PIT with the desired divider and enabling the speaker.
At some time later, we need to disable it.
An easy way to do this is using the int 1ch that is called 18.2 times a second.

By saving a duration in a variable when first playing a sound, by decrementing it at each tick of the int 1ch and by disabling the speaker when the count reaches zero it's possible to control the duration of the beep.

Using the int 1ch requires a setup function (beep_setup) and a teardown function (beep_teardown).

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

Special thanks to Sep Roland for fixing a flaw in the original code!

You can use beep_play to play a beep, the units used are the "natural" unit of the hardware configuration explained above.
If your frequencies and duration are fixed, these units simplify the code at no cost.

The beep stops after the duration given, you can use beep_stop to stop it forcefully.

Playing multiple sound at a time it's impossible (even mixing them is impossible without resorting to PWM techniques).
Calling beep_play while another beep is in play will have the effect of stopping the current beep and starting the new one.

这篇关于组装 8086 - DOSBOX - 如何产生蜂鸣声?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆