本文介绍了使用 OUT 指令在传统 PC 扬声器上生成声音的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在尝试用汇编代码生成声音.这是我发现的一些代码:

I'm currently trying to generate a sound in assembly code. Here is some code i found:

    section .text
  global sound

sound:
    mov     al, 182         ; meaning that we're about to load
    mov     ax, 182
    out     43h, al         ; a new countdown value
    ret
    mov     ax, 2153        ; countdown value is stored in ax. It is calculated by
    out     42h, al         ; Output low byte.
    mov     al, ah          ; Output high byte.
    out     42h, al

    in      al, 61h
    or      al, 00000011b
    out     61h, al     ; Send the new value
    ret

根据此代码的所有者的说法,它应该可以工作,但是当我使用 C main 运行它时,它被分段错误杀死了.

According to the owner of this code, it should be working, but when I run it with a C main, it's killed by a segmentation fault.

通过进一步的研究,我发现在现代操作系统中,由于权限的原因,很难访问扬声器.如果有人知道如何使用扬声器并播放声音,我很乐意学习.

With further researches, I found that in modern OS, it was harder to access the speakers because of rights . If someone knows how to access the speakers and play a sound, I would love to learn it.

注意:当我以超级用户身份运行我的代码时,我没有遇到分段错误,但没有产生声音.

Note: when I run my code as a super user, I get no segmentation fault, but no sound is produced.

推荐答案

[在使用 NASM 编译器阅读本文之前,我不确定其他编译器]

