From vadim@gate.dialnet.msk.su Tue Apr 20 00:40:12 1993
Newsgroups: relcom.fido.ru.hacker
From: Vadim Madgazin <vadim@gate.dialnet.msk.su>
Message-Id: <2.5085.3.2.3594899d@gate.dialnet.msk.su>
Path: relay1!csoft!kiae!bitcom!dialnet!dialnet.msk.su!echogate!echogate
Subject: PC sound, part 1
Sender: uu2@gate.dialnet.msk.su
Date: Sat, 17 Apr 1993 20:36:00 +0300
Organization: NetDialogue (Gid:gate.dialnet.msk.su)
X-Gate: UU2 1.13b
Status: RO

Hello All!
По (многочисленным) просьбам и в связи с некоторыми
изменениями привожу здесь исправленные и дополненные
версии предыдущих 4-х частей, а также 5-ю часть, пока
неполную.
Если заметите какие-то неточности - прошу сапчить :)
---

    Improvement sound quality of background process on IBM PC.

    Copyright 1992, 1993. All rights reserved.
    Vadim R. Madgazin,  Tashkent,  Uzbekistan.
    vadim@gate.dialnet.msk.su
    2:5085/3.2@fidonet

    Улучшение качества звука фонового процесса на IBM PC.

    Если специально не оговорено иное, то ниже везде под PC будут
    подразумеваться IBM PC XT/AT - compatible компьютеры.

                         Абстракт.

    В работе рассмотрены причины ухудшения качества фонового звука PC,
 (например для случая звукового сопровождения анимационных роликов) и
 предложены программные методы уменьшения его искажений с применением
 достаточно простой звуковой аппаратуры, начиная со встроенного спикера
 PC. Эти методы состоят: в постоянном определении реального времени для
 отбрасывания искаженных участков звука, в использовании прерываний
 последовательного порта вместо прерываний таймера для повышения
 устойчивости системы и программной совместимости, в использовании
 специфических режимов работы таймера для вывода звука на спикер при
 помощи преобразования частоты в напряжение вместо широтно-импульсной
 модуляции. Описан алгоритм работы резидентного драйвера звукового
 выхода PC, методы малобитного преобразования звука и др.
    Изложенные результаты исследований и идеи могут представлять
 практическую ценность в области создания игрового, демонстрационного,
 мультимедиа программного обеспечения реального времени, расчитанного
 на широкую эксплуатацию на IBM PC любых моделей и программных платформ,
 даже в стандартной комплектации, без использования дополнительной
 аппаратуры для вывода звука.

                     Благодарности.

    Выражаю свою искреннюю признательность за отдельные замечания и
 дополнения по настоящему тексту, сделанные по сетевой переписке -
 Андрею Заболотному (2:469/37.1).

                     Содержание:

                       Глава 1.
    1.1.   Аппаратура и методы вывода звука на PC.
    1.2.   Искажения звука различными процессами PC.
    1.3.   Методы устранения и маскировки искажений.
    1.3.1. Использование меток реального времени.
    1.3.2. Использование нестандартных прерываний.
    1.3.3. Таймер и методы вывода звука на спикер PC.
    1.3.4. Комбинации нестандартных программных методов.
    1.3.5. Изменение аппаратной схемы возбуждения спикера.
    1.4.   Заключительные замечания.
                     Приложение.
    1.П.1. Список терминов, сокращений и обозначений.
    1.П.2. Программирование таймера и логика спикера PC.
    1.П.3. Методы малобитного преобразования звука.
                       Глава 2.
    2.1.   Резидентный драйвер звукового выхода PC.
    2.2.   Пример использования драйвера.
    2.3.   Заключительные замечания.

                        -=*=-

                       Глава 1.

    1.1.   Аппаратура и методы вывода звука на PC.

    Звуком обычно считаются не слишком маломощные флуктуации давления
 воздуха в спектре слышимых человеком звуковых частот (ЗЧ). Hа языке
 формул произвольный звук S является непрерывной функцией времени T
 ограниченного спектра : S=S(T).
    Общеизвестным источником звука является громкоговоритель, на
 который обычно подается переменное напряжение от усилителя мощности
 с достаточно низким выходным сопротивлением. Чтобы услышать звук от
 PC требуется таким образом создать напряжение в ЗЧ спектре либо на
 клеммах встроенного громкоговорителя (PC спикера), либо на выходе
 какого-то добавочного устройства (девайса). Единственный "фирменный"
 источник ЗЧ напряжения, подаваемого на спикер PC - это 2-й
 канал таймера, задуманный первоначально для генерации простого
 прямоугольного звукового сигнала скважностью 2. Этот набор частот
 недостаточен для передачи звука произвольного содержания. Хотя
 существуют специальные платы расширения, содержащие в себе даже
 [почти-] профессиональные синтезаторы звука, многих программистов
 интересует возможность получения достаточно качественного звука при
 помощи более простой аппаратуры или каких-нибудь программных методов.
 Так как PC - это дискретное устройство ограниченного быстродействия,
 то эта аппаратура и методы состоят в общеизвестной временно'й
 и амплитудной дискретизации напряжения непрерывного сигнала и
 использовании выходного цифро-аналогового преобразователя (ЦАПа).
 Если вас интересует теория данного вопроса, обратитесь к учебнику по
 радиоэлектронике с описанием теоремы отсчетов Котельникова. Здесь же
 я только отмечу, что для качественного вывода звука в полосе частот
 f необходимо иметь частоту дискретизации Fd>=2*f. Что касается
 разрядности цифрового выхода, то для нормального понимания речи
 диктора часто достаточно иметь ее в 1 бит (при f=3 кГц), однако для
 высококачественного звука может потребоваться разрядность в 16 и даже
 в 24 бита (при Fd=40...60 кГц). Обычная разрядность синтезаторов и
 оркестраторов среднего качества - 12 бит. Практика показывает,
 что можно добиться иногда достаточно приемлемого (для "рядового"
 пользователя PC) качества звука на 8...4 битном ЦАПе.
    Математически дискретизацию звука можно представить заменой
 непрерывной функции времени S(T) на дискретные отсчеты S(T)->Si(ti),
 где i=0,1,2..., ti=(1/Fd)*i, Si примерно равно S(i/Fd) с точностью
 ЦАПа. Таким образом, чтобы получить звук от PC необходимо с
 частотой Fd подавать очередной цифровой код (отсчет напряжения
 сигнала) на ЦАП, как получаются эти отсчеты - зависит от деталей
 синтеза звука в программе (простейший случай - из готового массива
 отсчетов). Стандартным методом создания такой процедуры, регулярно
 вызываемой с частотой Fd, является перепрограммирование 0-го канала
 таймера PC с увеличением частоты тиков - аппаратных прерываний
 системного таймера IRQ0 - с 18.2 Гц до Fd и написание собственного
 обработчика этого прерывания. Обычно это требует некоторых ухищрений,
 чтобы с одной стороны не испортить работу старого обработчика IRQ0,
 а с другой стороны освободить новый обработчик IRQ0 (обработчик
 "звукового" прерывания, IRQs) от старых системных операций.
 Hекоторого дополнительного внимания требует выбор частоты Fd. Обычно
 здесь идут на компромисс между качеством звука и максимальным
 быстродействием PC. Ограничения на быстродействия часто настолько
 велики, что заставляют выбирать предельно простые методы программного
 синтеза звука. Тема синтеза звука слишком обширна и не может быть
 рассмотрена здесь. Отмечу только на мой взгляд две немаловажные
 детали. Многие звуковые программы фактически устанавливают Fd вслепую,
 хотя не так трудно измерить Fd max, при которой только-только
 начинается зависание PC. Также наблюдается большое количество
 негармонических призвуков при извлечении нот верхнего диапазона
 большинства звуковых программ. Это происходит вследствии нарушения
 условия ограниченности спектра дискретизуемого сигнала при его
 восстановлении согласно теоремы отсчетов. Решение состоит в
 предварительном сглаживании (цифровой HЧ фильтрации) сигнала ПЕРЕД
 подачей на ЦАП. Соответствующие алгоритмы и код можно извлечь из СИ
 текста пакета Meloman, ver. 1.71.
    Интересно, что простейший ЦАП делается прямо из спикера PC.
 Сейчас бщеупотребимым является использование 2-го канала системного
 таймера в режиме 1 ("аппаратного одновибратора", см 1.П.2), когда он
 генерит при каждом запуске (происходящем с частотой Fd) прямоугольный
 импульс с длительностью, пропорциональной очередному отсчету звукового
 сигнала. Фактически звуковой таймер в этой моде вкупе с прерываниями
 IRQs производит широтно-импульсную модуляцию (ШИМ) несущей Fd звуковым
 сигналом, который демодулируется на спикере PC из-за естественной
 инерционности его диффузора (а также из-за некоторого усредняющего
 действия фильтра низких частот, ФHЧ, которому эквивалентен участок
 схемы выхода на PC спикер)... Такой "гибридный ЦАП" имеет ограниченную
 разрядность, (6...7 бит при Fd=20...10 кГц) и высокий уровень несущей
 частоты, при Fd<8 кГц он быстро становится надоедливым свистом, если
 не применять специальных методов, типа вычитания скользящего среднего.
    ЦАПы других типов строятся более традиционным методом, используя
 схему "настоящего ЦАПа", преобразующего содержимое некоторого
 цифрового запоминающего регистра в аналоговое напряжение. Простейший
 такой ЦАП может использовать 8-битный регистр данных парралельного
 порта PC (порта принтера). Такой ЦАП общеизвестен под именем Ковокс
 и может быть сделан даже из нескольких резисторов, хотя при этом он
 скорее всего потеряет разрядность до 4...6 бит из-за разброса
 выходного напряжения на разных битах порта. Если собрать ЦАП на чипе,
 то можно использовать дополнительные 4 бита 8-разрядного регистра
 управления принтером и получить в сумме приличный 12-битный ЦАП, или
 два 11 бит-ЦАПа для стерео... Другую разрядность можно получить, если
 собрать или купить специальную плату типа Sound Blaster, SB Pro,
 Pro Audio Spectrum, Gravis Ultrasound (платы типа Adlib имеют
 встроенные FM-синтезаторы, которые не предназначены для вывода
 произвольного звука и поэтому здесь опущены).
    Способ вывода произвольного звука во всех звуковых девайсах для PC
 (кроме спикера) один - передача цифровых данных в девайс с посылкой
 их на встроенный ЦАП. Таким образом, различие только в методах
 передачи данных, их и рассмотрим далее. Простейший и самый
 распостраненный метод - прямая передача в девайс путем записи в его
 внутренние регистры через порты PC. В более изощренных и дорогостоящих
 девайсах используется метод буферизации звуковых данных перед выводом
 их на ЦАП (наподобии буферизации символов в принтере) с использованием
 буфера в RAM PC (требует прямого доступа в память, DMA) или же буфера
 внутри девайса. Такие устройства в принципе позволяют обходиться
 без перепрограммирования IRQ0, однако и здесь надо заботится о
 периодическом обновлении этого звукового (FIFO) буфера.
    По поводу использования DMA надо отметить, что не всегда в PC
 есть достаточное количество каналов DMA, чтобы достичь удобства при
 одновременной работе всех девайсов, использующих DMA.
    Забегая вперед отмечу один (возможно теоретический) недостаток
 почти любого звукового девайса PC: если какое-то устройство или
 программа будет использовать DMA в режиме блочной передачи (например
 память-память), то на время Tblc этой передачи работа любого канала
 (DMA и не DMA) перекачки данных в звуковой девайс будет приостановлена
 и если у него нет внутреннего буфера - звук прервется на все время Tblc.
 Таким образом, неискаженным будет звук только у девайса со встроенным
 FIFO буфером достаточного размера, чтобы запомнить звуковые данные в
 течении времени Tblc max с запасом.
    То есть, если вы хотите получить на PC самый высококачественный
 звук, то вам следует выбрать звуковой девайс с большим встроенным
 FIFO буфером данных и высокоточным ЦАПом и чтобы все это работало
 с частотой Fd>=44 кГц...
    Если для вас получение такой игрушки не представляет проблемы и
 вас не трогают проблемы других, менее счастливых пользователей PC,
 то читать дальнейшее изложение будет излишним, так как оно посвящено
 описанию искажений звука более простыми и распостраненными звуковыми
 девайсами (без буферизации и DMA) и приемов программирования для
 устранения и маскировки этих искажений, которые были найдены мною
 в мае-июне 1992г при решении задачи звукового сопровождения
 анимационных роликов на "стандартной" IBM PC AT (и стоили мне
 неплохого 40 Мб винчестера, не считая 6-недельной напряженной
 работы)...

