Search code examples
assemblydelaysleepx86-16speaker

Assembly speaker and wait interrupt endless sleep


I am working on an assembly program (8086) that plays music on the PC speaker.

Everything works fine but I've got one problem. Program falls in endless sleep (with speaker on) on 78th note, no matter what note it is.

I am using 86h function of 15 interrupt.

So why does that endless sleep occur, and how to fix that?

Here's the code (with Mortal Kombat Theme):

;constants
TB equ 38636; 1.19MHz/30Hz
TC equ 34546; 1.19MHz/33Hz
TD equ 30811; 1.19MHz/37Hz
TE equ 27805; 1.19MHz/41Hz
TF equ 25909; 1.19MHz/44Hz
TG equ 23265; 1.19MHz/49Hz
TA equ 20727; 1.19MHz/55Hz
TH equ 18387; 1.19MHz/62Hz
TP equ 1;pause
;K end of melody
strophe1n equ 'ACADAEDCCECGCECGGHGCGDCFFAFCFCH'
strophe1o equ '3434344444444443333434433334343'
strophe1t equ '2222222222222222222222222222222'
strophe2n equ 'APAPAPAPGCAPAPAPAPGEAPAPAPAPGCAPAPAPAPAPAPA'
strophe2o equ '4040404045404040404440404040454040404040404'
strophe2t equ '2424242422242424242224242424222424284844484'
strophe3n equ 'AEACABACABGAEACABACABGAEACABACABGAEACGPGGPGAAPAA'
strophe3o equ '454545454544545454545445454545454454540440444044'
strophe3t equ '424242424424242424244242424242442424248488448848'

Progr           segment
                assume  cs:Progr, ds:data, ss:stacky
interval:; waits DX:CX microseconds
        mov ah,86h;
        int 15h
        ret
        ;here come notes every note set up its time and sleep
note:;0,5 sec
        mov cx,7;
        mov dx,41248;
        call interval
        ret

halfnote:;0,25sec
        mov cx,3;
        mov dx,53280;
        call interval
        ret

quarternote:;0,125sec
        mov cx,1;
        mov dx,58982;
        call interval
        ret

eighthnote:
        mov cx,0;
        mov dx,62455;
        call interval
        ret

turnon:;sets tone and turn on speaker
        ;setting up tone
        mov ax,tone
        mov dx,42h
        out dx,al
        mov al,ah
        out dx,al

        ;turning speaker on
        mov dx,61h
        in al,dx;
        or al,00000011B;
        out dx,al;
        ret

turnoff:;turning speaker off
        mov dx,61h
        in al,dx;
        and al,11111100B;
        out dx,al;
        ret

play:
;simple switch for times
        call turnon
        cmp time,1
        je whole
        cmp time,2
        je half
        cmp time,4
        je quarter
        cmp time,8
        je eighth

        whole: call note;sleep for note time (while speaker is on) and then shuts up the speaker
        jmp endplay
        half: call halfnote
        jmp endplay
        quarter: call quarternote
        jmp endplay
        eighth: call eighthnote
        jmp endplay
        endplay:
        call turnoff; turning speaker off
        ret

exit:
        mov ah,4ch
        mov al,00h
        int 21h;
;START--------------------------------------------------------------------
start: mov ax,data ;some start up
mov ds,ax
mov ax,stacky
mov ss,ax
mov sp,offset peak

mov si,0
melody:
        lea bx,notes
        mov dl,ds:[bx+si];dl = next note
        cmp dl,'K'; if K then melody ends
        je exit
        ;simple switch for notes
        cmp dl,'A'
        je A
        cmp dl,'B'
        je B
        cmp dl,'C'
        je C
        cmp dl,'D'
        je D
        cmp dl,'E'
        je E
        cmp dl,'F'
        je F
        cmp dl,'G'
        je G
        cmp dl,'H'
        je H
        mov tone,TP

        readoctave:
        lea bx,octaves;reads next octave from array
        mov cl,ds:[bx+si]
        sub cl,'0'

        shr tone,cl; double the tone octave times (tone = tone *2^octave)

        lea bx,times;read next time from array
        mov cl,ds:[bx+si]
        sub cl,'0'
        mov time,cl

        call play;
        inc si;;next index
jmp melody;play next note
;notes asignment
A: mov tone,TA
jmp readoctave
B: mov tone,TB
jmp readoctave
C: mov tone,TC
jmp readoctave
D: mov tone,TD
jmp readoctave
E: mov tone,TE
jmp readoctave
F: mov tone,TF
jmp readoctave
G: mov tone,TG
jmp readoctave
H: mov tone,TH
jmp readoctave


Progr           ends

data            segment

notes db strophe1n,strophe2n,strophe3n,'K';notes k means end of melody
octaves db strophe1o,strophe2o,strophe3o,'0';octaves, tone =(tone = frequency of note *2^octave)
times db strophe1t,strophe2t,strophe3t,'0';just times to play each note
tone dw 0
time db 0

data            ends

stacky          segment
                dw    100h dup(0)
peak          Label word
stacky          ends

end start

I know that the code is kind of big but I don't know where's the issue.

@EDIT Maybe array size is too big but i dont think so @EDIT2 Program fails on 78th note, no matter what note it is.


Solution

  • It turned out that the

    interval:
            mov ah,86h;
            int 15h
            ret
    

    works wrong beacause int 15h 86h function somehow fails,

    so I wrote my own procedure

    interval:
            mov ah, 0
            int 1Ah ; actual time
            mov bx,dx
            delay:
                    mov ah, 0
                    int 1Ah
                    sub dx,bx
                    cmp di,dx
            ja delay
            ret
    

    also notes define their time in other way(now in di register)e.g.:

    note:;0,5 sec
            mov  di, 8
            call interval
            ret
    halfnote:;0,25 sec
            mov  di, 4
            call interval
            ret