组装播放音频文件 TASM 16 位

Assembly playing audio file TASM 16 bit

您好,我正在为学校项目编写游戏,但在播放音频文件时遇到问题。 我能够播放文件,但问题是程序冻结并停止响应用户

音乐文件代码

proc read Near ; Read next sample
    push bx
    push cx
    push dx
    mov ah, 3Fh
    mov bx, [filehandle]
    mov cx, 1
    lea dx, [Buffer]
    int 21h
    jc errorcode
    mov al, [Buffer]
    xor ah, ah
    mov bx, 54
    mul bx
    ; mov ax, dx ; Result is in DX because we need to div by 65536 which is all of AX
    shr ax, 8
    pop dx
    pop cx
    pop bx
    ret
endp
proc br Near; Print line break
    push dx
    push ax
    mov dl, 10
    mov ah, 2
    int 21h
    mov dl, 13
    mov ah, 2
    int 21h
    pop ax
    pop dx
    ret
endp
proc PlayMusic Near
    mov ah, 3Dh
    xor al, al
    lea dx, [filename]
    int 21h
    mov [filehandle], ax
    call br
    mov al, 90h
    out 43h, al
in al, 61h
    or al, 3
    out 61h, al
    cli
    mov ax, 0
totalloop:
    call read ; Read file
    out 42h, al ; Send data
    mov bx, ax
    mov cx, [delay]
portloop:
    loop portloop
    mov ax, bx
    out 42h, ax ; Send data
    mov cx, [delay]
rloop:
    loop rloop
    call read
    jmp totalloop
    ret
errorcode:
    ; Close
    sti
    mov al, 86h
    out 43h, al
    mov ah, 3Eh
    mov bx, [filehandle]
    int 21h
    pop dx
    pop cx
    pop bx
    ret
endp PlayMusic

在我调用这个 proc 之后,我调用 int 16h 来从用户那里读取一个密钥,但是音乐文件阻塞了 IO 有人知道我需要做什么吗? 顺便说一下,对不起我的英语不好 我是装配新手,所以我不太好

您想要做的是 "parallelize" 您的游戏代码(不使用线程)。关于如何执行此操作的选项很少:

  1. 交错代码

    这是最容易实现的方法。所以你的游戏架构应该是这样的:

    loop:handle input
         handle game logic
         render frame
         play sound (20-40ms)
         jmp loop
    

    此架构将允许游戏 运行 在 "parallel" 中完成所有任务。如果你的任务比较慢,你可以多插入一点音乐

    loop:handle input
         play sound (~10ms)
         handle game logic
         play sound (~10ms)
         render frame
         play sound (~10ms)
         jmp loop
    

    如果任何任务真的很慢,那么您需要直接将声音插入其中,否则声音会断断续续。这是一个例子(没有声音):

    这是有声的(但不是游戏):

    • No Signal demo

    您需要使您的键盘测试成为非阻塞的。取自我的无信号演示,它是这样完成的:

        mov ah,1    ; non blocking key test
        int 16h
        jz keyr0
        sub ax,ax   ; blocking key test
        int 16h
        ; here handle the key press...
    keyr0:          ; here continues your code
    
  2. 使用 PIT 作为发生器播放声音

    我没有使用这个,但是 IIRC PIT 可以配置为使用扬声器播放恒定频率。因此,无需设置扬声器 on/off,您只需设置其每帧左右的频率...这将在后台播放,在此期间 CPU 可以执行其他东西...

  3. 使用 PIT 作为定时器在后台播放声音

    为了更好的定时和在后台播放与游戏代码平行的声音,您可以将播放的声音完全移动到 PIT ISR,它可以在 1193180.0/16bit_divider Hz 运行,因此设置 PIT 到目标声音采样频率。为其设置 ISR 并在其中设置 fetch/play 单个位....

    如果你使用PWM和采样频率的倍数你可以把Speaker变成DAC甚至播放PCM*.wav 文件。

    在这种情况下,您根本不会在游戏循环中插入声音代码。

不要忘记在退出前将 PIT 频率设置回 18.2 Hz 因为 MS-DOS 和游戏用它来计时。许多游戏可以通过单独更改 PIT 频率来加速。此外,当您更改 PIT 频率和 ISR 时,最好从新的 ISR 调用频率为 18.2Hz 的原始 ISR。

有关 PC MS-DOS 和游戏的更多信息,请参阅:

  • PCGPE 1.0
  • WPCGPE 1.0 这应该是 *.hlp 格式(你需要 Windows6.1-KB917607 Win7+ 补丁,因为他们停止支持它)

这是我所知道的最适合入门的汇编:

但是 Z80 CPU 是捷克语,我不知道有任何翻译....