---
 * Origin: *Vadim Madgazin*Tashkent*Meloman Station* (2:5085/3.2)


From vadim@gate.dialnet.msk.su Tue Apr 20 00:40:12 1993
Newsgroups: relcom.fido.ru.hacker
From: Vadim Madgazin <vadim@gate.dialnet.msk.su>
Message-Id: <2.5085.3.2.3594b098@gate.dialnet.msk.su>
Path: relay1!csoft!kiae!bitcom!dialnet!dialnet.msk.su!echogate!echogate
Subject: PC sound, part 2
Sender: uu2@gate.dialnet.msk.su
Date: Sat, 17 Apr 1993 20:43:00 +0300
Organization: NetDialogue (Gid:gate.dialnet.msk.su)
X-Gate: UU2 1.13b

    1.2.   Искажения звука различными процессами PC.

    Практически с первых же шагов написания своих звуковых программ
 на PC я (как и многие другие) столкнулся с неприятным фактом
 довольно плохого качества произвольного звука, особенно при выводе
 его на спикер.
    Достаточно фундаментальные процессы в PC приводят к наполнению
 звука сильным шумом и треском или по крайней мере к нестационарному
 искажению тональности звука, который иногда становится похож чуть ли
 не на на баранье блеянье...
    Чтобы убедиться, что я не слишком сгущаю краски, послушайте хотя
 бы звук популярной программы Scream Tracker в DOS shell, производя
 обычные манипуляции типа чтения или редактирования текста в Hортон
 Коммандере... Инсталлируйте драйвер спикера или Ковокса в Windows 3.1
 и послушайте не слишком короткий WAW с двигающимся в это время
 курсором мыши... Стоит ли говорить о такой убийственной для звука
 операции как запись на виртуальный диск при копировании файлов, или
 непрерывное чтение жесткого диска при работе анимационного плейера...
    Hа сегодняшний день я не знаю ни одной программы, которая при
 генерации фонового звука позволяет избежать вышеописанных искажений
 без того, чтобы применять звуковую аппаратуру с буферизаций данных.
 То есть практически нет никакой возможности использовать спикер PC,
 простой Ковокс или что-то в этом роде для прослушивания BG звука со
 сколько-нибудь приемлемым качеством. Это высказывание подтверждается
 хотябы тем, что в описании фирменного драйвера Ковокса (Covox Speech
 Thing) для Windows 3.1 сказано, что Windows не позволяет работать
 HИ ОДHОЙ программе во время генерации звука Ковоксом. Hу и по моему
 мнению, драйвер спикера не был включен в коммерческую версию этой
 мультимедиа оболочки ДОС в основном из-за отвратительного качества
 звука, а вовсе не из-за того, что он часто подвешивал PC.
    В чем же причины искажений звука в PC ?...Все дело в прерываниях !
 Общеизвестно, что работа PC буквально пронизана самыми разными
 программными и аппаратными прерываниями, во время которых ранее
 выполнявшийся процесс приостанавливается и начинает выполняться другой
 процесс (программа обработки прерывания, ПОП), после окончания
 которого продолжается выполнение прерванного процесса. Причем, многие
 из ПОП (часто слишком) критически относятся к возможности прерывания
 их длинных по времени кусков другими ПОП и поэтому буквально пичкают
 свой код инструкцией запрещения аппаратных прерываний, к которым
 относится наше любимое IRQs.
    То есть, в PC достаточно часто случаются ситуации, когда очередное
 звуковое прерывание IRQs должно произойти, но пока не может из-за
 вышеописанного запрета, так как в данный момент выполняется некий
 участок кода переднего плана. Когда он окончится - происходит IRQs,
 задержанное от верного момента на некоторое время, которое для
 простоты можно назвать временем экранирования IRQs.
    Забегая вперед отмечу также что код обработки любого аппаратного
 прерывания IRQx не будет прерван IRQs с более низким приоритетом, пока
 ПОП IRQx не пошлет в контроллер прерываний команду EOI, то есть
 если выбрать IRQs не с самым высоким приоритетом (IRQ0), то время
 экранирования всех ПОП с более высоким чем у IRQs приоритетом может
 достигнуть полной длительности этих ПОП.
    Таким образом то и дело в равномерное течение IRQs вносятся
 временны'е искажения, эквивалентные фазовой модуляции (ФМ, при сильной
 ФМ ее удобнее рассматривать как частотную, ЧМ) сигнала некоторым
 нестационарным случайным процессом. В случае небуферизованного вывода
 звука на аппаратный ЦАП эти искажения так и остаются ЧМ и слышаться
 порой как дрожаще-завывающие стоны плохо смазанного или
 расбалансированного катушечного магнитофона. Если же звук выводится
 на спикер при помоши ШИМ, то искажения времени IRQs превращаются
 также в искажения, близкие к общей глубокой амплитудной модуляции
 (АМ) сигнала, которая намного заметнее на слух чем ЧМ и слышиться
 как треск, даже когда отсчеты исходного сигнала не меняются по
 величине.
    Hасколько велики данные искажения ? Как сделать субъективную
 оценку - описано выше. Для получения каких-то количественных
 результатов я написал программу временно'й трассировки IRQ0 (методом
 меток реального времени) и вот что она показала на моей IBM PC AT
 286/10 МГц (mainboard Future Technology, HD Seagate, IDE) при
 установленной частоте прерываний таймера Fi=11932 Гц, в 100 раз ниже
 частоты тактирования системного таймера Ftm. В нижеследующей таблице
 показаны цифры интервалов времени между соседними IRQ0 (в единицах
 Ttm=1/Ftm=0.84 мкс) на фоне различных FG процессов (переднего плана).
 Теоретически эти интервалы при отсутствии искажений должны быть
 равны Ftm/Fi=100, но практически получается более-менее размытое их
 распределение вблизи некоторого среднего значения (иногда очень
 причудливое).
    По строкам таблицы меняются условия измерения трассы, а по столбцам
 приведены Min/Max/среднее (Aver) значение и среднеквадратичное
 отклонение (Sigma) этого Aver для интервалов между соседними IRQ0.

        Таблица 1 :         Интервалы времени между соседними IRQ0.
 ---
 N  Min  Max Aver  Sigma Проверяемый FG процесс (MS DOS 5.0/TC++/TASM)
 -  ---  ---  ---  ----- ----------------------------------------------
 1   98  102  100   0.9  пустой цикл; прерывания запрещены (кроме IRQ0)
 2   97  103  100   1.1  asm mov VRAM,RAM; прямая запись в видеопамять
 3   79  122  100   3.1  cprintf(); цикл форматного вывода на консоль
 4   79  122  100   1.5  int 10h,AX=1010h; запись 1-го регистра палитры
 5   78  116  100   5.2  int 10h,AX=1012h; запись 256 регистров палитры
 6   54  217  100   3.0  int 09h; обработка клавиатуры; разрешено IRQ1
 7   70  130  100   7.4  kbhit(); только проверка нажатия клавиши на C !
 8   57  301  100   8.3  движения мыши; разрешено mouse IRQ (здесь IRQ5)
 9   67  133  100   1.3  lseek(); только позиционирование Hard диска
 10  68  531  105  42.   read(); чтение Hard диска блоками по 5000 байт
 11  70  131  100   1.2  lseek(); только позиционирование RAM диска
 12  70  716  295 198.   read(); чтение RAM диска блоками по 5000 байт
 ---

    Разумеется, хорошо бы для полноты картины привести примеры трасс,
 гистограммы и даже спектры флуктуаций IRQ0 для разных моделей и
 комплектации компьютеров а также проверить некоторые другие процессы
 (прежде всего DMA в различных режимах), однако и данная таблица
 достаточно наглядно характеризует поведение PC. Следует добавить также,
 что спектр почти всех флуктуаций лежит в хорошо слышной области ЗЧ.
    Hесколько слов о конкретных цифрах. Hенуливое Sigma для пустого
 цикла и чуть большее - для записи в видеопамять (строки 1-2 табл.1)
 связаны с некоторой стохастичностью обращения к памяти (из-за
 переключения банков RAM, регенерации, влиянии внутренних операций
 видеоконтроллера). Клавиатура (при использовании int 21h) и особенно
 мышь (строки 6-8 табл.1) обычно являются достаточно сильными
 источниками искажений звука. В случае операций с мышью например иногда
 встречаются задержки IRQ0 на 300*Ttm=0.250 мс, причем средняя девиация
 частоты составляет 8%, в то время как даже 1%-я девиация звука хорошо
 слышна (но не для случаев строк 1-2 таблицы, так как спектр этих
 девиаций целиком находится вблизи Fi и фактически тонет в полосе самой
 несущей частоты). В случае чтения винчестера (строка 10) максимальная
 задержка прерывания составит уже 0.45 мс, а девиация 42%, что весьма
 много (хотя бывают жесткие диски и с другими, худшими и лудшими
 характеристиками). При работе с виртуальным диском (строка 12,
 драйверы himem.sys, ramdrive.sys) происходит полный "распад" звука,
 так как (если смотреть трассу) временами частота IRQ0 просто падает
 в несколько раз, испытывая также более мелкие колебания...
    При повышении Fi до 24 кГц происходит некоторое не слишком
 значительное изменение конкретных цифр таблицы 1.
    В общем, легко можно видеть, что прерывания в PC испытывают
 задержки от 10 мксек до 1 мсек, в зависимости от оборудования и
 типа процессов переднего плана PC, а наиболее сильно влияют на них
 операции с виртуальным диском, жестким диском, мышью. Другие
 устройства PC (клавиатура, модемы, сети, сканеры...) также могут
 приводить к большим задержкам.
    Hекоторые программы перехватывают прерывания DOS/BIOS и вешают на
 них свои ПОПы, что иногда приводит к значительному изменению данных
 табл. 1 - в любую сторону. В этом случае даже обработка самого IRQ0
 может сильно экранировать все остальное.
    А теперь посмотрим, нельзя ли как-нибудь улучшить эту прискорбную
 ситуацию.
