在 x86 Assembly 中使用 PC 扬声器播放声音

Ins*_*ere 3 audio x86 assembly operating-system

因此,我尝试使用 x86 组件中的 pc 扬声器播放单音,它会播放声音,但是当我再次尝试将其关闭时......音调开始做我只能描述为颤抖的事情。

此外,如果这意味着什么,我正在为 16 位操作系统制作它。

这是我的 sound.asm 文件

; ------------------------------------------------------------------
; os_play_sound -- Play a single tone using the pc speaker
; IN: CX = tone, BX = duration

os_play_sound:
    mov     al, 182
    out     0x43, al
    mov     ax, cx

    out     0x42, al
    mov     al, ah
    out     0x42, al
    in      al, 0x61

    or      al, 00000011b
    out     0x61, al

    .pause1:
        mov cx, 65535

    .pause2:
        dec cx
        jne .pause2
        dec bx
        jne .pause1

        in  al, 0x61
        and al, 11111100b
        out 0x61, al

        ret
Run Code Online (Sandbox Code Playgroud)

这是 main.asm 中的部分,我从这里调用 sound.asm 标签

mov cx, 9121
mov bx, 25
call os_play_sound
Run Code Online (Sandbox Code Playgroud)

Krz*_*zyk 5

我参加聚会有点晚了,您可能已经想通了,但这是我对未来 StackOverflow 潜伏几代人的回答;)。

您可以测试以下代码段(基于您的代码;稍微清理一下),它实际上会发出音调,但请等待使用INT15Hfunction AX=86H。这通常比忙等待更好的做法,但比根据您的需要重新编程 PIT 稍差。由于您使用 MikeOS 作为主要代码库,因此我希望代码尽可能简单。包括注释以进一步理解代码。

; ---------------------------------------------
; Generate tone with frequency specified in AX.
; The tone will last for CX:DX microseconds.
; For instance, CX=0, DX=F4240h will play the
; specified tone for one second.
; Registers preserved.

tone:
    PUSHA               ; Prolog: Preserve all registers
    MOV BX, AX          ; 1) Preserve the note value by storing it in BX.
    MOV AL, 182         ; 2) Set up the write to the control word register.
    OUT 43h, AL         ; 2) Perform the write.
    MOV AX, BX          ; 2) Pull back the frequency from BX.
    OUT 42h, AL         ; 2) Send lower byte of the frequency.
    MOV AL, AH          ; 2) Load higher byte of the frequency.
    OUT 42h, AL         ; 2) Send the higher byte.
    IN AL, 61h          ; 3) Read the current keyboard controller status.
    OR AL, 03h          ; 3) Turn on 0 and 1 bit, enabling the PC speaker gate and the data transfer.
    OUT 61h, AL         ; 3) Save the new keyboard controller status.
    MOV AH, 86h         ; 4) Load the BIOS WAIT, int15h function AH=86h.
    INT 15h             ; 4) Immidiately interrupt. The delay is already in CX:DX.
    IN AL, 61h          ; 5) Read the current keyboard controller status.
    AND AL, 0FCh        ; 5) Zero 0 and 1 bit, simply disabling the gate.
    OUT 61h, AL         ; 5) Write the new keyboard controller status.
    POPA                ; Epilog: Pop off all the registers pushed
    RET                 ; Epilog: Return.
Run Code Online (Sandbox Code Playgroud)