-1

Hello i'm writing a game for school project and i'm having problems to play an audio file. I was able to play the file but the problem is that then the program freezes and stop responding to the user

The music file code

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

and after i call this proc i'm calling int 16h to read a key from the user but the music file blocks the IO someone have an idea what I need to do? sorry for my bad English by the way and i'm kind of new in assembly so i'm not so good

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • That code is quite messed up. For example, why are you jumping from the function `read` to the `errorcode`? – Jester Jan 29 '18 at 17:52
  • 1
    It will jump to error code only when the carry flag is turned on so that mean when there is an error – ShaharDagan14 Jan 29 '18 at 18:00
  • But it does wrong things. It does not match the prologue of `read` and does not even signal an error to the caller. – Jester Jan 29 '18 at 18:49
  • When you jump from `read` to `errorcode` you ignore the 6 bytes `PUSH`ed to the stack in the beginning of `read`. That could cause an unresolvable stack error aka hang-up (most like at the following `ret` instruction, because the return address has been messed up). – zx485 Jan 29 '18 at 19:12
  • You right I just fixed this error. do you maybe have an idea about how I can make the program continue to interact with the user when I play the audio raw file? – ShaharDagan14 Jan 29 '18 at 19:46
  • You still don't return any error information so your `jmp totalloop` will just ... loop forever. – Jester Jan 29 '18 at 19:49
  • 1
    I don't think there are many 86 bit processors (as in title). I assume you meant 16 bit or x86, right? – Rudy Velthuis Jan 29 '18 at 22:04
  • I'm kind of a beginner in Assembly do you have maybe some reference I can read that explain how to do it? @Spektre – ShaharDagan14 Jan 30 '18 at 09:41
  • @שחרדגן how to do what from the 3 options I mentioned. – Spektre Jan 30 '18 at 10:41
  • What do you think is the best option? by the way after I get some key from the keyboard I call the mainloop function that will draw the player and get input to move him and I need that the music continue to play all the time @Spektre – ShaharDagan14 Jan 30 '18 at 12:27
  • @שחרדגן (I repaired the bullet names they where out of order). The best is the **#3** but that it is hardest to implement especially if you did not code any ISR before. If I where you I would start with **#1** and tweak the interleaving and times until sound is not choppy. – Spektre Jan 30 '18 at 12:36
  • @שחרדגן btw if you go for SoundBlaster sound that uses DMA which is even better ... – Spektre Jan 30 '18 at 12:37
  • I want to understand more how the code work (I copied most of the parts of my game from the Internet and change it a little bit but I don't understand it and I need to explain the code to my teacher as a test) do you have some reference/book/videos I can learn how the build a game in graphics mode and understand it more?(read images and play audio and all that stuff works) @Spektre – ShaharDagan14 Jan 30 '18 at 12:41
  • 1
    @שחרדגן see [PCGPE 1.0](https://www.pcorner.com/list/UPLOAD/PCGPE.ZIP/INFO/) there is all the stuff you need like VGA/VESA, TSR,ISR,PIT ,SB, DOOM , Plasma and Fire and much much more .... however the best book of all times for assembly rookies is: [Assembler a ZX Spectrum 1](https://mts.speccy.cz/doc/asm_a_zxs_1.pdf) but it is in Czech for Z80 CPU and I do not know of any translations .... – Spektre Jan 30 '18 at 12:43
  • Do you maybe know more good books that explains this material?(not something hard and long because I don't have much time left) @Spektre – ShaharDagan14 Jan 30 '18 at 12:58
  • @שחרדגן no. `asm and ZX 1` and `PCGPE` where the only reference I used for learnig asm in general and PC games programing. – Spektre Jan 30 '18 at 13:00
  • Thank you very much, you have no idea how much you helped me! @Spektre – ShaharDagan14 Jan 30 '18 at 13:33

1 Answers1

1

What you want to do is "parallelize" your game code (without using threads). There are few options on how to do this:

  1. interleave the code

    This is the easiest way to implement. So you should have your game architecture like this:

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

    This architecture will allow the game to run all its task in "parallel". If your tasks are slower you can interleave the music a bit more

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

    if any task is really slow then you need to interleave the sound into it directly otherwise you would have choppy sound. Here is an example of this (without sound):

    And this is with sound (but not a game):

    You need to make your keyboard test non blocking. Taken from my No Signal demo it is done like this:

        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. play the sound using PIT as generator

    I did not use this but IIRC the PIT can be configured to play a constant frequency with the speaker. So instead of setting Speaker on/off you just set its frequency per each frame or so ... This will play in the background during which time the CPU can do other stuff...

  3. play the sound in background using PIT as timer

    For much better timing and playing the sound in the background parallel to your game code you can move the sound playing to the PIT ISR entirely which can operate at 1193180.0/16bit_divider Hz so set the PIT to target sound sampling frequency. Set the ISR for it and fetch/play single bit in it....

    If you use PWM and multiple of sampling frequency you can turn Speaker into DAC playing even PCM *.wav files.

    In this case you do not have the sound code interleaved in the game loop at all.

DO NOT FORGET TO SET PIT FREQUENCY BACK TO 18.2 Hz BEFORE EXIT because MS-DOS and games use it for timing. Many games can be speed-up by changing the PIT frequency alone. Also when you change PIT frequency and ISR it is a good idea to call the original ISR with 18.2Hz frequency from your new ISR.

For more info about PC MS-DOS and games see:

  • PCGPE 1.0
  • WPCGPE 1.0 this should be *.hlp format (you need Windows6.1-KB917607 patch for Win7+ as they stopped supporting it)

This is the best for starting with assembly I know of:

but it is in Czech for Z80 CPU and I do not know of any translations ....

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • Hi I have another question if you can help me I am currently reading the PCGPE 1.0 that you gave me is the best tutorial I ever seen i'm on the tutorial Asphixia's VGA Primer - Virtual Screens file but I cant find how to use virtual screens in assembly and not in Pascal do you have some example I can learn from on how to use virtual screens in assembly? – ShaharDagan14 Feb 01 '18 at 12:27
  • @שחרדגן took me a while to find the right page in windows help formated PCGPE (just single file instead of many) all the stuff is in assembly you just ignore the pascal headers and labels and use your own instead. I have not used this kind of access of VGA I always uses direct access to VRAM segment and remap only the pages instead of whole screens. I did not even use backbuffering or LFB at that time as the asm rendering was fast enough without flickering for me.... And I did even 3D engine in asm as school project game once (it was ~4 Kbyte *.com). – Spektre Feb 01 '18 at 14:37
  • @שחרדגן added link to the windows version (I found in a text file near my downloaded archive :)) – Spektre Feb 01 '18 at 14:44
  • Okay so I can use the move (mem[...]) that was written in assembly? and one more question if it's possible I'm building a mario game and I need that when the player move to the end of the screen the level will move with him do you have some idea how I can achieve that? @Spektre – ShaharDagan14 Feb 01 '18 at 15:19
  • @שחרדגן depends on the architecture of your game... if you take a look at my game in QA (What is the best way to move an object on the screen?) I linked it does exactly that the car is centered and map scrolls with movement ... It is just a matter of rendering the background with x and y offset. With tiles that means you render not from `(0,0)` corner tile but starts at some (x,y) instead usually taighted to player position. I did not see any `mem[]` in the PCGPE page. Anything between `asm` and `end;` is assembly code for TASM. – Spektre Feb 01 '18 at 19:23
  • @שחרדגן if your render is fast you can render whole map at once ... if not then you need to use scrolls which mean you copy/shift old frame by player movement and render only the missing stuff. – Spektre Feb 01 '18 at 19:27