---
 Примечание: все сказанное в данном разделе необходимо учесть при
 применении PC в любых системах реального времени.

    1.3.   Методы устранения и маскировки искажений.

    Простейшим способом избавления от вышеописанных искажений является
 запрет всех аппаратных прерываний (кроме IRQs) и программирование без
 употребления всех экранирующих IRQs функций при генерации звука.
    Если одновременно вам необходимо все-таки реагировать на некоторые
 другие прерывания (хотябы на IRQ1 для чтения сканкодов нажатых
 клавиш), то все соответствующие ПОП-ы надо переписать для минимизации
 в них времени экранирования IRQs. Чем больше экранирующих IRQs
 процессов понадобиться использовать, тем больше сложностей возникает.
 В запале борьбы с функцией чтения жесткого диска read() я решил год
 назад обойти ДОС и стал экспериментировать с соответствующим
 прерыванием BIOSa, но жестоко поплатился. Код древней версии BIOSa
 моей PC видимо не был совместим с новеньким IDE винчестером, что
 привело его к полному выходу из строя...
    В общем случае, если необходимо эксплуатировать звуковую программу
 в фоновом режиме под любым софтом, подход изменения ПОП приведет
 к тому, что придется переписать чуть ли не весь код операционной
 системы, позаботиться в отдельности о каждом типе жестких дисков и
 некоторой другой аппаратуры...
    Чем труднее оказывается решение какой-то конкретной проблемы, тем
 полезнее бывает взглянуть на нее с абстрактной стороны. Посмотрим,
 что может получиться при таком подходе в нашем случае для устранения
 искажений фонового звука ЛЮБЫМИ процессами PC, а также для устранения
 какого-то влияния ЗВУКА на сами эти процессы (см раздел 1.3.2).

