Я работаю над игрой «Саймон» в сборке. Мне нужно издавать звуковой сигнал всякий раз, когда включается кнопка, звуковые сигналы также должны отличаться друг от друга. спасибо
Сборка 8086 - DOSBOX - Как сделать звуковой сигнал?
Ответы (1)
Вы можете использовать динамик, чтобы упростить дизайн.
Динамик позволяет воспроизводить прямоугольные волны с разной частотой. частоты, на самом деле его можно использовать для воспроизводить цифровой звук, но это более сложно.
Динамик — это просто электромагнит, когда через него проходит ток, он оттягивается назад, в противном случае он остается в исходном положении.
Перемещая динамик вперед и назад, можно создавать звуковые волны.
Динамик можно перемещать вручную или с помощью канала 2 PIT.
Бит 0 порта 61h управляет источником динамика (0 = вручную, 1 = PIT), а бит 1 того же порта является битом «включения динамика» при использовании PIT («положением» динамика, когда нет).
Вот схема (с этой страницы), отсутствующая часть ручного управления:
PIT управляется через порт 40h-43h, мы будем использовать режим 3 (генератор прямоугольных импульсов), устанавливая каждый раз оба байта делителя.
Генератор PIT работает на частоте около 1,193180 МГц, делитель используется для управления период прямоугольной волны.
Не касаясь внутренностей: на каждом тике осциллятора PIT загруженный делитель уменьшается. Период прямоугольной волны равен времени, необходимому PIT для уменьшения делителя до нуля.
Создание звука — это просто вопрос программирования PIT с нужным делителем и включения динамика.
Через некоторое время нам нужно отключить его.
Самый простой способ сделать это — использовать int 1ch, который вызывается 18,2 раза в секунду.
Сохраняя продолжительность в переменной при первом воспроизведении звука, уменьшая ее на каждом такте int 1ch и отключая динамик, когда счетчик достигает нуля, можно контролировать продолжительность звукового сигнала.
Для использования int 1ch требуется функция настройки (beep_setup
) и функция демонтажа (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
Особая благодарность сепу Роланду за исправление ошибки в исходном коде!
Вы можете использовать beep_play
для воспроизведения звукового сигнала, используемые единицы являются "естественными" единицами аппаратной конфигурации, описанной выше.
Если ваши частоты и продолжительность фиксированы, эти единицы упрощают код бесплатно.
Звуковой сигнал прекращается по истечении заданного времени, вы можете использовать beep_stop
, чтобы остановить его принудительно.
Воспроизведение нескольких звуков одновременно невозможно (даже их микширование невозможно без использования методов PWM).
Вызов beep_play
во время воспроизведения другого сигнала приведет к остановке текущего сигнала и запуску нового.
AX
и не сохранить его. Решение простое, если вы написали: cmp WORD [cs:sound_counter], 0
je _bi_stop
dec WORD [cs:sound_counter]
. Нет необходимости использовать AX
вообще.
- person Sep Roland; 21.05.2017