Je travaille sur un jeu "simon" en montage. J'ai besoin de faire un bip à chaque fois qu'un bouton s'allume, les bips doivent être différents les uns des autres. merciAssembly 8086 - DOSBOX - Comment produire un bip sonore?
Répondre
Vous pouvez utiliser le speaker pour garder votre design simple.
Le haut-parleur vous permet de jouer des ondes carrées à différentes fréquences, it can actually be used to reproduce digital audio mais c'est plus impliqué.
Le haut-parleur est juste un électroaimant, quand le courant le traverse, il est tiré vers l'arrière sinon il reste dans sa position par défaut.
En déplaçant l'enceinte d'avant en arrière, il est possible de créer des ondes sonores.
Le haut-parleur peut être déplacé manuellement ou en utilisant le canal de » PIT 2.
Bit 0 de l'orifice 61h commande la source de haut-parleur (0 = manuel, 1 = PIT) et le bit 1 du même port est le bit "speaker enable" lors de l'utilisation du PIT (la "position" du locuteur quand il ne l'est pas).
Voici un schéma (de ce page) manque la partie manuelle de conduite:
Le PIT est contrôlé via le port 40h-43h, nous allons utiliser le mode 3 (Square générateur Wave) réglage chaque fois les deux octets du diviseur.
Le PIT a un oscillateur fonctionnant à environ 1.193180 MHz, le diviseur est utilisé pour contrôler la période de l'onde carrée.
Sans traiter les internes: à chaque coche de l'oscillateur PIT, le diviseur chargé est décrémenté. La période de l'onde carrée est égale au temps nécessaire au PIT pour décrémenter le diviseur jusqu'à zéro.
Produire un son consiste simplement à programmer le PIT avec le diviseur souhaité et à activer le haut-parleur.
Plus tard, nous devrons le désactiver.
Un moyen facile de faire cela est d'utiliser le int 1ch qui est appelé 18,2 fois par seconde. En enregistrant une durée dans une variable lors de la première lecture d'un son, en la décrémentant à chaque tick de l'int 1ch et en désactivant l'enceinte lorsque le compte atteint zéro, il est possible de contrôler la durée du bip. L'utilisation de int 1ch nécessite une fonction de configuration (beep_setup
) et une fonction de démontage (beep_teardown
).
BITS 16
ORG 100h
__start__:
;Setup
call beep_setup
;Sample beep of ~2sec
mov ax, 2000
mov bx, 36
call beep_play
;Wait for input
xor ax, ax
int 16h
;Tear down
call beep_teardown
mov ax, 4c00h
int 21h
;-------------------------------------------------
;
;Setup the beep ISR
;
beep_setup:
push es
push ax
xor ax, ax
mov es, ax
;Save the original ISR
mov ax, WORD [es: TIMER_INT * 4]
mov WORD [cs:original_timer_isr], ax
mov ax, WORD [es: TIMER_INT * 4 + 2]
mov WORD [cs:original_timer_isr + 2], ax
;Setup the new ISR
cli
mov ax, beep_isr
mov WORD [es: TIMER_INT * 4], ax
mov ax, cs
mov WORD [es: TIMER_INT * 4 + 2], ax
sti
pop ax
pop es
ret
;
;Tear down the beep ISR
;
beep_teardown:
push es
push ax
call beep_stop
xor ax, ax
mov es, ax
;Restore the old ISR
cli
mov ax, WORD [cs:original_timer_isr]
mov WORD [es: TIMER_INT * 4], ax
mov ax, WORD [cs:original_timer_isr + 2]
mov WORD [es: TIMER_INT * 4 + 2], ax
sti
pop ax
pop es
ret
;
;Beep ISR
;
beep_isr:
cmp BYTE [cs:sound_playing], 0
je _bi_end
cmp WORD [cs:sound_counter], 0
je _bi_stop
dec WORD [cs:sound_counter]
jmp _bi_end
_bi_stop:
call beep_stop
_bi_end:
;Chain
jmp FAR [cs:original_timer_isr]
;
;Stop beep
;
beep_stop:
push ax
;Stop the sound
in al, 61h
and al, 0fch ;Clear bit 0 (PIT to speaker) and bit 1 (Speaker enable)
out 61h, al
;Disable countdown
mov BYTE [cs:sound_playing], 0
pop ax
ret
;
;Beep
;
;AX = 1193180/frequency
;BX = duration in 18.2th of sec
beep_play:
push ax
push dx
mov dx, ax
mov al, 0b6h
out 43h, al
mov ax, dx
out 42h, al
mov al, ah
out 42h, al
;Set the countdown
mov WORD [cs:sound_counter], bx
;Start the sound
in al, 61h
or al, 3h ;Set bit 0 (PIT to speaker) and bit 1 (Speaker enable)
out 61h, al
;Start the countdown
mov BYTE [cs:sound_playing], 1
pop dx
pop ax
ret
;Keep these in the code segment
sound_playing db 0
sound_counter dw 0
original_timer_isr dd 0
TIMER_INT EQU 1ch
grâce à Sep Roland spéciaux pour la fixation d'une faille dans le code original!
Vous pouvez utiliser beep_play
pour émettre un bip, les unités utilisées sont l'unité «naturelle» de la configuration matérielle expliquée ci-dessus.
Si vos fréquences et durées sont fixes, ces unités simplifient le code sans frais.
Le bip s'arrête après la durée indiquée, vous pouvez utiliser beep_stop
pour l'arrêter avec force.
Jouer plusieurs sons à la fois c'est impossible (même les mélanger est impossible sans recourir aux techniques PWM).
L'appel du beep_play
alors qu'un autre bip est en cours aura pour effet d'arrêter le bip actuel et de démarrer le nouveau.
Une excellente réponse. +1 Mais la routine de service d'interruption * beep_isr * a un problème important! Vous ne pouvez pas simplement utiliser le registre 'AX' et ne pas le conserver. La solution est simple si vous avez écrit: 'cmp WORD [cs: sound_counter], 0' 'je _bi_stop'' dec WORD [cs: sound_counter] '. Pas besoin d'utiliser 'AX' du tout. –
Merci beaucoup @SepRoland! Je mets à jour la réponse avec des crédits :) –
double possible de [Lecture de fichiers .wav sur le périphérique Sound Blaster de DOSBox] (http://stackoverflow.com/questions/41359112/playing-wav-files-on-dosboxs-sound-blaster-device) –
Avez-vous consulté une référence d'interruption DOS? – Michael