问题
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!
回答1:
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.
来源:https://stackoverflow.com/questions/29168974/how-to-play-chords-in-asm-8086