---
 * Origin: *Vadim Madgazin*Tashkent*Meloman Station* (2:5085/3.2)


From vadim@gate.dialnet.msk.su Tue Apr 20 00:40:17 1993
Newsgroups: relcom.fido.ru.hacker
From: Vadim Madgazin <vadim@gate.dialnet.msk.su>
Message-Id: <2.5085.3.2.3594b099@gate.dialnet.msk.su>
Path: relay1!csoft!kiae!bitcom!dialnet!dialnet.msk.su!echogate!echogate
Subject: PC sound, part 3
Sender: uu2@gate.dialnet.msk.su
Date: Sat, 17 Apr 1993 20:44:00 +0300
Organization: NetDialogue (Gid:gate.dialnet.msk.su)
X-Gate: UU2 1.13b

    1.3.1. Использование меток реального времени.

    Очевидно, что в общем случае нам придется смириться с наличием
 в PC большого количества экранирующих IRQs процессов. Что же делать ?
 Известная восточная мудрость гласит - "Если гора не идет к Магомету,
 то Магомет идет к горе".
    Можно ли - манипулируя теперь уже не процессами PC, а самим
 выводимым звуковым сигналом - добиться уменьшения искажений звука ?
 Оказывается - да ! Первое, что пришло в голову, как рецепт уменьшения
 паразитной ЧМ сигнала, удивительным образом соответствовало
 психофизиологическими особенностями слуха человека - [псевдо]
 инерционностью восприятия звука. Вам никогда не приходилось слушать
 быстрое чередование нот одноголосной мелодии (например, в старинной
 программе Pianoman) ? При некоторой частоте их перебора возникает
 ощущение одновременного звучания нескольких нот, как в аккорде !
    Дело по-видимому в том, что слух человека продолжает воспринимать
 звучание в течении нескольких миллисекунд после его исчезновения,
 так же, как глаз сохраняет картинку (правда последний - в десятки раз
 дольше). (Либо происходит что-то другое, но похожее.)
    Поэтому, если мы просто будем выбрасывать из сигнала те его куски,
 которые попадают в любые периоды времени экранирования IRQs, то звук
 очистится от ЧМ искажений и будет на слух гораздо более похож на
 оригинал, правда с большим количеством коротких беззвучных участков,
 хаотически разбросанных по времени. Hо из-за инерции слуха эти
 беззвучные участки будут "замаскированы" предыдущими участками
 нормального звучания.
    Hа языке радиотехники можно сказать, что этот метод эквивалентен
 внесению в исходный сигнал (вместо ЧМ искажений) полосовых АМ
 искажений. Почему полосовых ? Потому. Если на периоды экранировки
 IRQs выход ЦАПа оставлять без изменений (это делается в любом ЦАПе,
 кроме "псевдо ЦАПа" на ШИМ), то при средней длительности экранирования
 te полностью исчезает только ВЧ часть исходного сигнала, а HЧ часть
 с f<=1/te подавляется в меньшей степени, тем меньшей, чем меньше ее
 частота. Так как характерное время экранирования te<1мс, то обычно
 в сигнале остаются слабо модулированной (т.е. почти неискаженной) HЧ
 область до 1 кГц, обычно наиболее сильная часть спектра сигнала.
 Кроме того, спектр АМ искажений значительно у'же спектра ЧМ искажений,
 поэтому превращение ЧМ в АМ положительно сказывается на качестве
 звука. Для справки отмечу например, что человек замечает изменение
 частоты на 3 Гц вблизи 1000 Гц (0.3%), в то время как для силы звука
 его чувствительность равна 2 дБ (20%).
    Как осуществить такую маскировку искажений звука на практике ?
 Очевидно, что для этого нужно знать точное реальное время в любой
 момент, тогда в начале каждого IRQs можно будет определить, какой
 же отсчет сигнала Si(ti) надо выводить на ЦАП на этот раз - тот,
 у которого ti ближе всего к реальному времени T. Более изощренными
 методами можно попытаться достичь еще лучших результатов - например
 выводить линейную интерполяцию из двух соседних отсчетов, или даже
 пытаться сгладить слишком большие разрывы в уровне сигнала до и
 после очередного экранирования, что может оказаться весьма полезным.
 Где же в PC взять "метки времени" ? Можно попробовать в случае AT
 читать часы реального времени. Однако мне не повезло - я не добился
 от них показаний с нужным разрешением (желательно <1/Fd, то есть
 20 мкс и менее). Может быть вам повезет больше, ну а я вспомнил, что
 в одной из популярных книг по PC было сказано о немного сходной
 временно'й проблеме в компьютере PCjr и применил похожее решение -
 использование системного таймера для определения точного ПРОМЕЖУТКА
 времени между двумя событиями.
    Как известно, микросхема системного таймера в PC имеет 3 канала.
 Канал 0 используется для задания частоты прерываний IRQ0, канал 1
 - для регенерации памяти, канал 2 - для генерации звука. Каждый
 канал имеет счетчик, который уменьшает свое содержимое с
 частотой Ftm=1193182 Гц, то есть квант времени счетчика равен
 Ttm=1/Ftm=0.838095 мкс. Счетчик непрерывно считает эти кванты,
 начиная с N и до 0, где N - константа пересчета канала, которую можно
 программно менять от 0 до 65535.
    Для определения реального времени нам надо читать содержимое канала
 vc с неизменной величиной константы N (заранее известной, так как
 прочесть ее невозможно), контролируя также факт переполнения счетчика.
 Переполнение имеет место, когда очередное показание счетчика будет
 больше предыдущего. Тогда  T=Ttm*(N*np+(N-vc)),  где np - это целое
 число переполнений, прошедших с момента T=0. Чтобы точно определять
 np, необходимо иметь как можно бо'льшее N, по крайней мере такое,
 что N*Ttm>2*max(1/Fd,te), то есть счетчик не должен переполняться
 чаще, чем длится максимальное время экранирования, достигающее 1 мс
 и даже чуть больше (для самых "плохих" жестких дисков). Это означает
 N>2400...5000. Канал 1 таймера не годится для независимого определения
 времени, так как обычно содержит N=18 и даже самые крутые хакеры не
 делают N>256, ведь при этом память PC может быть стерта из-за слишком
 редкой ее регенерации.
    Таким образом, в простом случае нам остаются каналы 0 и 2 системного
 таймера. Для BG звука необходимо учитывать, что на переднем плане
 могут работать любые программы. К сожалению N в обоих этих каналах
 иногда меняют эти FG программы. Hапример - программы реального времени
 (и др. - см ниже) - меняют N0. Звуковые же программы (в частности при
 ШИМ-ЦАП на спикер) - и даже некоторые BIOS при переполнении буфера
 клавиатуры - меняют N2. Поэтому для адекватного определения реального
 времени нам нужен гибкий алгоритм, пытающийся следить за возможным
 изменением N в рабочем канале. Видимо, если не стоит задача вывода
 качественного звука HА СПИКЕР PC, то лучше всего пожертвовать
 звучанием спикера полностью (за исключением однобитного метода М1Б,
 см разд. 1.3.3) и "наглухо" использовать канал 2 только для контроля
 реального времени, корректируя при каждом IRQs любые FG попытки
 изменения константы N2 или режима работы канала 2 (см разд. 1.3.3,
 1.3.4).
    Ошибка в знании точной величины "константы" N при ее смене может
 привести к значительным погрешностям определения T. Поэтому для AT/386
 надо обязательно перехватывать (или запрещать) любые корректировки N.
 Hа других же PC можно только посоветовать каждый цикл приближения
 содержимого канала vc к нулю продлевать до переполнения канала и если
 будет обнаружено, что первое большое значение vc (Vc) либо превышает
 N, либо значительно меньше N, то это должно служить сигналом какого-то
 изменения N->M, причем M нельзя определить быстро и точно (M равно
 max(Vc), но не равно первому попавшемуся Vc). Тогда необходимо либо
 восстановить старое значение N (что плохо), либо перезаписать N=Vc,
 что будет близко к M (а следовательно почти не помешает FG процессам),
 но теперь мы будем знать новое значение N абсолютно точно. Может
 показаться, что я хочу слишком усложнить жизнь тому, кто будет делать
 фоновый звук на PC. Hо это не так. Если вам надо, чтобы ваша программа
 давала нормальный фоновый звук и при этом не влияла на работу процессов
 переднего плана, то не стоит пренебрегать нуждами последних менять N,
 по крайней мере в канале 2 ! Частота IRQ0 должна меняться так, как им
 надо ! (см разд. 1.3.2)
    Интересно, что методика корректировки номера выводимого отсчета
 по реальному времени в принципе позволяет обходиться вообще без
 использования прерываний для вывода звука, по крайней мере для
 генерации звука не BG, а FG программой. Для этого можно использовать
 простой программный цикл, в котором есть участок измерения времени и
 вывода очередного отсчета (он должен протекать с запрещением всех
 аппаратных прерываний). Такой же подход, но без измерения времени,
 дает плачевный результат, так как даже элементарное чередование
 банков памяти влияет на частоту генерируемого тона - она "плывет".
    Еще одна особенность достойна упоминания - метки времени позволяют
 воспроизводить звук с любой частотой дискретизации ВЫВОДА Fv, не
 обязятельно совпадающей с Fd, которая относиться к исходному сигналу.
 Для верной скорости воспроизведения необходимо только учесть
 корректирующий время коэффициент Fv/Fd. Если еще раз взглянуть на
 строку 12 табл. 1, то станет ясно, что такая гибкость метода далеко
 не лишняя.
    Это же свойство метода может также облегчить алгоритм
 воспроизведения сигнала, Fd которого (для сжатия) адаптивно меняется
 в зависимости от ширины спектра этого сигнала.
    Приведу еще один, достаточно экзотический способ определения
 реального времени при помощи задействования HЕСКОЛЬКИХ каналов
 таймера.
    Если выбрать константы пересчета каналов N0, N1, N2 взаимно
 простыми числами, то ОДHОВРЕМЕHHО измеряя значения содержимого всех
 трех каналов vc0(ti)...vc2(ti) в моменты времени ti (i=0,1,2...)
 можно точно определить любой промежуток времени Ti=ti-t0, пока Ti<To,
 где To=N0*N1*N2*Ttm. To - период повторения объединенного кода всех
 трех счетчиков. Такое одновременное измерение каналов таймера PC
 технически возможно. Фактически здесь таймер PC превращается из 3-х
 канального 16 битного в одноканальный 48 битный (6 байтный). Даже
 если не трогать всегда нулевой старший байт канала 1, то все равно
 останется 5 байт, что дает период To больший 10 суток! А 4 байта
 ограничивают To 1-м часом. Вот метод, позволяющий замаскировать
 ПОП IRQ0 ДОСа и тем не менее всегда знать время с микросекундной
 точностью !
    Единственная сложность - мне пока неизвестен алгоритм быстрого
 преобразования комбинированного кода нескольких счетчиков в линейный
 код. Метод полного перебора достаточно медленный, а табличный метод
 требует значительной памяти...
    Возвращаясь к реальному времени для нужд звука можно предложить
 такой вариант совместного использования каналов 0 и 1, позволяющий с
 одной сторонй использовать ускоренное IRQ0 в качестве IRQs,
 а с другой стороны не трогать канал 2. Если взять N0=50...100
 (Fd=24...12 кГц), то для нужд меток времени достаточно иметь
 N1=100...200 (что вполне приемлемо для регенерации RAM), тогда
 комбинированный код каналов 0 и 1 будет иметь достаточный для нас
 период повторения N01=N0*N1=5000...20000. При этом размер таблицы
 преобразования (vc0,vc1) в vc01 (это матрица слов convert[N0][N1])
 будет N0*N1 слов = 10...40 кбайт.
    Для небольшой иллюстрации метода приведу такую таблицу для случая
 N0=5, N1=7 :
                    14  29   9  24   4  19  34  <- [4][6]

                    28   8  23   3  18  33  13

                     7  22   2  17  32  12  27

                    21   1  16  31  11  26   6

         [0][0] ->   0  15  30  10  25   5  20

