audioassemblytimerx86-16sound-synthesis

How to play chords in ASM 8086?


I want to know what is the best way to play more then 1 note at the time in assembly. If you can, please add a procedure that explain your answer. Thanks!


Solution

  • Orange, next code is a program a made long time ago in EMU8086 and Windows XP (it ran at that time). Now I have Windows 8 64 bits and it doesn't run anymore. I will give you the code because it may help you. All the names and comments are in spanish because I am costarrican, but the assembler code is universal (google translator will give you a hand):

    .model small
    .stack 100h
    .data
    
    ;----------------------------------------------------------------------------
    
    MENSAJEPLAY    DB '                       PROYECTO ® PIANO ¯',13,10
                   DB 13,10
                   DB '            LAS TECLAS DE LAS NOTAS VAN EN EL ORDEN SIGUIENTE:',13,10
                   DB 13,10
                   DB '                        2  3     5  6  7' ,13,10
                   DB '                      q  w  e  r  t  y  u',13,10,13,10
                   DB 13,10
                   DB '                        s  d     g  h  j' ,13,10
                   DB '                      z  x  c  v  b  n  m',13,10,13,10
                   DB '                       PARA TERMINAR PRESIONE ESC','$'
    
    ;----------------------------------------------------------------------------
    
    .code
    
    TONO MACRO NUMERO               ;Esta macro recibe el tono
            MOV     BX,NUMERO       ;y manda a llamar a los procedimientos
            CALL    BOCINA
    ENDM
    
    ;----------------------------------------------------------------------------
    
    CLRSCR PROC
    ;Limpia la pantalla
            MOV     AH,6
            XOR     AL,AL
            XOR     CX,CX
            MOV     DX,184FH
            MOV     BH,13
            INT     10H
            RET
    ENDP
    
    ;----------------------------------------------------------------------------
    
    BocinaOn  PROC                  ;Activa la bocina
            IN      AL, 61h
            OR      AL, 11B
            OUT     61h, AL
            RET
    BocinaOn  ENDP
    
    ;----------------------------------------------------------------------------
    
    BocinaOff  PROC                 ;Desactiva la bocina
            IN      AL, 61h
            AND     AL, 11111100b
            OUT     61h, AL
            RET
    BocinaOff  ENDP
    
    ;----------------------------------------------------------------------------
    
    Ajustar  PROC                  ;Ajusta la bocina con la frecuencia dada
            PUSH    BP
            MOV     BP, SP
            MOV     DX, 18      
            MOV     AX, 13353   
            MOV     BX, [BP + 4]
            DIV     BX
            MOV     BX, AX  
            MOV     AL, 0B6h
            OUT     43h, AL
    ;ENVIAR AL PUERTO LA FRECUENCIA EN DOS BYTES POR SEPARADO.
            MOV     AX, BX
            OUT     42h, AL ;ENVIA PRIMER BYTE. (PUERTO PARALELO = 378H)
            MOV     AL, AH
            OUT     42h, AL ;ENVIA SEGUNDO BYTE. (PUERTO SERIAL = 3F8H)
            POP     BP
            RET
    Ajustar  ENDP
    
    ;----------------------------------------------------------------------------
    
    Suena proc                      ;Activa la bocina y coloca el nombre de
            CALL bocinaON           ;la tecla.
            MOV     AX,40H
            MOV     ES,AX
            MOV     DX,ES:[006EH]
            MOV     AX,ES:[006CH]
            ADD     AX,7
            ADC     DX,0            ;Se le suma 7 unidades a ese valor
    CLIC:
            CMP     DX,ES:[006EH]   ;Y se compara hasta que sean iguales
            JB      FINI            ;Pasando por un ciclo, cuando llegen
            JA      CLIC            ;a ser iguales se sale del ciclo y
            CMP     AX,ES:[006CH]
            JA      CLIC
    FINI:
            CALL    BocinaOff       ;Se desconecta la bocina y regresa.
            RET
    Suena endp
    
    ;----------------------------------------------------------------------------
    
    Bocina proc                     ;Este procedimiento guarda AX y BX en
            PUSH    BX              ;la pila para no perder su valor, con
            MOV     AX, BX          ;esto llama a ajusta y a suena
            PUSH    AX
            CALL    Ajustar         ;Pone la frecuencia en el puerto.
            POP     AX
            POP     BX
            CALL    SUENA           ;Activa el speaker y lo desactiva.
            ret
    Bocina endp
    
    ;----------------------------------------------------------------------------
    ;CONVERTIR A MINUSCULA SI ERA MAYUSCULA
    
    MINUSCULA PROC
            CMP AL, 65    ;'A'
            JB  CONTINUAR ;SI LA TECLA ES MENOR QUE LA 'A' NO HACE NADA
            CMP AL, 90    ;'Z'
            JA  CONTINUAR ;SI LA TECLA ES MAYOR QUE LA 'Z' NO HACE NADA
            ADD AL, 32    ;Convierte may£scula en min£scula.
         CONTINUAR:
            RET
    MINUSCULA ENDP
    
    ;----------------------------------------------------------------------------
    ;CAPTURA LA TECLA CON LA NOTA QUE EL USUARIO DESEA.
    
    TECLA PROC
            MOV     AH,8            ;Si la hay, obtiene la nota
            INT     21H
            CALL    MINUSCULA
            RET
    TECLA ENDP
    ;----------------------------------------------------------------------------
    ;Cicla el programa hasta que el usuario presione la tecla ESC.
    ;El procedimiento reacciona a las teclas indicadas en el segmento de datos.
    ;Cualquier otra tecla es ignorada.
    ;La tecla presionada es convertida a min£scula, ya que la tabla ASCII
    ;trata distinto unas de otras.
    ;Despu‚s de que cada tecla es presionada, el ciclo vuelve al inicio y
    ;se repite.
    ;Si la tecla presionada corresponde a una nota musical, el c¢digo
    ;correspondiente es enviado al parlante.
    
    SPEAKER PROC
    COMIENZA:
            CALL    TECLA
            CMP     AL,'q'   ;DO alto
            JNE     S1       ;SI NO ES LA TECLA ESPERADA, SALTA PARA VERIFICAR LA SIGUIENTE.
            TONO    523      ;SI ES LA TECLA ESPERADA, GENERA EL SONIDO CORRESPONDIENTE
            JMP     COMIENZA ;DESPUES DEL SONIDO REINICIA PARA ESPERAR OTRO SONIDO.
    S1:     CMP     AL,'w'   ;RE alto
            JNE     S2
            TONO    587
            JMP     COMIENZA
    S2:     CMP     AL,'e'   ;MI alto
            JNE     S3
            TONO    659
            JMP     COMIENZA
    S3:     CMP     AL,'r'   ;FA alto
            JNE     S4
            TONO    698
            JMP     COMIENZA
    S4:     CMP     AL,'t'   ;SOL alto
            JNE     S5
            TONO    784
            JMP     COMIENZA
    S5:     CMP     AL,'y'   ;LA alto
            JNE     S6
            TONO    880
            JMP     COMIENZA
    S6:     CMP     AL,'u'   ;SI alto
            JNE     S8
            TONO    988
            JMP     NOSALTO1
    SALTO1:
       JMP COMIENZA
    NOSALTO1:
            JMP     COMIENZA
    S8:     CMP     AL,'2'   ;DO# alto
            JNE     S9
            TONO    554
            JMP     COMIENZA
    S9:     CMP     AL,'3'   ;RE# alto
            JNE     S10
            TONO    622
            JMP     COMIENZA
    S10:    CMP     AL,'5'   ;FA# alto
            JNE     S11
            TONO    740
            JMP     COMIENZA
    S11:    CMP     AL,'6'   ;SOL# alto
            JNE     S12
            TONO    830
            JMP     COMIENZA
    S12:    CMP     AL,'7'   ;SIb alto
            JNE     S13
            TONO    923
            JMP     COMIENZA
    S13:    CMP     AL,'z'   ;DO bajo
            JNE     S14
            TONO    261
            JMP     COMIENZA
    S14:    CMP     AL,'x'   ;RE bajo
            JNE     S15
            TONO    293
            JMP     COMIENZA
    S15:    CMP     AL,'c'   ;MI bajo
            JNE     S16
            TONO    329
            JMP     NOSALTO2
    SALTO2:
       JMP SALTO1
    NOSALTO2:
            JMP     COMIENZA
    S16:    CMP     AL,'v'   ;FA bajo
            JNE     S17
            TONO    349
            JMP     COMIENZA
    S17:    CMP     AL,'b'   ;SOL bajo
            JNE     S18
            TONO    392
            JMP     COMIENZA
    S18:    CMP     AL,'n'   ;LA bajo
            JNE     S19
            TONO    466
            JMP     COMIENZA
    S19:    CMP     AL,'m'   ;SI bajo
            JNE     S20
            TONO    498
            JMP     COMIENZA
    S20:    CMP     AL,'s'   ;DO# bajo
            JNE     S21
            TONO    277
            JMP     COMIENZA
    S21:    CMP     AL,'d'   ;RE# bajo
            JNE     S22
            TONO    311
            JMP     COMIENZA
    S22:    CMP     AL,'g'   ;FA# bajo
            JNE     S23
            TONO    370
            JMP     COMIENZA
    S23:    CMP     AL,'h'   ;SOL# bajo
            JNE     S24
            TONO    415
            JMP     COMIENZA
    S24:    CMP     AL,'j'   ;SIb bajo
            JNE     S25
            TONO    515
            JMP     COMIENZA
    S25:    CMP     AL,27 ;27 = tecla ESC (terminar).
            JNE     SALTO2
            RET
    SPEAKER ENDP
    
    ;----------------------------------------------------------------------------
    
    MENSAJE PROC
            MOV     AH,9
            LEA     DX,MENSAJEPLAY
            INT     21H
            RET
    MENSAJE ENDP
    
    ;----------------------------------------------------------------------------
    
    EMPIEZA:
            MOV     AX, @data         ;se mandan llamar todos los
            MOV     DS, AX            ;procedimientos
            CALL    CLRSCR            ;Limpiar pantalla.
            CALL    MENSAJE           ;Despliega la explicaci¢n del programa.
            CALL    SPEAKER           ;Sonidos.
            MOV     AX, 4C00H
            INT     21H
    
    ;----------------------------------------------------------------------------
    
    END EMPIEZA
    

    What it does is to show you a the keys to press in order to make the notes to sound. You can open it in EMU8086 and run it, but the speaker interrupts behave weird because of Windows 8.

    Orange just edited the question, now he wants simultaneous notes playing. Well, my code doesn't do that, it plays one note at a time. For two or more notes to play at the same time we would requiere threads or processes executing that way.

    I am not sure assembler can do that, not even sure if the speaker, controlled by an interruption, is allowed to do it. This is because something called "reentrancy", or something like that, it refers to the problem caused when an interrupt is executed when it is already executing, usually the program halts when it happens.