Skip to content

Instantly share code, notes, and snippets.

@dhy2000
Last active April 5, 2023 14:38

Revisions

  1. dhy2000 revised this gist Mar 23, 2023. 1 changed file with 8 additions and 8 deletions.
    16 changes: 8 additions & 8 deletions play.asm
    Original file line number Diff line number Diff line change
    @@ -21,19 +21,19 @@ F2 EQU 1715
    G2 EQU 1521

    ; para 1: sol sol la sol DO si
    PARA1: DW G1, G1, A1, G1, C2, B1
    PARA1 DW G1, G1, A1, G1, C2, B1
    ; para 2: sol sol la sol RE DO
    PARA2: DW G1, G1, A1, G1, D2, C2
    PARA2 DW G1, G1, A1, G1, D2, C2
    ; para 3: sol sol SOL ME DO si la
    PARA3: DW G1, G1, G2, E2, C2, B1, A1
    PARA3 DW G1, G1, G2, E2, C2, B1, A1
    ; para 4: FA FA MI DO RE DO
    PARA4: DW F2, F2, E2, C2, D2, C2
    PARA4 DW F2, F2, E2, C2, D2, C2

    ; total song with 4 paragraphs
    NUM_PARA: DW 4
    PARA_HEAD: DW PARA1, PARA2, PARA3, PARA4
    PARA_LEN: DW 6, 6, 7, 6
    DURATION: DW 10
    NUM_PARA DW 4
    PARA_HEAD DW PARA1, PARA2, PARA3, PARA4
    PARA_LEN DW 6, 6, 7, 6
    DURATION DW 10

    DATA ENDS

  2. dhy2000 revised this gist Mar 22, 2023. 1 changed file with 0 additions and 16 deletions.
    16 changes: 0 additions & 16 deletions play.asm
    Original file line number Diff line number Diff line change
    @@ -106,22 +106,6 @@ MAIN PROC
    MOV AX, DATA
    MOV DS, AX

    ; play note test
    MOV AX, C2
    PUSH AX
    MOV AX, 10
    PUSH AX
    CALL PLAY
    MOV AX, 10
    CALL DELAY
    MOV AX, D2
    PUSH AX
    MOV AX, 10
    PUSH AX
    CALL PLAY
    MOV AX, 10
    CALL DELAY

    ; outer loop: para
    XOR CX, CX ; set CX=0
    LP_PARA:
  3. dhy2000 created this gist Mar 22, 2023.
    168 changes: 168 additions & 0 deletions play.asm
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,168 @@
    ; Happy Birthday in MASM
    STACK SEGMENT PARA STACK
    STACK_AREA DW 100h DUP(?)
    STACK_TOP EQU $-STACK_AREA
    STACK ENDS

    DATA SEGMENT PARA
    ; message is a string
    MESSAGE DB 'Happy birthday, '
    DB 'chang' ; change it to your name
    DB '$' ; '$' is the terminator for dos print

    ; frequency of music notes
    G1 EQU 3043
    A1 EQU 2711
    B1 EQU 2415
    C2 EQU 2280
    D2 EQU 2031
    E2 EQU 1809
    F2 EQU 1715
    G2 EQU 1521

    ; para 1: sol sol la sol DO si
    PARA1: DW G1, G1, A1, G1, C2, B1
    ; para 2: sol sol la sol RE DO
    PARA2: DW G1, G1, A1, G1, D2, C2
    ; para 3: sol sol SOL ME DO si la
    PARA3: DW G1, G1, G2, E2, C2, B1, A1
    ; para 4: FA FA MI DO RE DO
    PARA4: DW F2, F2, E2, C2, D2, C2

    ; total song with 4 paragraphs
    NUM_PARA: DW 4
    PARA_HEAD: DW PARA1, PARA2, PARA3, PARA4
    PARA_LEN: DW 6, 6, 7, 6
    DURATION: DW 10

    DATA ENDS

    CODE SEGMENT
    ASSUME CS:CODE, DS:DATA, SS:STACK

    ; TICK: wait until the timer ticks
    TICK PROC
    PUSH AX
    PUSH ES
    MOV AX, 40h
    MOV ES, AX
    MOV AX, ES:[6Ch] ; read hardware clock ticks from 0040h:6Ch
    TICK_WAIT:
    CMP AX, ES:[6Ch] ; until clock ticks increase
    JE TICK_WAIT
    POP ES
    POP AX
    RET
    TICK ENDP

    ; DELAY AX: delay for at least AX ticks
    DELAY PROC
    PUSH AX
    PUSH CX
    MOV CX, AX
    DELAY_COUNT:
    CALL TICK
    LOOP DELAY_COUNT
    POP CX
    POP AX
    RET
    DELAY ENDP

    ; PLAY(freq, dur): play note of a frequency and lasts a duration
    PLAY PROC
    PUSH BP
    MOV BP, SP ; use BP to address argument stack
    ADD BP, 4 ; skip BP and ra
    PUSH AX
    ; setup speaker: send 0B6h to port 43h
    MOV AL, 0B6h
    OUT 43h, AL
    ; setup frequency: send to port 42h
    MOV AX, [BP+02h] ; load frequency
    OUT 42h, AL ; send low byte
    MOV AL, AH
    OUT 42h, AL ; send high byte
    ; start beep: set bit 1 and 0 to high of port 61h
    IN AL, 61h
    OR AL, 03h
    OUT 61h, AL
    ; delay for duration
    MOV AX, [BP+00h] ; load duration
    CALL DELAY
    ; stop beep: set bit 1 and 0 to low of port 61h
    IN AL, 61h
    AND AL, 0FCh
    OUT 61h, AL
    POP AX
    POP BP
    RET 4
    PLAY ENDP

    MAIN PROC
    ; setup stack and data segment register
    MOV AX, STACK
    MOV SS, AX
    MOV SP, STACK_TOP
    MOV AX, DATA
    MOV DS, AX

    ; play note test
    MOV AX, C2
    PUSH AX
    MOV AX, 10
    PUSH AX
    CALL PLAY
    MOV AX, 10
    CALL DELAY
    MOV AX, D2
    PUSH AX
    MOV AX, 10
    PUSH AX
    CALL PLAY
    MOV AX, 10
    CALL DELAY

    ; outer loop: para
    XOR CX, CX ; set CX=0
    LP_PARA:
    MOV BX, CX
    SHL BX, 1 ; offset for para head
    ; inner loop: note
    PUSH CX
    XOR CX, CX
    LP_NOTE:
    MOV SI, CX
    SHL SI, 1 ; offset inside para
    ; load freq and dur of the note
    PUSH BX
    MOV BX, PARA_HEAD[BX]
    MOV AX, [BX+SI] ; AX=para_i[j]
    POP BX
    PUSH AX ; freq
    MOV AX, WORD PTR DURATION
    PUSH AX ; dur
    CALL PLAY
    MOV AX, PARA_LEN[BX]
    INC CX
    CMP CX, AX
    JB LP_NOTE

    POP CX
    ; break between paras
    MOV AX, WORD PTR DURATION
    CALL DELAY
    ; next para
    INC CX
    CMP CX, WORD PTR NUM_PARA
    JB LP_PARA

    ; print message
    MOV AH, 9
    LEA DX, MESSAGE
    INT 21h
    ; return to dos
    MOV AX, 4C00h
    INT 21h
    MAIN ENDP
    CODE ENDS
    END MAIN