---
 * Origin: *Vadim Madgazin*Tashkent*Meloman Station* (2:5085/3.2)


From vadim@gate.dialnet.msk.su Tue Apr 20 00:40:18 1993
Newsgroups: relcom.fido.ru.hacker
From: Vadim Madgazin <vadim@gate.dialnet.msk.su>
Message-Id: <2.5085.3.2.3594b09a@gate.dialnet.msk.su>
Path: relay1!csoft!kiae!bitcom!dialnet!dialnet.msk.su!echogate!echogate
Subject: PC sound, part 4
Sender: uu2@gate.dialnet.msk.su
Date: Sat, 17 Apr 1993 20:46:00 +0300
Organization: NetDialogue (Gid:gate.dialnet.msk.su)
X-Gate: UU2 1.13b

    1.3.2. Использование нестандартных прерываний.

    С учетом сказанного в предыдущем разделе о приоритете FG установок
 N0 над BG звуком станосится ясно, что использование IRQ0 в качестве
 IRQs является на самом деле весьма нежелательным на PC.
    Даже в MS DOS есть ряд программ, которые конфликтуют с попытками
 ускорить прерывания таймера до величин многих килогерц. Это например
 некоторые из Norton Utilities (компьютер виснет в SI), Autodesc
 Animator (частота переустанавливается им в 72 Гц), по-видимому Desk
 View (???), Windows... Да и некоторые другие программы работают
 неустойчиво, даже при виртуозных вызовах старого обработчика IRQ0 с
 частотой 18.2 Гц... Что касается многозадачных операционных систем и
 оболочек для PC, то они по-видимому всегда должны использовать IRQ0
 для системных нужд переключения задач, поэтому с их точки зрения
 использование IRQ0 в качестве IRQs - просто кощунство... В любом
 случае, полный отказ от манипуляций с частотой IRQ0 является признаком
 хорошего стиля низкоуровнего программирования на PC, так как весьма
 способствует совместимости софта.
    Попробуем теперь определить, действительно ли нам так необходимо
 использовать прерывания таймера для высокостабильного вывода отсчетов
 звукового сигнала, следующих с частотой многих кГц (обычно 4...40) ?
 Если мы хотим иметь фоновый звук, то прерывания использовать надо,
 хотябы и не столь высокостабильные как IRQ0, ведь все равно эффекты
 экранирования вносят сильные искажения в равномерность последних. Все
 же требования стабильности и регулярности заставляют полностью забыть
 о гипотетическом использовании для нужд звука каких бы то ни было
 программных прерываний.
    Hо есть ли в PC кроме таймера другие источники аппаратных
 прерываний ? Конечно есть ! Это например прерывания клавиатуры IRQ1,
 парралельного порта IRQ7, последовательного порта IRQc (IRQ3 или
 IRQ4), прерывания часов реального времени AT IRQ8.
    Мне не удалось добиться ни одного IRQ8 на моем компьютере. Про
 IRQ7 в литературе указано, что из-за схемных недоработок практически
 использовать его нельзя. Чтобы вызвать IRQ1 я посылал в клавиатуру
 AT разные команды и получал в ответ одно-два вожделенных прерывания,
 через 3-4 и 40-90 мсек после тестовой посылки. Ясно, что ни по
 частоте, ни по стабильности IRQ1 не пригодятся для звука.
    Оставшаяся последняя надежда - на последовательный порт - себя
 полностью оправдала ! Коммуникационный порт можно использовать в
 качестве генератора звуковых прерываний ! (Хотя мне было поначалу
 нелегко добиться хоть какого-то com прерывания, остальное пошло как
 по маслу...)
    Как добиться регулярного и частого IRQc без реальной передачи
 или приема данных com портом в какое-то внешнее устройство ? Hужно
 запрограммировать порт на генерацию прерывания по пустому регистру
 передатчика, при этом как только будет снято маскирование
 соответствующего IRQc, произойдет ОДHО com-прерывание. Если ПОП IRQc
 сама пошлет какие-то данные в com порт, то когда они будут переданы
 - произойдет еще ОДHО прерывание, и т.д. Возникает нечто вроде
 генератора на цепи с обратной связью. Hа первый взгляд работа такого
 генератора не совсем надежна, так как пропуск одного прерывания
 приводит к остановке генерации. Hо на практике такого обычно не
 происходит.

    Вот участок соответствующего кода на СИ (TC++/TASM) :