[BEFORE YOU READ THIS WORKS WITH THE NASM COMPILER, I'M NOT SURE ABOUT OTHER COMPILERS]

您的代码很好,但问题是:

Your code is fine but here's the problem:

  1. 它不会在虚拟机中产生声音.0x43、0x42 端口的用途是 PIT(可编程间隔定时器)芯片,它处理您可以在此处阅读的内容 OSDEVWIKI.PIT 芯片处理的一件事是板载扬声器,这就是您要访问的内容.虚拟机没有板载扬声器.
  1. It will not produce sound in a virtual machine.What the 0x43, 0x42 ports are for are the PIT (Programmable Interval Timer) chip which handles somethings which you can read up on here OSDEVWIKI. One of the things the PIT chip handles is the on board speaker which is what you are trying to access. Virtual machines don't have an onboardspeaker.

长话短说,您正在尝试访问主板扬声器,但虚拟机无法使用它,因此您听不到任何声音.

Long story short you are trying to access the motherboard speaker but virtual machines can't use it so you don't hear anything.

此外,大多数较新的主板也没有板载扬声器.

Also most newer motherboards don't have on board speakers either.

  1. 您的代码.因此,仅看一眼您的代码,我猜您正在使用 nasm,因此我对此感到有些困惑:
mov     al, 182         ; meaning that we're about to load
mov     ax, 182
out     43h, al         ; a new countdown value
ret

要稍微修饰一下这部分,您可以删除 mov ax, 182ret 因为那里的返回会跳出代码到您调用的位置它不再运行代码制作:

To touch up this part a little you can remove the mov ax, 182 and the ret because the return right there will jump out of the code to where you called it no longer running the code making:

mov     ax, 2153        ; countdown value is stored in ax. It is calculated by
out     42h, al         ; Output low byte.
mov     al, ah          ; Output high byte.
out     42h, al

in      al, 61h
or      al, 00000011b
out     61h, al     ; Send the new value
ret

过时了.对于 mov ax, 182,当我使用扬声器时,我的作品没有这个,所以我猜你不需要它,所以我会说如果有必要就删除它.

obsolete. For the mov ax, 182 when I use the speaker mine works without this so my guess is you don't need it so I'd say remove it if it is necessary.

因此,您的代码的改进版本将是:

So a revamped version of your code would be:

bits 16

start:
mov ax, 0x07c0   ; Setup the stack past where we are loaded
add ax, 544
cli              ; Disable interrupts
mov ss, ax
mov sp, 4096
sti              ; Restore interrupts

mov ax, 0x07c0   ; Set the data segment to where we are
mov ds, ax

sound:
mov al, 182         ; Were about to load
out 0x43, al

mov ax, 15000       ; 15000(Pitch) = 1,193,180 / 79.5453333(Repeating)

out 0x42, al        ; Give the port the lower value
mov al, ah
out 0x42, al        ; Now give it the higher

in al, 0x61

or al, 00000011b    ; Connect the speaker to Timer 2
out 0x61, al
jmp $               ; hang

times 510-($-$$) db 0     ; Pad the rest of the file with 0's
dw 0xaa55                 ; Little Endian MBR Signature

要运行它以查看它是否有效,请确保您拥有的计算机具有板载扬声器.我的看起来像这样:这里

To run this to see if this works make sure the computer you have has an on board speaker. Mine looks like this:here

如果你没有它,你的可能看起来不像我的,如果没有,你可以在代码之后显示或做一些事情以确保它运行.

If you don't have it yours may not look like mine, if there isn't one you could display or make something happen after the code to make sure it ran.

我使用这些命令来运行它.

I use these commands to run it.

nasm -f bin <YOURFILENAME>.asm -o boot.bin
dd if=boot.bin of=\\.\<DRIVENUMBER>: bs=512

这些做的是 nasm 一个是 nasm 编译器并编译程序集文件.如果你在 linux 上,dd 是 rawwrite,它已经存在,但在我使用的 Windows 上,你可以下载 rawwrite 这里.确保您的驱动器编号是您使用的驱动器,例如 USB 或软盘.例如,如果您的 USB 位于驱动器 d 上:您将使用:dd if=boot.bin of=\\.\d: bs=512

What these do is the nasm one is the nasm compiler and compiles the assembly file. The dd one is rawwrite if you are on linux it is already there, but on windows like I am using you can download rawwrite here. MAKE SURE YOUR DRIVE NUMBER IS THE DRIVE YOU ARE USING SUCH AS A USB OR FLOPPY. An example would be if your usb is on drive d: you would use:dd if=boot.bin of=\\.\d: bs=512

然后你就可以用振荡器把usb插到电脑上了.启动计算机并为我进入启动菜单我只是垃圾邮件 f10 直到我到达那里但对你来说它可能是一个不同的按钮在那里你会被问到你应该启动什么设备来找到你的 USB 并启动它.如果没有 os 显示,它应该启动:

Then you can plug the usb into the computer with the oscillator. Boot up the computer and get into the boot menu for me I just spam f10 until I get there but for you it may be a different button there you will be asked what device you should boot to find your usb and boot to it. It should boot if not have the os display something like:

mov ah, 0x0e
mov al, 'X'
int 0x10

bits 16之后添加到文件顶部,看看它是否正在启动:

To see if it is booting if not add this to the top of the file AFTER bits 16:

jmp short start
nop

OEMLabel            db "Contoso"   ; OEM Label
BytesPerSector      dw 512          ; There are 512b per sector
SectorsPerCluster   db 1            ; Sectors per cluster
ReservedForBoot     dw 1            ; # of sectors reserved for boot
NumberOfFats        db 2            ; # of fats
RootDirEntries      dw 224          ; # of root directory entries
LogicalSectors      dw 2880         ; # of sectors
MediumByte          db 0x0f0        ; Medium descriptor byte
SectorsPerFat       dw 9            ; # of sectors per fat
SectorsPerTrack     dw 18           ; # of sectors per track
Sides               dw 2            ; # of sides
HiddenSectors       dd 0            ; # of hidden sectors
LargeSectors        dd 0            ; # of large sectors
DriveNo             dw 0            ; The drive number
Signature           db 41           ; The drive signature
VolumeID            dd 0xdeadbeef   ; The volume id
VolumeLabel         db "Windows9   "; This can be any 11 characters
FileSystem          db "FAT12   "   ; File system of the floppy DONT CHANGE

如果由于任何原因代码不起作用,请检查是否有任何错误并确保您的主板具有板载扬声器.

If for any reason the code doesn't work check for any errors and make sure your motherboard has an on board speaker.

有关更多信息,请转到此处,如上所述.源代码的基础此处.有关组装的一些提示这里,这是一个记录良好的开源操作系统,可帮助初学者学习组装.

For more info go here as said above.Base of the source code here.For some tips on assembly here, this is a very well documented open source OS to help beginners learn assembly.

希望这会有所帮助!

Peter Cordes 的一些拼写错误和帮助(在评论中)

Some Typos and help from Peter Cordes (In the comments)

这篇关于使用 OUT 指令在传统 PC 扬声器上生成声音的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-01 08:34