我想知道在汇编中一次演奏超过1个音符的最佳方式是什么。如果可以的话,请添加一个程序来解释你的答案。谢谢
Orange,下一个代码是很久以前在EMU8086和Windows XP中制作的程序(当时运行)。现在我有了Windows 8 64位,它不再运行了。我会把代码给你,因为它可能会对你有所帮助。所有的名字和注释都是西班牙语,因为我是哥斯达黎加人,但汇编代码是通用的(谷歌翻译会帮你的):
.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
它的作用是向您显示要按下的键,以使音符发出声音。你可以在EMU8086中打开它并运行它,但由于Windows 8,扬声器中断的行为很奇怪。
Orange刚刚编辑了这个问题,现在他想同时播放笔记。我的代码不这么做,它一次只播放一个音符。为了同时演奏两个或多个音符,我们需要线程或进程以这种方式执行。
我不确定汇编程序是否能做到这一点,甚至不确定受中断控制的扬声器是否被允许这样做。这是因为被称为"可重入性"或类似的东西,它指的是当中断已经在执行时执行时引起的问题,通常程序在发生时会停止。