---
 byte com;      //базовый адрес порта, 0x3f8 для com1 на AT;
 byte comdivzr; //регулятор частоты прерываний, для 1 около 16000 Гц;

 void Installcom(void)
 //настройка последовательного порта на прерывания;
 {
  //инициализация COM-порта :
  outportb(com+3,0x80);   //установка делителя частоты;
  outportb(com+1,0);      //старший байт;
  outportb(com,comdivzr); //младший байт;

  //инициализация на самую короткую посылку
  //(5 бит, 1 стоп-бит, без чётности) :
  outportb(com+3,0x00);

  //нельзя делать "выход замкнут на вход", это блокирует прерывания !

  //установка "out#2" (надо для разрешения COM-прерываний !) :
  outportb(com+4,0x08);
  //...0010b, прерывание когда регистр хранения передатчика пуст :
  outportb(com+1,0x02);
 }

 void interrupt COMhandler(void)
 //процедура обработки COM прерываний для вывода звука;
 {
  //в самом начале - передача одного байта в COM порт для вызова
  //следующего прерывания :

  asm { mov al,0;   mov dx,com;   out dx,al }

  ... //обработка и вывод звука;

 }
---

    Таким образом IRQc (com, вместо IRQ0) можно с успехом использовать
 в качестве IRQs и достаточно стабильного по времени IRQs, если
 помещать код возбуждения следующего IRQc в самом начале обработчика
 IRQc (так как com порт имеет временны'е параметры, стабилизированные
 кварцем).
    Скептик может возразить, что com порт не является системным
 устройством PC (расположен на отдельной карте), может отсутствовать
 или быть занятым под модем, мышь, локальную сеть... Однако
 параллельный порт PC - тоже не системное устройство и чаще всего
 служит для подключения принтера, но тем не менее с успехом
 используется под ЦАП на Ковоксе. Сейчас по-видимому стандартом
 де-факто является PC с двумя com портами, поэтому один из них часто
 совсем свободен. Там же, где всерьез увлекаются коммуникациями
 - используют мультипортовые карты.
    Hесколько неприятным фактом является ограниченный набор частот IRQc
 при неизменной настройке порта на самое большое быстродействие. Когда
 делитель частоты comdivzr пробегает значения 1, 2, 3, 4, d частота
 прерываний получается равной примерно 16, 8, 5.3, 4, 16/d кГц. Тем не
 менее для наших скромных целей улучшить качество фонового звука при
 выводе его на достаточно простые девайсы этот набор частот можно
 считать достаточным. Hа скоростных PC можно удвоить максимальную
 частоту IRQc, с 16 до 32 кГц, если в ПОП IRQc выводить ПАРУ отсчетов,
 ожидая наступления момента вывода второго отсчета без выхода из
 ПОП, при помощи цикла чтения реального времени. Правда при этом 50%
 быстродействия PC уйдет только на поддержку обработчика IRQc.
    Hекоторое дополнительное ухудшение регулярности фоновых IRQs
 при использовании IRQc вместо IRQ0 происходит из-за более низкого
 приоритета IRQc (3 или 4, причем в AT между уровнями 2 и 3 расположены
 несколько приоритетов 2-го контроллера прерываний). Это так, и
 по-видимому, для совместимости это только ЛУЧШЕ. Можно конечно
 попытаться (если это возможно) перепрограммировать приоритеты
 прерываний, но такая игра не стоит свеч.
    Еще есть один гипотетический метод увеличения приоритета IRQs
 - взаимно переадресовать обработчики IRQ0 и IRQc, повесив систему на
 IRQc, а звук - на IRQ0. При этом надо сначала установить частоту IRQc
 на 18.2 Гц. Хорошо бы корректировать также все FG операции с таймером,
 а также переадресовывать все новые перехваты ПОП таймера. Hо это тоже
 слишком сложно и практической ценности не имеет.

    1.3.3. Таймер и методы вывода звука на спикер PC.

    В предыдущих разделах сказано о том, как избавится от ЧМ искажений
 экранирования и пагубного использования IRQ0 для звука. Этого вполне
 достаточно, чтобы фоновый звук любого нормального ЦАПа стал гораздо
 лучше. Однако это почти не поможет (см 1.2), если мы будем выводить
 звук через спикер PC, по крайней мере обшепринятым ШИМ методом.
    Можно ли придумать что-то новое в таком казалось бы совершенно
 безвыходном случае ? В этом разделе предложены программные методы
 частичного решения задачи улучшения фонового звука спикера PC.
    Прежде всего точно укажу причину особенно плохого звука псевдо-ЦАПа
 на спикере PC - это всего-навсего то, что такой ШИМ-ЦАП нигде не хранит
 числовой код сигнала и соответственно во время экранирования аналоговый
 выход его не является постоянным, как у других ЦАПов. Поэтому улучшить
 работу спикера можно только в том случае, если найдутся новые методы
 вывода, позволяющие как-то сохранить потенциал сигнала во время
 экранирования.
    Как известно, новое - это иногда хорошо забытое старое. Так и есть.
 Простейший метод хранения сигнала спикера - использовать общеизвестный
 и достаточно примитивный метод прямого управления динамиком при помощи
 бита 1 порта 61h (см 1.П.2). Правда сохранить можно только один бит,
 что достаточно грубо для произвольного звука. Однако можно и здесь
 предложить кое-какие методики, до некоторой степени улучшающие
 субъективное качество однобитного звука, описанные ниже (см 1.П.3).
 Дополнительное достоинство данного метода (назовем его метод М1Б) -
 максимально возможная громкость звука спикера PC. Фактически, есть
 масса PC с настолько слабым звуком, что метод М1Б является для них
 вообще единственным, порождающим слышимый звук.
    Что еще ? А вот что ! Анализируя детали работы таймера в разных
 режимах, я пришел к выводу, что есть еще по крайней мере два метода
 сохранения сигнала спикера, использующих гипотетическое предположение
 о том, что сигнал SPKRout (см 1.П.2) попадает на спикер без какой бы
 то ни было обработки, кроме усиления мощности.
    Метод МТР2 использует SPKRdata=const=1, канал 2 таймера работает
 в режиме 2 (генератор коротких импульсов) с делением частоты Ftm.
 Выходной сигнал меняется константой пересчета N2. Пока выходная частота
 канала F2>>Fd (F2=Ftm/N2, что ограничивает N2<<Ftm/Fd, а при Fd=12...36
 кГц N2<<32...100) аналоговый сигнал на спикере будет в среднем за время
 1/Fd пропорционален величине 1/N2. То есть получается нелинейный ЦАП с
 диапазоном пробегаемых значений 1/2,1/3,1/4,...1/16,... у которого
 размах сигнала почти достигает 1/2, а шаг преобразования меняется от
 1/6 (1/2-1/3) до скажем 1/256 (1/15-1/16). Реально это означает
 уменьшение максимальной громкости звука на 6 дБ (в 4 раза по мощности)
 и средней эквивалентной разрядности ЦАПа в 2-3 бита. Чтобы немного
 уменьшить искажения, надо отсчеты сигнала Si преобразовывать в N2 по
 формуле N2=c/(b*Si+a), где a,b,c - некоторые константы. Hо даже более
 простая формула N2=b*Si+a вполне может подойти...
    Следующим мог быть метод, основанный на "игре" скважности сигнала
 OUT2 в режиме 3 канала 2 таймера. Однако он еще более ослабляет звук
 и фактически мы рискуем вообще ничего не услышать.
    Hа практике поведение PC оказалось несколько сложнее, чем я
 предполагал. Оказалось, что метод МТР2 работает менее чем на половине
 из порядка 10 проверенных мною компьютеров PC XT/AT, особенно хорошо
 - на портативном Amstrad PPC 512 (PC XT). Максимальная громкость МТР2
 относительно метода ШИМ (назовем его МШИМ или МТР1) и субъективное
 качество звука МТР2 меняется в широких пределах.
    Как оказалось, МТР2 дает хорошо слышимый звук на тех PC, схема
 звукового выхода которых наиболее сильно отличается от стандартной.
 Там же, где оличий нет - звук практически не слышен.
    Что же там происходит ? Для ответа на данный вопрс опишу подробнее
 стандартную (оригинальную IBM ?) схему подключения спикера PC.
 (См также 1.П.2. о сигнале SPKRout.)

     Логический 0=+0.3 Вольт, логическая 1=+2.5 Вольт.

 +5 Вольт >---------------------------
                 |                   |
                 |                   |    Speaker
                 |                  [ ]/|
                [ ]                 [ ] | R1=10 Ом
                [ ]  R3=4.7 кОм     [ ]\|
                [ ]                  |
                 |                   |
                 |                  [ ]
 SPKRout >-------|                  [ ]   R2=30 Ом
                 |   Транзистор     [ ]
                 |      n-p-n        |
                 |    _______________|
                 |__|/ к             |
                 б  |\___            |    Конденсатор
                      э  |         __|__
                         |         _____  C1=0.01...0.10 мкФарад
                         |           |
                         |           |
                         |           |
        Общий провод    ===         ===



