Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.149.230.44] |
|
Сообщ.
#1
,
|
|
|
Воспроизведение звука из системного динамика (PC Speaker'а) Для того чтобы заставить встроенный системный динамик издать какой-либо сигнал, необходимо задействовать две микросхемы: Системный таймер представляет собой генератор импульсов, работающий с частотой 1193181 Гц (~ 1.19 МГц). Он подаёт импульсы на три канала: канал 0 (генерирующий прерывание 8, т.е. IRQ0), канал 1 (предназначенный для регенерации памяти) и канал 2 (связанный с системным динамиком). Принцип работы всех каналов одинаковый. Каждый из них имеет несколько регистров: регистр управляющего слова (CWR, 8 бит), регистр состояния счётчика, регистр-счётчик (Counting Element (CE), 16 бит), регистр, хранящий значение коэффициента пересчёта (CR, 16 бит) и регистр-защёлку (OL, 16 бит), в который периодически передаётся значение регистра-счётчика. При каждом поступлении импульса от таймера происходит декремент (уменьшение на единицу) значения регистра-счётчика. В режиме работы 2 и 3 (см. ниже) при достижении нулевого значения в регистр-счётчик загружается значение коэффициента пересчёта, которое может быть установлено при помощи записи в соответствующий порт ввода-вывода (40h для канала 0, 41h для канала 1 и 42h для канала 2) и весь процесс повторяется заново. Т.о, чем меньше коэффициент пересчёта, тем короче цикл счёта (и длится он CR/1193181 секунды, т.е. повторяется с частотой 1193181/CR Гц). Каждый канал имеет шесть режимов работы, но нам больше всего подходит режим 3 (генератор меандра), т.к. именно в этом режиме положительный и отрицательный выходной сигнал занимают по половине периода счёта1. На вход звукогенератора поступает логическое "И" двух сигналов: выхода второго канала таймера и содержимого бита 1 порта PB ППИ (порт 61h). Счёт же второго канала разрешается только в том случае, если установлен бит 0 порта PB ППИ. Т.о, всё, что нам необходимо сделать - это инициализировать таймер и установить биты 0 и 1 порта PB ППИ. Для инициализации таймера нужно записать некоторое значение в регистр управляющего слова (доступ к которому осуществляется посредством записи в порт 43h), а затем поочерёдно младший и старший байты коэффициента пересчёта, т.е. значения (1193181/частота) в порт ввода-вывода канала 2 (порт 42h). Регистр управляющего слова имеет следующую структуру: Т.е. в нашем случае необходимо записать значение 10110110b (0B6h). Для отключения звука достаточно сбросить биты 0 и 1 порта PB ППИ. А вот, собственно, и сам код (SOUND.INC): ; Подключка для генерации звука ; Процедура Sound: включить звук ; Вход: AX = частота звука (Гц) Sound proc mov dx,12h cmp ax,dx ; Частота <= 18 Гц ? jbe @@Exit ; Да, на выход, чтобы избежать переполнения xchg cx,ax ; Сохраняем частоту в СX mov al,10110110b ; Упр.сл.таймера: канал 2, режим 3, дв.слово out 43h,al ; Выводим в регистр режима mov ax,34DDh ; DX:AX = 1193181 div cx ; AX = (DX:AX) / СX out 42h,al ; Записываем младший байт счетчика mov al,ah out 42h,al ; Записываем старший байт счетчика in al,61h ; Порт PB or al,11b ; Устанавливаем биты 0-1 out 61h,al ; Записываем обратно в PB @@Exit: ret ; Выходим из процедуры Sound endp ; Процедура NoSound: отключить звук NoSound proc in al,61h ; Порт PB and al,not 11b ; Сбрасываем биты 0-1 out 61h,al ; Записываем обратно в PB ret ; Выходим из процедуры NoSound endp Теперь я хочу рассказать немного о нотах. Как известно, в природе существует 12 нот (7 основных и 5 с производными названиями), также известно, что изменение высоты на октаву - это изменение частоты в два раза, а частота ноты "ля" первой октавы = 440 Гц. Отсюда получаем, что изменение высоты на полутон - это изменение в корень 12-й степени из 2 раз (~ 1.059463). Вычисляем частоту ноты "до" самой низкой октавы фортепиано (субконтроктавы) и получаем ~ 16.351598 Гц. Таким образом, вычисление частоты ноты сводится к простейшей процедуре: P.S. Кстати, Вы не забыли, что от перестановки мест множителей произведение не меняется? Для вычислений можно, конечно, привлечь математический сопроцессор, но я нашёл более, как мне кажется, короткий и быстрый путь (NOTEFREQ.INC): ; Подключка для получения частоты ноты ; Процедура GetNoteFreq: получение частоты ноты ; Вход: AH = номер октавы, AL = номер ноты ; Выход: AX = частота (Гц) ; Октавы: 0-субконтроктава, 1-контроктава, 2-большая, 3-малая, 4-первая, 5-вторая... 9-шестая ; Ноты: 0-до, 1-до#, 2-ре, 3-ре#, 4-ми, 5-фа, 6-фа#, 7-соль, 8-соль#, 9-ля, 10-ля#, 11-си GetNoteFreq proc xchg cx,ax cmp cl,11 jbe @@OkNote mov cl,11 @@OkNote: mov ax,7 mov dx,0B78Ah+23 mov bx,61858 @@1: xchg dx,ax div bx push ax div bx xchg ax,dx pop ax dec cl jns @@1 cmp ch,9 jbe @@2 mov ch,9 @@2: shl dx,1 rcl ax,1 dec ch jns @@2 shl dx,1 adc ax,0 ret GetNoteFreq endp |