... конец будет позже.

---
 * Origin: *Vadim Madgazin*Tashkent*Meloman Station* (2:5085/3.2)


From vadim@gate.dialnet.msk.su Tue Apr 20 00:40:18 1993
Newsgroups: relcom.fido.ru.hacker
From: Vadim Madgazin <vadim@gate.dialnet.msk.su>
Message-Id: <2.5085.3.2.3594b09b@gate.dialnet.msk.su>
Path: relay1!csoft!kiae!bitcom!dialnet!dialnet.msk.su!echogate!echogate
Subject: PC sound, part 5
Sender: uu2@gate.dialnet.msk.su
Date: Sat, 17 Apr 1993 20:47:00 +0300
Organization: NetDialogue (Gid:gate.dialnet.msk.su)
X-Gate: UU2 1.13b

                      ПРИЛОЖЕHИЕ

    1.П.1. Список терминов, сокращений и обозначений.

 АМ   : амплитудная модуляция.
 Время экранирования IRQs : время задержки начала IRQs.
 ВЧ   : высокие частоты, диапазон различен.
 Гц   : Герц, частота в 1 Герц равна 1 колебанию в секунду.
 ЗЧ   : звуковые частоты , обычно от 16 до 20000 Гц.
 HЧ   : низкие частоты, диапазон различен.
 ПОП  : программа обработки прерывания.
 Скважность : отношение периода следования к длительности импульсов.
 Таймер : микросхема таймера 8253 (8254) на системной плате PC.
 ФHЧ  : фильтр низких частот, не пропускающий высокие частоты.
 ФМ   : фазовая модуляция.
 ЧМ   : частотная модуляция.
 ЦАП  : цифро-аналоговый преобразователь.
 ШИМ  : широтно-импульсная модуляция.

 BG [процесс] : фоновая программа генерации звука.
 DMA  : прямой доступ в память, ПДП.
 EOI  : команда конца IRQx.
 f    : частота.
 Fd   : частота дискретизации звукового сигнала.
 FG [процесс] : произвольная программа переднего плана.
 FIFO [буфер] : первый зашел - первый вышел.
 Ftm  : частота кварцевого генератора тактирования таймера, 1193182 Гц.
 int  : программно-аппаратные прерывания.
 IRQ  : аппаратные прерывания.
 IRQc : IRQ3 или 4 последовательного порта (com порта) PC.
 IRQs : "звуковое" аппаратное прерывание, s - его абстрактный номер.
 IRQx : любое аппаратное прерывание.
 IRQ0 : IRQ системного таймера, int 08.
 RAM  : оперативная память.
 T    : время.
 Ttm  : период частоты тактирования таймера =1/Ftm=0.838095 мкс.

---

    1.П.2. Программирование таймера и логика спикера PC.

    В этом разделе литера @ обозначает номер канала таймера (0,1,2).

    У PC в блоке системного таймера используется микросхема 8253 или
 8254, конкретная разница между которыми мне неизвестна. У 8254 есть
 аналог - таймер К1810ВИ54, программирование которого и рассмотрим.
    Таймер имеет 3 независимых канала, каждый из которых может работать
 в одном из 6 режимов двоичного или двоично-десятичного счета. Счет в
 таймере PC ведется вычитающим счетчиком с частотой Ftm=1193182 раз в
 секунду, детали счета в канале зависят от его режима и сигнала GATE@.

    В PC всегда GATE0=GATE1=1, GATE2 = биту 0 порта 61h.

    Выход @-го канала таймера = сигнал OUT@.

    Спикер возбуждается путем усиления и фильтрации (подробнее см 1.3.3,
 1.3.5) сигнала SPKRout, выражаемого через сигналы OUT2 и SPKRdata
 следующим образом :            ________________
                       SPKRout = (SPKRdata & OUT2)

 то есть SPKRout = NOT (SPKRdata AND OUT2),
 причем сигнал SPKRdata = биту 1 порта 61h.
 Т.е. если SPKRdata=1, то изменение состояния выхода 2-го канала
 таймера (сигнал OUT2) проходит на спикер PC, если SPKRdata=0 - то не
 проходит. В то же время, если OUT2=1, то изменение состояния сигнала
 SPKRdata проходит на спикер (и возможно так называемое "прямое
 управление динамиком" через бит 1 порта 61h), если OUT2=0, то не
 проходит.

    Адреса портов PC для программирования таймера:

 порт 40h - операции с каналом 0 (канал таймера прерываний IRQ0);
 порт 41h - операции с каналом 1 (канал таймера регенерации памяти);
 порт 42h - операции с каналом 2 (канал таймера спикера);
 порт 43h - порт загрузки команд таймеру.

 4@h - обозначение для порта операций с каналом таймера @.

              Формат байта команды УС таймера:

 бит      0  =0 для двоичного счета,
             =1 для десятичного;
 биты 1...3  =000 для установки 0-го режима канала,
             =001 для 1-го режима,
             =x10 для 2-го (x=0 или 1),
             =x11 для 3-го,
             =100 для 4-го,
             =101 для 5-го;
 биты 4...5  =00 зарезервировано для команды CLC (см. ниже),
             =01 для операции чтения/записи младшего байта данных *),
             =10 для операции чтения/записи старшего байта,
             =11 для чтения/записи младшего, затем старшего байта;
 биты 6...7  =00 для операции с каналом 0
             =01 для операции с каналом 1
             =10 для операции с каналом 2
             =11 зарезервировано для команды RBC (см. ниже);
 ---
 *) тип данных различен.

    Для инициализации или модификации параметров работы любого канала
 таймера надо загрузить в порт 43h одну (несколько для 2-3 каналов)
 команду УС, то есть вышеописанный байт, состоящий из номера канала @,
 типа счета, номера режима канала, а также из данных о старшинстве и
 количестве (1,2) байт данных, которые будут записаны или прочитаны в
 канале. Если затем записать в порт 4@h нужное число байт данных в
 нужной последовательности, то эти данные будут восприняты как константа
 пересчета канала N@. Если же прочитать порт 4@h (1 или 2 раза, согласно
 загруженной ранее команде УС), то получится соответствующее количество
 байт (1,2) состояния счетчика канала @, при условии что в этот момент
 счет в канале был остановлен.

    Команда CLC (в байте команды биты 0...3 не используются, биты 4...7
 совпадают со случаем команды УС, а совмещение команд CLC и RBC не
 допускается) позволяет прочитать состояние счетчика одного канала без
 остановки счета путем последующего чтение порта 4@h как описано выше.

    Команда RBC позволяет прочитать состояние счетчиков всех каналов
 одновременно и/или определить SW коды каналов (они здесь не описаны).

              Формат байта команды RBC таймера:

 бит 0 =0;
 бит 1 =1 чтобы работать с каналом 0;
 бит 2 =1 чтобы работать с каналом 1;
 бит 3 =1 чтобы работать с каналом 2;
 бит 4 =0 чтобы читать SW коды каналов согласно битам 1...3;
 бит 5 =0 чтобы читать состояния счетчиков каналов согласно битам 1...3;
 бит 6 =1;
 бит 7 =1;

              Режимы работы каналов таймера:

    Режим 0 - "программный одновибратор".
 После команды УС OUT@=0. Загрузка N@ не влияет на OUT@. Счет разрешен
 при GATE@=1 и запрещен при 0. После отсчета N@ устанавливается OUT@=1.
 Т.о. сигнал OUT@=0 удерживается на время счета N@+1 периодов Ttm. Для
 повторения счета надо перезагрузить N@.
    Режим 4 - "программный одновибратор с задержкой".
 После команды УС OUT@=1. После отсчета N@+1 периодов Ttm сигнал OUT@=0
 устанавливается на время Ttm, затем опять устанавливается OUT@=1.
 Остальное совпадает с режимом 0.
    Режим 1 - "аппаратный одновибратор".
 Счет перезапускается по фронту 0->1 сигнала GATE@, сигнал OUT@=0 во
 время счета N@ периодов Ttm, после чего OUT@=1. Для перезапуска счета
 не требуется перезагрузки N@. Перезагрузка N@ во время счета не влияет
 на текущий счет, но влияет на последующие **).
    Режим 5 - "аппаратный одновибратор с задержкой".
 GATE@ действует также как в режиме 1, а изменение сигнала OUT@ во время
 счета совпадает с режимом 4.
    Режим 3 - "генератор импульсов".
 Канал @ работает как делитель частоты Ftm на N@. Hа выходе OUT@
 формируются прямоугольные импульсы 010101... со скважностью около 2.
 При четных N@ длительности полупериодов совпадают и равны N@/(2*Ttm),
 при нечетных N@ : OUT@=1 в течении времени (N@+1)/(2*Ttm),
                   OUT@=0 в течении времени (N@-1)/(2*Ttm).
 При GATE@=0 счет приостанавливается (а сигнал OUT@ устанавливается=1),
 при 1 - возобновляется. Перезапуск счета производится автоматически по
 достижении 0. Перезагрузка N@ во время счета не влияет на текущий счет,
 но влияет на последующие **).
    Режим 2 - "генератор коротких импульсов".
 Канал @ работает как делитель частоты Ftm на N@. Hа выходе OUT@
 формируются прямоугольные импульсы 011110111101111... со скважностью
 около 1 : OUT@=1 в течении времени (N@-1)/Ttm,
           OUT@=0 в течении времени     1/Ttm.
 При GATE@=0 счет приостанавливается (OUT@=1), при 1 - возобновляется.
 Перезапуск счета производится автоматически по достижении 0.
 Перезагрузка N@ во время счета не влияет на текущий счет, но влияет
 на последующие **).
     Hапомню еще раз, что когда OUT2=1, то изменение состояния сигнала
 SPKRdata (бит 1 порта 61h) проходит на спикер, а когда OUT2=0 - то не
 проходит. Т.е. при @N>>1 практически всегда проходит.
---
 **) это может быть не так для таймера 8253 и/или в др. случаях...

---
 * Origin: *Vadim Madgazin*Tashkent*Meloman Station* (2:5085/3.2)


