ТРАКТАТ о PC-SOUND или ТЕХНОЛОГИЯ КАЧЕСТВЕННОГО ВЫВОДА ФОНОВОГО ЗВУКА НА IBM PC. (C) Авторские права: Вадим Р. Мадгазин, 1992, 1993. (C) Copyright Vadim R. Madgazin, 1992, 1993. Все права сохранены. All rights reserved. E-mail: vm(at)vmgames.com Если специально не оговорено иное, то ниже везде под PC будут подразумеваться IBM PC XT/AT - совместимые компьютеры. Краткое содержание. В настоящем трактате рассмотрены причины, мешающие использовать компьютер IBM PC для фоновой работы программного кода в ОС MS DOS, способного выводить произвольный звук на спикер PC и/или на другое достаточно простое устройство звукового выхода. Предложен ряд программных методов, позволяющих ощутимо уменьшить отрицательное влияние этих причин на качество звука, а именно: -определение искаженных участков звука путем измерения реального времени и отбрасывание этих участков; -использование программно-аппаратных прерываний последовательного порта вместо аппаратных прерываний системного таймера; -использование специфических приемов работы с таймером для вывода звука на спикер при помощи преобразования частоты в напряжение вместо метода широтно-импульсной модуляции. К работе приложен демонстрационный пакет программ мультимедиа- плейера для DOS, позволяющий озвучивать произвольные анимационные ролики. Изложенные результаты и идеи являются составной частью новой технологии SoundMedia, технологии программного создания и фонового вывода качественного звука на IBM PC. Эта технология имеет практическую ценность для MultiMedia и любых других программных продуктов, использующих звук и расчитанных на широкую эксплуатацию на IBM PC разных моделей и программных платформ. Благодарности. Выражаю свою искреннюю признательность за отдельные замечания и дополнения по настоящему тексту, а также за некоторые сведения и ценные мысли по ряду смежных вопросов, высказанные мне по сетевой переписке - и просто за содействие и поддержку : Вадиму Зубанову (Vadim Zubanov, 2:5085/3@fidonet) Славе Филимонову (Slava Filimonov, 2:469/33@fidonet) СОДЕРЖАНИЕ. ТЕХНОЛОГИЯ КАЧЕСТВЕННОГО ВЫВОДА ФОНОВОГО ЗВУКА НА IBM PC. 1. Аппаратура и методы вывода звука на PC. 2. Искажения звука различными процессами PC. 3. Методы устранения и маскировки искажений. 3.1. Использование меток реального времени. 3.2. Использование нестандартных прерываний. 3.3. Таймер и методы вывода звука на спикер PC. 3.4. Комбинации нестандартных программных методов. 3.5. Изменение аппаратной схемы возбуждения спикера. 4. Заключительные замечания. SoundMedia. Приложение. П.1. Список терминов, сокращений и обозначений. П.2. Программирование таймера и логика спикера PC. П.3. Методы малобитного преобразования звука. П.4. Пакет программ Multi Media Player. РИСУНКИ И ТАБЛИЦЫ. 1. Рис. 1 Нелинейные искажения дискретизованного сигнала при нарушении условий теоремы отсчетов и их уменьшение. Рис. 2 Вывод звука на спикер PC методом ШИМ-ЦАП. 2. Рис. 3 Экранирование прерывания вывода звука IRQs. Табл. 1 Интервалы времени между соседними IRQ0. 3.3. Рис. 4 "Стандартная" схема выхода на спикер PC. Рис. 5 Зависимость сигнала на спикере PC от сигнала SPKRout. Рис. 6 Зависимость среднего напряжения на спикере от константы пересчета канала 2 таймера. 3.4. Табл. 2 Сводные характеристики методов вывода звука. 3.5. Рис. 7 Улучшенная блок-схема возбуждения спикера. -=*=- ТЕХНОЛОГИЯ КАЧЕСТВЕННОГО ВЫВОДА ФОНОВОГО ЗВУКА НА IBM PC. 1. Аппаратура и методы вывода звука на PC. Звуком обычно считаются не слишком маломощные колебания давления воздуха в спектре слышимых человеком звуковых частот (ЗЧ), в среднем от 16-20 до 16000-20000 Герц (колебаний в секунду). На языке формул произвольный звук S является непрерывной функцией времени T ограниченного спектра : S=S(T). Общеизвестным источником звука является громкоговоритель, на который обычно подается переменное напряжение от усилителя мощности с достаточно низким выходным сопротивлением. Чтобы услышать звук от PC требуется таким образом создать напряжение в ЗЧ спектре либо на клеммах встроенного громкоговорителя (PC спикера), либо на выходе какого-то добавочного устройства (назовем любое из них Устройством Звукового Вывода, УЗВ). Единственный штатный источник ЗЧ напряжения, подаваемого на спикер PC - это 2-й канал таймера, задуманный первоначально для генерации простого меандра (прямоугольного сигнала со скважностью Q=2, Q - это отношение периода следования к длительности импульса). Этот набор простых сигналов недостаточен для передачи звука произвольного содержания. Хотя существуют специальные УЗВ на платах расширения, содержащие в себе устройства для профессионального синтеза звука (например Proteus-эмуляторы), многих людей может заинтересовать возможность получения достаточно качественного звука при помощи более простой аппаратуры или каких-нибудь программных методов. Так как PC - это дискретное устройство ограниченного быстродействия, то эти методы состоят в общеизвестной временно'й и амплитудной дискретизации напряжения непрерывного сигнала, а аппаратура - это выходной цифро-аналоговый преобразователь (ЦАП), либо несколько ЦАПов для стерео, квадро и прочих систем. Если вас интересует теория данного вопроса, обратитесь к учебнику по радиоэлектронике с описанием теоремы отсчетов Котельникова. Здесь я только отмечу, что для качественного вывода звука в полосе частот f необходимо иметь частоту его дискретизации Fd>=2*f. Что касается разрядности цифрового выхода, то для нормального понимания речи диктора иногда достаточно иметь ее в 1 бит (при f=3 кГц), однако для прослушивания высококачественного звука требуеться разрядность в 16 и даже в 24 бита (при Fd=40...60 кГц). Музыкальные синтезаторы среднего качества типа Yamacha имеют разрядность ЦАПов в 12 бит. Практика показывает, что можно добиться достаточно приемлемого (для "рядового" пользователя PC) качества звука на 8...6 битном ЦАПе. Математически дискретизацию звука можно представить заменой непрерывной функции времени 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) от постоянного выполнения старых системных операций. Некоторого дополнительного внимания требует выбор частоты Fd. Обычно здесь идут на компромисс между качеством звука и максимальным быстродействием PC. Ограничение на быстродействие часто настолько велико, что заставляет выбирать предельно простые методы программного синтеза звука. Тема синтеза звука слишком обширна и не может быть рассмотрена мной здесь (по этому поводу можно обратиться к исходным текстам программ-трекеров или программы Меломан). Отмечу здесь только на мой взгляд две немаловажные детали. Многие звуковые программы фактически устанавливают Fd вслепую, чем подвергают PC риску зависания, хотя не так трудно измерить Fd max, при которой только-только начинается такое зависание (см в П.4. функцию Testftact() программы mmplay.c). Также наблюдается большое количество негармонических призвуков при извлечении нот верхнего диапазона большинства звуковых программ. Это происходит вследствии нарушения условия ограниченности спектра дискретизуемого сигнала при его восстановлении согласно теореме отсчетов: при извлечении верхних нот все больше и больше гармоник звука содержится выше запретной границы Fd/2 и возникают паразитные разностные частоты. Идеальное решение состоит в предварительном сглаживании исходного виртуального сигнала ПЕРЕД его дискретизацией и подачей на ЦАП неким фильтром НЧ с частотой среза Fd/2 и бесконечной крутизной (ПОСЛЕ ЦАПа то же самое можно сделать с выходным аналоговым сигналом - тогда он будет совпадать с исходным и гармоник Fd в нем не будет). Практически же достаточно хоть как-то уменьшить крутизну фронтов дискретизуемого сигнала, это пропорционально уменьшит призвуки. Чтобы понять, что это возможно - следует разобраться в деталях программного формирования звука ноты. Соответствующие алгоритмы и код можно извлечь из пакета Meloman, ver. 1.71x, а здесь я приведу лишь иллюстративный рисунок. ^ Исходный виртуальный сигнал с богатым спектром | | <------------> Период сигнала Fs | ........ ........ ........ ........ ...... | : : : : : : : : : | : : : : : : : : : |..: :......: :......: :......: :......: +--+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-> Время ^ Дискретизованный сигнал | | Период сильного паразитного НЧ - призвука f | <----------------------------------------> | ............. ....... ....... ............. .. | : : : : : : : : : | : : : : : : : : : |..: :.....: :.....: :.....: :.....: +--+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-> n n+2 n+4 n+6 n+8 Время Номер периода частоты дискретизации звука Fd ^ Спектр дискретизованного сигнала | | | НЧ призвук I<----->| | | I f | | | Сигнал I | Фантом Частота +-------+-----------------+---+---+-------------------------+----> f Fs Fd/2 Fd ^ Исходный сигнал со сглаженным спектром | | <------------> Период сигнала Fs | /\ /\ /\ /\ | / \ / \ / \ / \ / | / \ / \ / \ / \ / | \/ \/ \/ \/ \/ +--+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-> Время ^ Дискретизованный сигнал | | Период биений f между сигналом и его фантомом | <----------------------------------------> | +-----+ ______ +-----+ | : : +-----______ : : : : | : : :_____: +------ : : :_____: | +-----+ +-----+ +--+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-> n n+2 n+4 n+6 n+8 Время Номер периода частоты дискретизации звука Fd ^ Спектр дискретизованного сигнала | | I<----->| | I f | | . Сигнал I | Фантом Частота +-------+-----------------+---+---+-------------------------+----> f Fs Fd/2 Fd Рис. 1 Нелинейные искажения дискретизованного сигнала при нарушении условий теоремы отсчетов и их уменьшение. ------------------------------------------------------------ Интересно, что простейший "псевдо"-ЦАП делается прямо из спикера PC. Сейчас общеупотребимым является использование 2-го канала системного таймера в режиме 0 (или 1, см. П.2.), когда он генерит при каждом перезапуске (происходящем с частотой Fd) прямоугольный импульс с длительностью, пропорциональной очередному отсчету звукового сигнала. Фактически таймер в этом режиме вкупе с прерываниями IRQs производит широтно-импульсную модуляцию (ШИМ) несущей Fd звуковым сигналом, который демодулируется на спикере PC из-за естественной инерционности его диффузора. Все вышесказанное иллюстрируется рис. 2 и нижеследующем участком кода ПОП IRQ0. ^ Код дискретизованного сигнала | ............. | : :............ | : :............ | ............: | ............: +--+-----------+-----------+-----------+-----------+-----------+-> ^ ШИМ напряжение на спикере | ... ..... .......... ........ ...... | : : : : : : : : : : | : :.........: :.......: :..: :....: :....... +--+-----------+-----------+-----------+-----------+-----------+-> ^ Давление звука спикера . | .. / \ . | / \ / \ / \ | . / \./ \./ \ | . / \ / \ | / \........./ \...../ \ +--+-----------+-----------+-----------+-----------+-----------+-> n n+1 n+2 n+3 n+4 Время Номер периода частоты дискретизации звука Fd Рис. 2 Вывод звука на спикер PC методом ШИМ-ЦАП. ------------------------------------------------- Вот участок соответствующего кода на СИ (TC++/TASM) : ----------------------------------------------------- void interrupt Timer_speaker(void) //ПОП IRQ0 с выводом звука на спикер PC в режиме 1 таймера; { //возврат сигнала GATE2 в 0 для подготовки //канала 2 таймера к новому перезапуску : asm { in al,61h //чтение текущего состояния битов порта 61h; and al,11111100b or al, 2 //для установок SPKRdata=1, GATE2=0; out 61h,al //запись этих установок в порт 61h; } //здесь в регистре BL должен формироваться //очередной отсчёт звукового сигнала : ... asm { mov al,10010010b out 43h,al //запись команды УС в таймер; mov al,bl inc al //BL=0 дает сбой вывода! out 42h,al //запись сигнала в виде константы пересчета N2; //установка сигнала GATE2 в 1 для //перезапуска канала 2 таймера : asm { in al,61h and al,11111100b or al, 3 //для установок SPKRdata=1, GATE2=1; out 61h,al //перезапуск счета по фронту 0->1 GATE2; } //конец аппаратного прерывания, команда EOI : asm { mov al,20h; out 20h,al } } Такой ШИМ ЦАП имеет ограниченную разрядность, (6...7 бит при Fd=20...10 кГц) и высокий уровень несущей частоты, при Fd<10 кГц он быстро становится надоедливым свистом, если не применять специальных методов обработки выводимого сигнала, типа вычитания скользящего среднего. "Настоящие" ЦАПы устроены по-другому, они содержат запоминающий цифровой регистр и электрическую схему, преобразующую код этого регистра в аналоговое напряжение. Простейший из таких ЦАПов использует для себя 8-битный регистр данных парралельного порта PC (порта принтера), он общеизвестен под названием Ковокс и может быть сделан фактически из одного разьема и нескольких резисторов (что обойдется вам порядка $2), хотя при этом его эффективная разрядность упадет до 4...6 бит из-за разброса выходного напряжения на разных битах порта принтера. Если собрать ЦАП на чипе, то можно использовать дополнительно 4 бита 8-разрядного регистра управления принтером и получить нечто вроде 12-битного ЦАПа. Другие параметры ЦАПа можно получить, если сделать его на плате самостоятельно или приобрести УЗВ в виде плат Sound Blaster Pro, Pro Audio Spectrum, PAS 16, Gravis UltraSound... (платы типа Adlib имеют только встроенный FM-синтезатор, который не предназначен для штатного вывода произвольного звука, поэтому они отсутствуют в этом списке плат с ЦАПами). Способ вывода произвольного звука во всех УЗВ для PC (кроме спикера) один - передача цифровых данных сигнала в УЗВ с посылкой их на встроенный ЦАП. Таким образом, различие только в методах передачи данных в УЗВ, их и рассмотрим далее. Простейший и самый "ходовой" метод - прямая передача в УЗВ путем записи в его регистры через порты PC. В более изощренных и дорогостоящих УЗВ используется метод буферизации звуковых данных перед выводом их на ЦАП (наподобии буферизации символов в принтере) с использованием буфера в оперативной памяти PC (что требует использования прямого доступа в память, ПДП) или же буфера в памяти самого УЗВ. Такие УЗВ в принципе позволяют обходиться без использования IRQ0, однако и здесь надо заботится о периодическом обновлении содержимого звукового (FIFO) буфера. По поводу использования ПДП в УЗВ платах надо отметить, что не всегда в PC имеется достаточное количество каналов ПДП, чтобы достичь удобства при одновременной работе такой платы и всех других устройств, использующих ПДП. То же самое относится и к прерываниям, которые УЗВ плата обычно "отнимает" у достаточно бедной PC. Забегая вперед отмечу один (возможно несколько теоретический) общий недостаток любого УЗВ PC: если какое-то устройство или программа будет использовать ПДП в режиме блочной передачи (например память-память), то на время Tblc этой передачи работа любого канала (с ПДП и без ПДП !) перекачки данных в УЗВ будет приостановлена и если в УЗВ нет внутреннего буфера - звук прервется на все время Tblc. Кроме того, если для вывода звука требуется периодическое обращение к диску в многозадачной системе, то это может послужить еще одной причиной остановки звука с ожиданием освобождения диска другой задачей (пример - SB Pro, проигрывающий длинные WAV-файлы из Windows). Таким образом, по-настоящему неискаженным и непрерывным может быть звук только у УЗВ со встроенным FIFO буфером достаточного размера, чтобы запомнить звуковые данные в течении максимального времени блокировки с запасом, и если вы хотите получить на PC самый высококачественный звук, то вам следует выбрать звуковую плату с большим встроенным FIFO буфером данных и высокоточным ЦАПом и чтобы все это работало с частотой Fd>=44 кГц... Если для вас получение такой "игрушки" не представляет проблемы и вас не трогают проблемы других, менее счастливых, но гораздо более многочисленных пользователей PC, то читать дальнейшее изложение будет излишним, так как оно посвящено описанию искажений звука более простыми и распостраненными УЗВ (без буферизации и ПДП) и приемов программирования для устранения и маскировки этих искажений, которые были найдены мною в мае-июне 1992г при решении задачи звукового сопровождения анимационных роликов на "стандартной" IBM PC AT (и стоили мне неплохого 40 Мб винчестера, не считая 6-недельной напряженной работы)... 2. Искажения звука различными процессами PC. *) ------------------------------------------------------------------ *) Все сказанное в данном разделе необходимо учесть при применении PC в любых системах реального времени. Практически с первых же шагов написания своих звуковых программ на PC я (как и многие другие) столкнулся с неприятным фактом довольно плохого качества произвольного звука, особенно при выводе его на спикер. Достаточно фундаментальные процессы в PC приводят к наполнению звука сильным шумом и треском или по крайней мере к нестационарному искажению тональности звука, который иногда становится похож чуть ли не на блеянье барашка... Чтобы убедиться, что я не слишком сгущаю краски, послушайте хотя бы звук популярной программы Scream Tracker в DOS shell, производя обычные манипуляции типа чтения или редактирования текста в Нортон Коммандере... Инсталлируйте драйвер спикера или Ковокса в Windows 3.1 и послушайте не слишком короткий WAV-файл с двигающимся в это время курсором мыши... Стоит ли говорить о таких убийственных для звука операциях как использование дискового кеша в HI-memory, запись данных на виртуальный диск или непрерывное чтение жесткого диска при работе анимационного плейера (по крайней мере для не слишком быстрых PC)... На сегодняшний день я не знаю ни одной программы, которая при генерации фонового звука позволяет избежать вышеописанных искажений без того, чтобы применять звуковую аппаратуру с буферизаций данных. То есть практически нет никакой возможности использовать спикер PC, простой Ковокс или что-то в этом роде для прослушивания BG звука со сколько-нибудь приемлемым качеством. Мои слова подтверждаются в частности тем, что в описании фирменного драйвера Ковокса (Covox Speech Thing) для Windows 3.1 сказано, что Windows не позволяет работать НИ ОДНОЙ программе во время генерации звука Ковоксом. Ну и по моему личному мнению, драйвер спикера не был включен в коммерческую версию этой мультимедиа оболочки ДОС в основном из-за плохого качества его звука, а не из-за того, что он слишком часто подвешивал PC. В чем же причины искажений звука в PC ?...Все дело в прерываниях ! Общеизвестно, что работа PC буквально пронизана самыми разными программными и аппаратными прерываниями, во время которых ранее выполнявшийся процесс приостанавливается и начинает выполняться другой процесс (программа обработки прерывания, ПОП), после окончания которого продолжается выполнение прерванного процесса. Причем, многие из ПОП (часто слишком) критически относятся к возможности прерывания их длинных по времени кусков другими ПОП и поэтому буквально пичкают свой код инструкцией CLI запрещения аппаратных прерываний, к которым относится наше любимое IRQs. То есть, в PC достаточно часто случаются ситуации, когда очередное звуковое прерывание IRQs должно произойти, но пока не может из-за вышеописанного запрета, так как в данный момент выполняется некий участок кода переднего плана. Когда он окончится - происходит IRQs, задержанное от верного момента на некоторое время, которое для простоты можно назвать временем экранирования IRQs. Сказанное иллюстрируется нижеследующим рисунком. ^ Разрешение аппаратных прерываний. | разрешены |----------- ----- --- ------ ---------------- | | -- ---- ----- ----------- запрещены +--+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-> ^ Начало прерывания IRQs. | | промежутки экранирования IRQs | <-> <---> <--------> | I I I I I I II I I I | I I I I I I II I I I +--+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-> n n+1 n+2 n+4 n+6 n+8 Время Номер периода частоты дискретизации звука Fd Рис. 3 Экранирование прерывания вывода звука IRQs. --------------------------------------------------- Забегая вперед отмечу также что код обработки любого аппаратного прерывания IRQx не будет прерван IRQs с более низким приоритетом, пока ПОП IRQx не пошлет в контроллер прерываний команду EOI, то есть если выбрать IRQs не с самым высоким приоритетом (IRQ0), то время экранирования всех ПОП с более высоким чем у IRQs приоритетом может достигнуть полной длительности этих ПОП. Таким образом то и дело в равномерное течение IRQs вносятся временны'е искажения, эквивалентные фазовой модуляции (ФМ, при сильной ФМ ее удобнее рассматривать как частотную, ЧМ) сигнала некоторым нестационарным случайным процессом. В случае небуферизованного вывода звука на аппаратный ЦАП эти искажения так и остаются ЧМ и слышаться порой как дрожаще-завывающие стоны плохо смазанного или расбалансированного катушечного магнитофона. Если же звук выводится на спикер при помоши ШИМ, то искажения времени IRQs превращаются также в искажения, близкие к общей глубокой амплитудной модуляции (АМ) сигнала, которая намного заметнее на слух чем ЧМ и слышиться как треск, даже когда отсчеты исходного сигнала не меняются по величине. Насколько велики искажения экранирования ? Выше описано как сделать субъективную оценку. Для получения каких-то количественных данных я написал программу (см П.4, ta120.c) временно'й трассировки IRQ0 (методом меток реального времени) и вот объединение худших результатов, которые она дала на нескольких проверенных мной PC AT 286 10...16 МГц при установленной частоте прерываний таймера Fi=11932 Гц, в 100 раз ниже частоты тактирования системного таймера Ftm. В нижеследующей табл. 1 показаны соответствующие цифры интервалов времени между соседними IRQ0 (в единицах Ttm=1/Ftm=0.84 мкс) на фоне различных FG процессов (переднего плана). Теоретически эти интервалы при отсутствии искажений должны быть равны Ftm/Fi=100, но практически получается более-менее размытое их распределение вблизи некоторого среднего значения (иногда очень причудливое). По строкам табл. 1 меняются условия измерения трассы, а по столбцам приведены Min/Max/среднее (Aver) значение и среднеквадратичное отклонение (Sigma) этого Aver для интервалов между соседними 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 75 125 100 4.4 cprintf(); цикл форматного вывода на консоль 4 56 136 100 5.0 int 10h,AX=1010h; запись 1-го регистра палитры 5 75 125 100 12. int 10h,AX=1012h; запись 256 регистров палитры 6 55 501 100 7.4 int 09h; обработка клавиатуры; разрешено IRQ1 7 51 300 102 24. kbhit(); только проверка нажатия клавиши на TC (многократный перехват IRQ1) 8 57 301 100 8.3 движения мыши; разрешено mouse IRQ (здесь IRQ5) 9 51 201 100 2.9 lseek(); только позиционирование Hard диска 10 50 531 112 66. read(); чтение Hard диска блоками по 5000 байт 11 70 131 100 1.2 lseek(); только позиционирование RAM диска 12 70 716 295 198. read(); чтение RAM диска блоками по 5000 байт (драйвер ramdrive.sys) 13 51 825 294 198. read(); чтение Hard диска блоками по 5000 байт (драйвер smartdrv.sys) ----------------------------------------------------------------------- Табл. 1 Интервалы времени между соседними IRQ0. ------------------------------------------------- Разумеется, хорошо бы для полноты картины привести примеры трасс, гистограммы и даже спектры флуктуаций IRQ0 для разных моделей и комплектации компьютеров а также проверить некоторые другие процессы (прежде всего ПДП в различных режимах), однако и данная таблица достаточно наглядно характеризует поведение PC. Следует добавить также, что спектр почти всех флуктуаций лежит в хорошо слышной области ЗЧ. Несколько слов о конкретных цифрах. Ненуливое Sigma для пустого цикла и чуть большее - для записи в видеопамять (строки 1-2 табл. 1) получаются из-за того, что прерывание IRQ0 не может произойти, пока очередная команда процессора не выполнится полностью. Клавиатура (при учете многократного перехвата ее прерываний) и особенно мышь (строки 6-8 табл. 1) обычно являются достаточно сильными источниками искажений звука. В случае операций с мышью например иногда встречаются задержки IRQ0 на 300*Ttm=0.250 мс, причем средняя девиация частоты составляет 8%, в то время как даже 1%-я девиация звука хорошо слышна (но не для случаев строк 1-2 табл. 1, так как спектр этих девиаций целиком находится вблизи Fi и фактически тонет в полосе самой несущей частоты). В случае чтения винчестера (строка 10) максимальная задержка прерывания составит уже 0.45 мс, а девиация 66%, что весьма значительно (хотя бывают жесткие диски и с лучшими характеристиками). При работе с виртуальным или кэшированным диском (строки 12-13 табл. 1, драйверы himem.sys, ramdrive.sys, smartdrv.sys) происходит полный "распад" звука, так как (если смотреть трассу) временами частота IRQ0 просто падает в несколько раз, испытывая также более мелкие колебания. Следует отметить, что влияние операций с HI-memory на задержку прерываний сильно зависит от быстродействия PC и частоты прерываний Fi. При увеличении быстродействия свыше некоторого порогового значения (или при соответствующем уменьшении частоты Fi) происходит почти скачкообразное уменьшение задержек. Если погонять возле такого порога мой мультимедиа-плейер, то впечатление такое, что еле дышащая сначала PC буквально с цепи срывается, когда порог пройден (у PC 286 10 МГц порог Fi около 5 кГц). Можно заметить также, что сильные искажения равномерности IRQ0 сопровождаются также уменьшением средней частоты этих прерываний, так как часть их не может произойти по нескольку раз подряд. При повышении Fi до 24 кГц происходит некоторое не слишком значительное изменение конкретных цифр табл. 1. В общем, легко можно видеть, что прерывания в PC испытывают задержки от 10 мксек до 0.7 мсек, в зависимости от оборудования и типа процессов переднего плана PC, а наиболее сильно влияют на них операции с виртуальным диском, жестким диском, мышью. Другие устройства PC (клавиатура, модемы, сети, сканеры...) также могут приводить к большим задержкам. Некоторые программы перехватывают прерывания DOS/BIOS и вешают на них свои ПОПы, что иногда приводит к значительному изменению данных табл. 1 - в любую сторону. В этом случае даже обработка самого IRQ0 может сильно экранировать все остальное. А теперь посмотрим, нельзя ли как-нибудь улучшить эту прискорбную ситуацию. 3. Методы устранения и маскировки искажений. Простейшим способом избавления от вышеописанных искажений является запрет всех аппаратных прерываний (кроме IRQs) и программирование без употребления всех экранирующих IRQs функций во время генерации звука. Если одновременно вам необходимо все-таки реагировать на некоторые другие прерывания (хотябы на IRQ1 для чтения сканкодов нажатых клавиш), то все соответствующие ПОП-ы надо переписать для минимизации в них времени экранирования IRQs. Чем больше экранирующих IRQs процессов понадобиться использовать, тем больше сложностей возникает. В запале борьбы с функцией чтения жесткого диска read() я в свое время решил обойти DOS и стал экспериментировать с использованием BIOSa, но жестоко поплатился. Код древней версии BIOSa моей тогдашней PC видимо не был совместим с новеньким IDE винчестером, что привело его к полному выходу из строя... В общем случае, если необходимо эксплуатировать звуковую программу в фоновом режиме под любым софтом, подход изменения ПОП приведет к тому, что придется переписать чуть ли не весь код операционной системы, позаботиться в отдельности о каждом типе жестких дисков и некоторой другой аппаратуры... Чем труднее оказывается решение какой-то конкретной проблемы, тем полезнее бывает взглянуть на нее с абстрактной стороны. Посмотрим, что может получиться при таком подходе в нашем случае для устранения искажений фонового звука ЛЮБЫМИ процессами PC, а также для устранения какого-то влияния ЗВУКА на сами эти процессы (см раздел 3.2). 3.1. Использование меток реального времени. Очевидно, что в общем случае нам придется смириться с наличием в PC большого количества экранирующих IRQs процессов. Что же делать ? Известная восточная мудрость гласит - "Если гора не идет к Магомету, то Магомет идет к горе". Можно ли - манипулируя теперь уже не процессами PC, а самим выводимым звуковым сигналом - добиться уменьшения искажений звука ? Оказывается - да ! Первое, что пришло мне в голову, как рецепт уменьшения паразитной ЧМ сигнала, видимо некоторым образом соответствовало психофизиологическим особенностям слуха человека - [псевдо-]инерционностью восприятия звука. Вам никогда не приходилось слушать быстрое чередование нот одноголосной мелодии (например, в старинной программе Pianoman) ? При некоторой частоте их перебора возникает ощущение одновременного звучания нескольких нот, как в аккорде ! Дело по-видимому в том, что слух человека продолжает воспринимать звучание в течении нескольких миллисекунд после его исчезновения, так же, как глаз сохраняет картинку (правда последний - в десятки раз дольше). А может происходит что-то другое, но похожее... Вот сам рецепт: если мы просто будем выбрасывать из сигнала те его куски, которые попадают в любые периоды времени экранирования IRQs, то звук очистится от ЧМ искажений и будет на слух гораздо более похож на оригинал, правда с большим количеством коротких беззвучных участков, хаотически разбросанных по времени. Но из-за [псевдо-]инерции слуха эти беззвучные участки будут "замаскированы" предыдущими участками нормального звучания. На языке радиотехники можно сказать, что такой метод эквивалентен внесению в исходный сигнал (вместо ЧМ искажений) полосовых АМ искажений. Почему полосовых ? Потому. Если на периоды экранировки IRQs выход ЦАПа оставлять без изменений (это делается в любом ЦАПе, кроме "псевдо ЦАПа" на ШИМ), то при средней длительности экранирования te полностью исчезает только ВЧ часть исходного сигнала, а НЧ часть с f<=1/te подавляется в меньшей степени, тем меньшей, чем меньше ее частота. Так как характерное время экранирования te=0.2...0.5 мс, то обычно в сигнале остаются слабо модулированной (почти неискаженной) НЧ область до 1-3 кГц, т.е. обычно наиболее сильная часть спектра. Кроме того, спектр АМ искажений значительно у'же спектра ЧМ искажений, поэтому превращение ЧМ в АМ положительно сказывается на качестве звука. Для справки отмечу например, что человек замечает изменение частоты на 3 Гц вблизи 1000 Гц (0.3%), в то время как для силы звука его чувствительность равна 2 дБ (20%). Как осуществить такую маскировку искажений звука на практике ? Очевидно, что для этого нужно знать точное реальное время в любой момент, тогда в начале каждого IRQs можно будет определить, какой же отсчет сигнала Si(ti) надо выводить на ЦАП на этот раз - тот, у которого ti ближе всего к реальному времени T. Более изощренными методами можно попытаться достичь еще лучших результатов - например выводить линейную интерполяцию из двух соседних отсчетов, или даже пытаться сгладить слишком большие разрывы в уровне сигнала до и после очередного экранирования, что может оказаться весьма полезным. Где же в PC взять "метки времени" ? Для этого можно использовать показания системного таймера, так как его точность весьма высока. Как известно, микросхема системного таймера в 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 программы. Например - программы реального времени (и др. - см ниже) - меняют N0. Звуковые же программы (в частности при ШИМ-ЦАП на спикер) - и даже некоторые BIOS при переполнении буфера клавиатуры - меняют N2. Поэтому для адекватного определения реального времени нам нужен гибкий алгоритм, пытающийся следить за возможным изменением N в рабочем канале. Видимо, если не стоит задача вывода качественного звука НА СПИКЕР PC, то лучше всего пожертвовать звучанием спикера полностью (за исключением однобитного метода М1Б, см разд. 3.3) и "наглухо" использовать канал 2 только для контроля реального времени, корректируя при каждом IRQs любые FG попытки изменения константы N2 или режима работы канала 2 (см разд. 3.3, 3.4). Ошибка в знании точной величины "константы" N при ее смене может привести к значительным погрешностям определения T. Поэтому для программ защищенного режима можно посоветовать перехватывать любые корректировки N. В других случаях можно попытаться каждый цикл приближения содержимого канала vc к нулю продлевать до переполнения канала и если будет обнаружено, что первое большое значение vc (Vc) либо превышает N, либо значительно меньше N, то это должно служить сигналом какого-то изменения N->M, причем M нельзя определить быстро и точно (M равно max(Vc), но не равно первому попавшемуся Vc). Тогда необходимо либо восстановить старое значение N (что плохо), либо перезаписать N=Vc, что будет близко к M (а следовательно почти не помешает FG процессам), но теперь мы будем знать новое значение N абсолютно точно. Может показаться, что я хочу слишком усложнить жизнь тому, кто будет делать фоновый звук на PC. Но это не так. Если вам надо, чтобы ваша программа давала нормальный фоновый звук и при этом не влияла на работу процессов переднего плана, то не стоит пренебрегать нуждами последних менять N, по крайней мере в канале 2 ! Частота IRQ0 должна меняться так, как надо другим ! (см разд. 3.2) Интересно, что методика корректировки номера выводимого отсчета по реальному времени в принципе позволяет обходиться вообще без использования прерываний для вывода звука, по крайней мере для генерации звука не BG, а FG программой. Для этого можно использовать простой программный цикл, в котором есть участок измерения времени и вывода очередного отсчета (он должен протекать с запрещением всех аппаратных прерываний). Такой же подход, но без измерения времени, дает плачевный результат, так как даже элементарное чередование банков оперативной памяти влияет на частоту генерируемого тона - она "плывет". Еще одна особенность достойна упоминания - метки времени позволяют воспроизводить звук с любой частотой дискретизации ВЫВОДА Fv, не обязятельно совпадающей с Fd, которая относиться к исходному сигналу. Для верной скорости воспроизведения необходимо только учесть корректирующий время коэффициент Fv/Fd. Если еще раз взглянуть на строку 12 табл. 1, то станет ясно, что такая гибкость метода далеко не лишняя, так как на практике встречаются случаи сильного, частого и непредсказуемого для фоновой звуковой программы колебания Fd. Это же свойство метода может также облегчить алгоритм воспроизведения сигнала, Fd которого (для сжатия данных) адаптивно меняется в зависимости от ширины спектра сигнала. Приведу еще один, достаточно экзотический способ определения реального времени при помощи задействования НЕСКОЛЬКИХ каналов таймера. Если выбрать константы пересчета каналов N0, N1, N2 взаимно простыми числами, то ОДНОВРЕМЕННО измеряя значения содержимого всех трех каналов vc0(ti)...vc2(ti) в моменты времени ti (i=0,1,2...) можно точно определить любой промежуток времени Ti=ti-t0, пока Ti 0 15 30 10 25 5 20 3.2. Использование нестандартных прерываний. С учетом сказанного в предыдущем разделе о приоритете FG установок N0 над BG звуком становится ясно, что использование IRQ0 в качестве IRQs является на самом деле весьма нежелательным на PC. Даже в MS DOS есть ряд программ, которые конфликтуют с попытками ускорить прерывания таймера до величин многих килогерц. Это например некоторые из Norton Utilities (SI сначала уничтожает звук, а затем компьютер виснет при измерении CPU speed), Autodesc Animator (частота IRQ0 переустанавливается им примерно в 72 Гц), smartdrv/MS DOS 6.0 (PC повисает при попытке записи на диск с разрешенным кешированием на запись), EMM/QEMM, Desk View, Windows... Да и некоторые другие программы работают неустойчиво, даже при виртуозных вызовах старого обработчика IRQ0 с частотой 18.2 Гц... (а иначе эти программы - и не только эти - просто виснут). Что касается многозадачных операционных систем и оболочек для PC (в стандартной комплектации, так как есть варианты со специальными платами для многозадачной работы), то они по-видимому всегда должны использовать IRQ0 для системных нужд переключения задач, поэтому с их точки зрения использование IRQ0 в качестве IRQs - просто кощунство... В любом случае, полный отказ от манипуляций с ПОП и частотой IRQ0 является хорошим стилем программирования на PC, так как весьма способствует совместимости софта. Это следует понять раз и навсегда. Вы же не используете сплошь и рядом доступ к жесткому диску на физическом уровне (через программирование его контроллера), так почему же вам надобно лезть в системный таймер ? Факт, что последнее сделать намного проще - плохой аргумент для того, чтобы делать это на самом деле ! Попробуем теперь определить, действительно ли нам так необходимо использовать прерывания таймера для вывода отсчетов звукового сигнала, следующих с частотой многих кГц (обычно 4...40) ? Если мы хотим получить фоновый звук, то какие-то регулярные прерывания для него иметь надо, хотябы и не столь высокостабильные, как IRQ0 (все равно эффекты экранирования вносят сильные искажения в их равномерность). Но есть ли в PC кроме таймера другие источники аппаратных прерываний ? Конечно есть ! Это например прерывания клавиатуры IRQ1, парралельного порта IRQ7, последовательного порта IRQc (IRQ3 или IRQ4), прерывания часов реального времени AT IRQ8. Мне не удалось добиться ни одного IRQ8 на моем компьютере (я искал их не имея ясного описания), но эти поиски еще нужно продолжить. *) ------------------------------------------------------------------- *) позже эта проблема была решена, но оказалось, что предельная частота IRQ8 равна 8200 Гц, что хуже в 2 раза по сравнению с 16500 Гц у IRQc. Про IRQ7 в литературе указано, что не все платы с парралельными портами его поддерживают, поэтому лучше не использовать это IRQ. Чтобы вызвать IRQ1 я посылал в клавиатуру AT разные команды и получал в ответ одно-два вожделенных прерывания, через 3-4 и 40-90 миллисекунд после тестовой посылки. Ясно, что ни по частоте, ни по стабильности IRQ1 не годятся для звука. Оставшаяся последняя надежда - на последовательный порт - себя полностью оправдала ! Коммуникационный порт можно использовать в качестве генератора звуковых прерываний ! Как добиться регулярного и частого IRQc без реальной передачи или приема данных com портом в какое-то внешнее устройство ? Нужно запрограммировать порт на генерацию прерывания по пустому регистру передатчика, при этом как только будет снято маскирование соответствующего IRQc, произойдет ОДНО com-прерывание. Если ПОП IRQc сама пошлет какие-то данные в com порт, то когда они будут "переданы" - произойдет еще ОДНО прерывание, и т.д. Возникает нечто вроде автогенератора на цепи с обратной связью. На первый взгляд работа такого программного генератора аппаратных прерываний "не совсем надежна", так как пропуск одного прерывания приводит к остановке генерации. Но этого не происходит на практике. Вот участок соответствующего кода на СИ (TC++/TASM) : ----------------------------------------------------- byte com=0x3f8; //базовый адрес порта, 0x3f8 для com1 на AT; byte comdivzr; //регулятор частоты прерываний; void Installcom(void) //настройка последовательного порта на прерывания; { //выбор частоты com-прерываний : comdivzr=1; //для 1 около 16.5 кГц; //инициализация com-порта : outportb(com+3,0x80); //установка делителя частоты; outportb(com+1,0); //старший байт; outportb(com,comdivzr); //младший байт; //инициализация на самую короткую посылку 5 бит данных, 1 стоп-бит, //без бита чётности (плюс 1 старт бит, итого 7 бит в посылке) : outportb(com+3,0x00); //нельзя делать "выход замкнут на вход", это блокирует прерывания ! //установка "out#2" (надо для разрешения com-прерываний !) : outportb(com+4,0x08); //...0010b, прерывание когда регистр хранения передатчика пуст : outportb(com+1,0x02); } void interrupt Comhandler(void) //процедура обработки com прерываний для вывода звука; { //в самом начале - передача одного байта (0) в com порт для вызова //следующего прерывания : asm { mov al,0; mov dx,com; out dx,al } ... //обработка и вывод звука; } Таким образом IRQc (IRQcom, вместо IRQ0) можно с успехом использовать в качестве IRQs, достаточно стабильного по времени, если помещать код возбуждения следующего IRQc в самом начале обработчика IRQc (так как com порт имеет временны'е параметры, стабилизированные внутренним кварцованным генератором). Скептик может возразить, что com порт не является системным устройством PC (расположен на отдельной карте), может отсутствовать или быть занятым под модем, мышь, локальную сеть... Однако например жесткий диск, монитор или параллельный порт PC - тоже не системные устройства, а последний чаще всего служит для подключения принтера, но тем не менее с успехом используется под ЦАП на Ковоксе. Сейчас стандартом де-факто является PC с двумя com портами, поэтому один из них почти всегда свободен. При неизменной настройке com порта на самую короткую посылку (7 бит) частоту Firqc com прерываний можно менять при помощи comdivzr, делителя частоты кварца компорта (Fc=115200 Гц): Firqc=(Fc/7)/comdivzr=16500/comdivzr На практике Firqc получается на несколько процентов меньше чем по приведенной формуле, так как код вызова следующего IRQc выполняется не мгновенно. Когда comdivzr пробегает значения 1, 2, 3, 4, частота Firqc получается равной примерно 16.5, 8, 5.4, 4, кГц. Для наших скромных целей улучшить качество фонового звука при выводе его на достаточно простые УЗВ этот набор частот можно считать вполне достаточным. Получить промежуточные значения можно меняя длину кодовой посылки. Максимальная частота дискретизации выходного звука Fd может быть увеличена свыше максимума Firqc (16.5 кГц) при помощи одного из трех достаточно хитрых способов: 1.Способ (удвоение, Fd до 33 кГц). В ПОП IRQc выводится не один, а пара отсчетов, первый - в начале ПОП, а второй - после цикла ожидания момента середины времени двух соседних IRQc. Правда 50% времени процессора уйдет только на поддержку обработчика IRQc, поэтому этот способ годится больше для скоростных PC. 2.Способ (удвоение, Fd до 33 кГц). Используются два com прерывания вместо одного (IRQ3 и IRQ4 от com1 и com2), на одинаковой частоте f1=f2=f. При этом нужно осуществить поддержание сдвига фаз в половину периода (1/2f) между IRQ3 и IRQ4, поочередно выводя звуковые отсчеты через ПОП обоих com прерываний. Правда для этого надо иметь два свободных com порта... 3.Способ (учетверение, Fd до 66 кГц !). Используется комбинация обоих вышеописанных способов. В ПОП IRQ3 выводится один отсчет, затем после прохождения 1/4f - второй. Третий отсчет выводится в ПОП IRQ4, затем после прохождения 1/4f - четвертый, и т.д. Временно'й сдвиг междй обоими IRQc должен быть равен 1/2f. Этот способ требует два com порта и 50% времени процессора, но зато позволяет получить самое высокое по частоте качество звука (если забыть об экранировании или устранить его). Некоторое дополнительное ухудшение регулярности фоновых IRQs при использовании IRQc вместо IRQ0 может происходить из-за более низкого приоритета IRQc (3 или 4, причем в AT между уровнями 2 и 3 расположены 8 приоритетов 2-го контроллера прерываний). Это так, и по-видимому, для совместимости это только ЛУЧШЕ. Можно конечно попытаться перепрограммировать приоритеты прерываний, но эта игра не стоит свеч. 3.3. Таймер и методы вывода звука на спикер PC. В предыдущих разделах сказано о том, как избавится от ЧМ искажений экранирования и пагубного использования IRQ0 для звука. Этого вполне достаточно, чтобы фоновый звук любого нормального ЦАПа стал гораздо лучше. Однако все вышеописанное мало поможет, если мы будем выводить звук через спикер PC, по крайней мере обшепринятым ШИМ методом. В данном разделе я опишу некоторые известные и видимо неизвестные программные методы решения задачи улучшения фонового звука спикера PC. Прежде всего, точно укажу - в чем причина особенно плохого звука псевдо-ЦАПа на спикере PC : в том, что такой ШИМ-ЦАП нигде не хранит числовой код сигнала и соответственно во время экранирования аналоговый выход его не является постоянным, как у других ЦАПов. Поэтому улучшить работу спикера можно, если найдутся новые методы вывода, позволяющие как-то сохранить потенциал сигнала во время экранирования. Как известно, новое - это часто хорошо забытое старое. Так и есть. Простейший способ хранения сигнала спикера - использовать общеизвестный и достаточно примитивный метод прямого управления динамиком при помощи бита 1 порта 61h (см П.2). Правда в нем сохранить можно только один бит, что достаточно грубо для произвольного звука. Однако имеются кое- какие методики, до некоторой степени улучшающие субъективное качество однобитного звука, и они описаны в П.3. Дополнительное достоинство данного метода (назовем его метод М1Б) - максимально возможная для спикера PC громкость звука. Фактически, в мире есть масса PC с таким слабым звуком, что метод М1Б является для них вообще единственным, порождающим слышимый звук. А теперь опишу кое-что посвежее. Анализируя детали работы таймера в разных режимах, я пришел к выводу, что есть еще по крайней мере два метода сохранения сигнала спикера, использующих пока гипотетическое предположение о том, что сигнал SPKRout (см П.2) попадает на спикер без какой бы то ни было обработки, кроме усиления мощности. Метод МТР2 использует SPKRdata=const=1, канал 2 таймера работает в режиме 2 (генератор коротких импульсов) с делением частоты Ftm. Выходной сигнал меняется константой пересчета N2. Это преобразователь частоты в напряжение с постоянной длительностью импульсов. Пока выходная частота канала F2>>Fd (F2=Ftm/N2, что ограничивает N2<--------------------------- | | | | PC speaker | [ ]/| [ ] [ ] | R1=10 Ом [ ] R3=4.7 кОм [ ]\| [ ] | | | Сигнал | [ ] SPKRout >-------| T1 [ ] R2=30 Ом | Транзистор [ ] Вольты | n-p-n | +0.3 <-> +2.5 | к_______________| 0 <---> 1 |__|/ | Логические б |\___ | Конденсатор уровни э | __|__ | _____ C1=0.1 мкФарад *) | | | | | | Общий провод === === Рис. 4 "Стандартная" схема выхода на спикер PC. ------------------------------------------------- *) величина емкости различна на разных моделях PC, обычно диапазон ее изменений составляет 10...100% от указанного на схеме номинала. Если пренебречь индуктивностью спикера (которая здесь в первом приближении дает только линейный подьем ВЧ), то главной особенностью схемы является парралельное включение конденсатора C1 и ключевого транзистора T1, что приводит к нелинейным искажениям сигнала SPKRout - различному сглаживанию его фронтов. В самом деле, фронт 0->1 отпирает транзистор T1 и почти мгновенно конденсатор C1 разряжается через небольшое сопротивление коллектор- эмиттер транзистора T1, а через сопротивление R1 катушки PC спикера начинает течь ток максимальной интенсивности. Фронт же 1->0 сигнала SPKRout запирает T1, но ток через спикер R1 уменьшается постепенно, благодаря плавному заряду C1 через R1+R2. Вот какое напряжение Uspkr получается на спикере при периодическом изменении сигнала SPKRout с разной скоростью (рис. 5). +--------------------------------------------------------------> Время | --------- ----- -- d | / | / | / | | / | / | / | /| e | / a | / b | / c | / | | / | / | / | / | /| |----- ------ ------ ------ ------ ------ | <--> V Сигнал на спикере Uspkr Td Сигнал SPKRout: 11111 1111111 1111111 1111111 1111111 1111111 000000000000 00000000 00000 000 0 Рис. 5 Зависимость сигнала на спикере PC от сигнала SPKRout. ------------------------------------------------------------- Хорошо видно, что при уменьшении времени нахождения сигнала SPKRout в нуле амплитуда импульсов на спикере уменьшается. Для количественной оценки длительности импульса d (начало уменьшения амплитуды) по рис. 4 годится простая формула: Td = (R1+R2)*C1 = 40 Ом * 0.1 мкФ = 4 мксек, в то время, как квант таймера Ttm=0.84 мксек << Td. Теперь становится ясно, что в случае PC со схемой по рис. 4 метод МТР2 приводит к тому, что спикер достигает лишь небольшая (10-20%) часть амплитуды сигнала и мы практически ничего не слышим (см примечание к рис. 5). Но как водится - нет худа без добра ! Не стоит опускать руки, когда удача сама идет в них ! Та же самая "дефективная" схема позволяет сделать ЦАП получше, на другом варианте преобразовании частоты в напряжение ! То есть, если использовать таймер в режиме генерации импульсов со скважностью около 2 (это режим 3), то в зависимости от частоты такого генератора F2 среднее значение выходного сигнала на спикере будет меняться. Это и есть следующий метод, МТР3, который работает тем лучше, чем хуже работает МТР2. Вообще говоря, МТР2 и МТР3 очень напоминают старый метод ШИМ, однако в них не надо никаких прерываний, вместо которых таймер сам перезапускает счет (это позволяет сохранять на спикере аналоговый сигнал независимо от какого-то программного кода), а кроме того, частота перезапуска меняется пропорционально звуковому сигналу. В методе МТР3 когда частота F2 максимальна - короткие нули SPKRout не проходят на спикер, и максимально. Когда же F2 минимальна - нули проходят почти также хорошо, как и единицы и на спикере создается прамоугольные колебания со скважностью около 2, а (это среднее значение !) равно 50% от максимума. Естественно, что частота F2 всегда должна быть больше частоты дискретизации звука Fd, иначе не произойдет усреднения колебаний Uspkr. Если F2 сравнима с Fd, то в зависимости от деталей работы таймера возможна некоторая неоднозначность связи с F2. В частности, возникают сильные "биения" F2 и Fd, если перед перезагрузкой константы пересчета N2 приходится вновь посылать команду установки режима канала 2 таймера (см примечание в конце П.2). На рис. 6 приведена зависимость от N2 (F2=Ftm/N2) при частоте Fd=5013 Гц как раз для такого случая. + 50 % | от максимума * * | * * * | ** *** * * * + 40 * * ** *** * * * | * * | * | * + 30 * | * | * | * + 20 * * | * -------> . * | * * . | * . * + * -------> * . | * * | * | +----+----+----+----+----+----+----+----+----+----+----+----+---> 0 5 10 15 20 25 30 35 40 45 50 55 60 Константа N2 Рис. 6 Зависимость среднего напряжения на спикере от константы пересчета канала 2 таймера. -------------------------------------------------- При N2>30 на рис. 6 хорошо виден эффект биений F2 с Fd. Кроме того, в области N2<20 график имеет зазубрины (показано стрелками с увеличением), связанные с тонкой "игрой" скважности сигнала таймера OUT2 в режиме 3 в зависимости от четности кода N2 (см П.2). Чтобы уменьшить нелинейность преобразования сигнала Si->N2->Uspkr можно использовать табличное предыскажающее преобразование Si->N2 с учетом последующих искажений на этапе N2->Uspkr. Однако для этого необходимо проделать достаточно тщательные измерения зависимости, показаной на графике рис. 6, что практически нереально, так как данный график меняется для разных Fd и разных PC... Поэтому можно просто пожертвовать участком биений и даже не обращать внимание на нелинейность, приняв простую формулу преобразования N2=a*Si+b, где a,b=const. Избавиться от зазубрин графика можно простой инверсией младшего бита кода N2 (N2=N2 xor 1) перед записью его в таймер. Таким образом, от МТР3 можно получить (также как и в МТР2) несколько ослабленный максимальный размах звукового сигнала, около 30...50% от абсолютного максимума, неплохую линейность (лучше чем у МТР2), а число уровней квантования на выходе составит примерно 100/Fd (кГц), то есть от 20 (Fd=5 кГц), до 5 (Fd=20 кГц) или около 4...2 бит разрядности ЦАПа. Взакличение - пара замечаний. Так как МТР2 и МТР3 обычно используют только ультразвуковую область частот F2>20 кГц, даже такие низкие значения Fd как 5 кГц не приводят к сильному неприятному свисту в звуке, в то же время этот самый свист практически не позволяет слушать звук по обычному методу ШИМ, если Fd<10 кГц, что весьма ограничивает использование ШИМ на спикер медленных PC. Часто на одном и том же компьютере работают оба метода, МТР2 и МТР3, однако почти всегда какй-то один дает более громкий звук, так как эти два метода используют противоположные свойства выходной схемы возбуждения спикера. 3.4. Комбинации нестандартных программных методов. Следующая таблица отражает возможные комбинации методов вывода звука на PC спикер и/или на ЦАП типа Covox (или аналогичный). При этом полезные свойства каждого отдельного из вышеизложенных методов складываются и вместе образуют, как мне представляется, вполне сносную технологию программирования фонового вывода звука на PC. .................................................................... : Метод IRQs IRQ0 Метки врем. FM Спикер AM Бит Громк. Свист : .................................................................... : КМ1 IRQ0 + нет + МШИМ + 7 2-3 + : : КМ2 IRQ0 + Т2Р2 18.2 Гц - М1Б - 1 3 - : : КМ3 IRQc - Т2Р2 18.2 Гц - М1Б - 1 3 - : : КМ4 IRQc - Т0Р2 18.2 Гц - М1Б - 1 3 - : : КМ5 IRQc - Т0Р2 18.2 Гц - МТР2 - 2-3 0-2 - : : КМ6 IRQc - Т0Р2 18.2 Гц - МТР3 - 3-4 2-0 - : .................................................................... Табл. 2 Сводные характеристики методов вывода звука. ------------------------------------------------------ Пояснения к табл. 2 : IRQs - тип звукового прерывания; IRQ0 - ухудшается ли совместимость из-за использования IRQ0; Метки врем. - метод получения меток времени, ТXРY Z Гц обозначает канал X режим Y таймера с выходной частотой Z Герц; FM - наличие фазо-частотных искажений звука (спикер/ковокс); Спикер - метод вывода звука на спикер PC; AM - наличие искажений звука спикера типа амплитудной модуляции; Бит - примерная разрядность вывода на спикер, для Fd=10 кГц; Громк. - громкость звука спикера по шкале 0-3; Свист - наличие свиста несущей при Fd<10 кГц (спикер). Метод КМ1 общеизвестен, он хорошо работает только при отсутствии экранирования и F0>10 кГц. В методе КМ2 частота прерываний таймера F0 звуковая (плохо), может меняться в разумных пределах, звук спикера 1-битный. В методе КМ3 частота прерываний таймера F0 не влияет на звук и может быть любой, звук спикера 1-битный. В методах КМ4, КМ5 и КМ6 оптимальная частота прерываний таймера F0=18.2 Герц, она может быть больше (но не слишком), но ее значение должно быть точно известно. В противном случае (особенно если F0 непостоянна) алгоритм получения меток времени значительно усложняется. Это наиболее многообещающие методы фонового звука и работать они будут лучше всего при встраивании в такие среды, как многозадачная ОС с возможностью перехвата (или запрета) любых обращений прикладных программ к портам таймера. Вывод на спикер по МШИМ с метками времени не имеет практического значения, так как уменьшение FM тонет в сильных AM искажениях. Во всех методах следует бороться с попытками FG процессов менять режим работы канала 2 таймера, используемого для получения меток времени или/и (и! - см КМ2, КМ3) вывода звука на спикер. В принципе, хорошей программе фонового звука ничто не мешает применять несколько разных комбинированных методов вывода звука, и даже используя ШИМ тогда, когда отсутствует экранирование IRQs, но переключаясь на что-то другое сразу после его возникновения. 3.5. Изменение аппаратной схемы возбуждения спикера. Улучшить качество звука PC спикера можно, если изменить схему обработки сигнала SPKRout следующим образом: Сигнал SPKRout >---------->Фильтр ФНЧ1----->Фильтр ФВЧ1---- | | | | ---->Сумматор С1<-----Детектор Д1<--- | | ------>Усилитель У1----->Громкоговоритель Гр1 Рис. 7 Улучшенная блок-схема возбуждения спикера. -------------------------------------------------- Фильтр ФНЧ1 должен быть линейным и иметь примерно плоскую АЧХ до f=10 кГц, далее необходим равномерный спад АЧХ до частоты 600 кГц, причем пропускание его должно меняться как 1/f, т.е. достаточно стандартным образом. ФВЧ1 должен отсекать постоянную составляющую сигнала. Детектор Д1 должен иметь хорошую характеристику вблизи малых амплитуд. Сумматор С1 и усилитель У1 должны быть линейными. Полоса пропускания У1 может быть ограничена диапазоном 100 - 10000 Герц, лучше на его входе завалить ВЧ линейным фильтром. У1 должен иметь регулятор громкости и запас усиления, желательно также регулировать завал ВЧ. Гр1 должен быть мощностью до 0.5 Вт и иметь не слишком плохую характеристику на НЧ и ВЧ. Лучше не запирать Гр1 в глухом корпусе без дырок. Данная схема позволит успешно сочетать вывод звука на спикер по всем методам (старым и новым, кроме КМ5). При этом для метода КМ6 повысится разрядность и линейность, а громкость и тембр звука всегда будут вполне сносными. Есть также вариант улучшения схемы попроще. Надо хотябы применять во всех PC одинаковую стандартную схему возбуждения спикера, показанную на рис. 4, выбрав также неизменными (и оптимальными) значения емкости C1 и сопротивлений R1 и R2. 4. Заключительные замечания. SoundMedia. Данная работа была посвящена описанию методов улучшения качества фонового звука PC спикера и простейшего ковокса. Путем различных программных ухищрений фоновый звук действительно становится лучше, и даже на спикере теперь что-то можно услышать, хотя для этого желательна небольшая настройка параметров. Но качество звука у PC с таким выводом все-таки гораздо слабее, чем у Hi-Fi систем. Логично задать вопрос - зачем же вся эта возня нужна, стоит ли наша игра свечь ? Это филосовский вопрос. Когда я исследовал PC, то не очень-то задумывался над ним. Просто я не люблю отступать, раз берусь за дело, то должен его закончить. Когда варишь "суп из ничего" - то не очень-то думаешь о его вкусе - лишь бы что есть было... Все-таки аргументы в пользу того, что это надо - есть. В мире существует гигантский парк PC, не оборудованных никаким звуковым железом, кроме спикера. Поменьше, но тоже достаточно много таких, которые имеют вывод на внешний усилитель через ковокс или подобную простую штуку. Машин же с другими звуковыми картами гораздо меньше (т.к. цены этих карт порой сравнимы с ценой самой PC), к тому же часто возникают проблемы в совместимости софта с этой кучей разных карт, ведь никогда неизвестно заранее, какая карта у потребителя... А спикер и даже ковокс на порте принтера - всегда один. Поэтому, если вы хотите, чтобы любой обладатель PC наверняка смог услышать звук, сопровождающий работу вашего софта (и услышать достаточно хорошо), то вы должны использовать вышеизложенные методы. Кто желает - может оценить сей труд на практике. В настоящий момент у меня есть работающая программа mmplay.exe (см П.4). Она предназначена для одновременного проигрывания анимационного файла (напоминающего fli-файл Autodesk Animator-а) и звукового файла (линейная запись) при помощи VGA-монитора и спикера PC (и/или ковокса). Эта программа на мой взгляд уже достаточно убедительно показывает недостатки стандартного подхода и преимущества новых методов вывода фонового звука. Я уверен, что немалую практическую ценность на сегодня может иметь идея разработки обобщенной технологии ПРОГРАММНОГО создания, обработки и вывода в реальном времени фонового звука на IBM PC (и вообще на персональном компьютере) с получением простого и удобного многозадачного звукового-музыкального интерфейса для прикладных программ. Если вы работали в мультизадачных средах, то вероятно знаете, что там графэкран, клавиатура и мышь обычно являются строго разделяемыми ресурсами, которые ни одна задача не может безвозвратно забрать себе. А графэкран может одновременно содержать вывод сразу нескольких задач. Я думаю, что звуковой выход компьютера может и даже должен быть таким же разделяемым ресурсом, а также обладать такими же возможностями параллельного вывода звука разными задачами. Логично будет назвать эту технологию SoundMedia ("звуковой среды", наименее проработанная составляющая MultiMedia). Возможно, в скором времени SoundMedia позволит вам с наслаждением слушать музыку на своей старушке PC, периодически экономя средства на приобретении очередной, самой "суперовой" музыкальной карты. Вместо soundcard я бы советовал вам покупать лучше motheboard, на 386, 486 или даже 586-м процессоре (вместо вашего потрепанного 286-го), при этом получая все более и более качественный звук на одних и тех же программах... - не правда ли, это более заманчивая перспектива ? ПРИЛОЖЕНИЕ П.1. Список терминов, сокращений и обозначений. АМ : амплитудная модуляция. АЧХ : амплитудно-частотная характеристика цепи, зависимость амплитуды выходного напряжения цепи от частоты при входном синусоидальном сигнале неизменной амплитуды. Время экранирования IRQs : время задержки начала IRQs. ВЧ : высокие частоты, диапазон различен. Гц : Герц, частота в 1 Герц равна 1 колебанию в секунду. ЗЧ : звуковые частоты , обычно от 16 до 20000 Гц. НЧ : низкие частоты, диапазон различен. ПДП : прямой доступ в память, DMA. ПОП : программа обработки прерывания. Скважность : отношение периода следования к длительности импульсов. Таймер : микросхема таймера 8253 (8254) на системной плате PC. УЗВ : Устройство Звукового Вывода. ФНЧ : фильтр низких частот, не пропускающий высокие частоты. ФМ : фазовая модуляция. ЧМ : частотная модуляция. ЦАП : цифро-аналоговый преобразователь. ШИМ : широтно-импульсная модуляция. BG [процесс] : фоновая программа генерации звука. DMA : прямой доступ в память, ПДП. EOI : команда конца IRQx. f : частота. Fd : частота дискретизации звукового сигнала. FG [процесс] : произвольная программа переднего плана. FIFO [буфер] : первый зашел - первый вышел. Ftm : частота кварцевого генератора тактирования таймера, 1193182 Гц. F0 : частота канала 0 таймера, частота прерываний IRQ0. F2 : выходная частота канала 2 таймера в режимах 2 и 3, F2=Ftm/N2. int : программно-аппаратные прерывания. IRQ : аппаратные прерывания. IRQc : IRQ3 или IRQ4 последовательного порта (com порта) PC. IRQs : "звуковое" аппаратное прерывание, s - его абстрактный номер. IRQx : любое аппаратное прерывание. IRQ0 : IRQ системного таймера, int 08. RAM : оперативная память. S(T) : звуковой сигнал (напряжение), непрерывная функция времени. Si(ti) : дискретные отсчеты звукового сигнала. T : время. Ttm : период тактирования (квант) таймера =1/Ftm=0.838095 мкс. П.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@. Спикер возбуждается путем усиления и фильтрации (подробнее см разд. 3.3, 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 позволяет прочитать состояние счетчиков всех каналов одновременно и/или определить коды состояния каналов (Status Word), причем после команды RBC сначала из порта 4@h считывается один байт Status Word, а затем 1 или 2 байта кода счетчика, как по команде CLC. Формат байта команды RBC таймера: бит 0 =0; бит 1 =1 чтобы работать с каналом 0; бит 2 =1 чтобы работать с каналом 1; бит 3 =1 чтобы работать с каналом 2; бит 4 =0 чтобы читать Status Word коды каналов согласно битам 1...3; бит 5 =0 чтобы читать состояния счетчиков каналов согласно битам 1...3; бит 6 =1; бит 7 =1; Режимы работы каналов таймера: Режим 0 - "программный одновибратор". После команды УС OUT@=0. Счет разрешен при GATE@=1 и запрещен при 0. После отсчета N@ устанавливается OUT@=1. Т.о. сигнал OUT@=0 удерживается на время счета N@+1 периодов Ttm. Для повторения счета надо перезагрузить N@. Режим 1 - "аппаратный одновибратор". Счет перезапускается по фронту 0->1 сигнала GATE@, сигнал OUT@=0 во время счета N@ периодов Ttm, после чего OUT@=1. Для перезапуска счета не требуется перезагрузки N@. Перезагрузка N@ во время счета не влияет на текущий счет, но влияет на последующие **). Режим 2 - "генератор коротких импульсов". Канал @ работает как делитель частоты Ftm на N@. На выходе OUT@ формируются прямоугольные импульсы 011110111101111... со скважностью около 1 : OUT@=1 в течении времени (N@-1)/Ttm, OUT@=0 в течении времени 1/Ttm. При GATE@=0 счет приостанавливается (OUT@=1), при 1 - возобновляется. Перезапуск счета производится автоматически по достижении 0. Перезагрузка N@ во время счета не влияет на текущий счет, но влияет на последующие **). Напомню еще раз, что когда OUT2=1, то изменение состояния сигнала SPKRdata (бит 1 порта 61h) проходит на спикер, а когда OUT2=0 - то не проходит. Т.е. при @N>>1 практически всегда проходит. Режим 3 - "генератор импульсов". Канал @ работает как делитель частоты Ftm на N@. На выходе 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@ во время счета не влияет на текущий счет, но влияет на последующие **). В этом режиме счетчик вычитает двойками. Режим 4 - "программный одновибратор с задержкой". После команды УС OUT@=1. После отсчета N@+1 периодов Ttm сигнал OUT@=0 устанавливается на время Ttm, затем опять устанавливается OUT@=1. Остальное совпадает с режимом 0. Режим 5 - "аппаратный одновибратор с задержкой". GATE@ действует также как в режиме 1, а изменение сигнала OUT@ во время счета совпадает с режимом 4. --------------------------------------------------------------------- **) это может быть не совсем так : мои эксперименты показали, что при многократной перезагрузке N@ во время счета с вероятностью 1/1000...1/10000... происходит сбой в работе таймера и т.о. вы никогда не можете быть уверены на все 100%, что константа N@ загрузится правильно. Хотя обычно чем PC "новее", тем эти сбои случаются реже, вплоть до полного исчезновения на самых последних моделях. Этот факт должен быть учтен в частности в драйверах, меняющих быстродействие PC путем манипуляций с частотой регенерации памяти. Если вы хотите, чтобы PC не сбоила - надо перед любой загрузкой N@ посылать соответствующую команду установки режима канала @ таймера. П.3. Методы малобитного преобразования звука. Как было упомянуто выше, имеются методы (кратко названные мной малобитными), до некоторой степени улучшающие субъективное качество произвольного или почти произвольного звука при кодировании его сигналом с низким разрешением по уровню (1-3 бита), меньшим чем в оригинале (5-8 и более бит). Рассмотрим здесь некоторые из них. 1.Хорошо известный нам метод состоит в ШИМ кодировании сигнала, то есть преобразовании напряжения в длительность прямоугольных импульсов при постоянной их амплитуде и частоте следования. Например, чтобы передать 16 уровней сигнала (получить разрядность 4 бит), надо использовать частоту Fd в 16 раз бо'льшую чем обычно. Это-то повышение частоты и является наиболее ощутимым ограничением метода, качество же такого 1-битного преобразования превосходное. 2.Метод симметричного ограничения состоит в неискаженной передаче сигнала, если его модуль не превышает порога ограничения P, а если превышает, то положительные значение заменяются на +P, отрицательные на -P (этот метод в частности использован в программе Меломан для увеличения громкости звука спикера свыше номинального уровня 100%). Крайний случай метода - использование P=1/2 (вместо +1/2 и -1/2 можно брать более естественные целые уровни 1 и 0), выходной сигнал будет тогда 1-битным, но качество его достаточно низким. 3.Комбинация метода 2 с предварительной ВЧ-фильтрацией для подавления НЧ-части спектра звука, начиная где-то с 300-1000 Герц и ниже, позволяет уменьшить искажения метода 2, неплохо работает в случае спикера, который все равно НЧ почти не воспроизводит. 4.Метод передачи фронтов сигнала. Это метод 2, но работающий не на абсолютном значении сигнала, а на его изменении. В случае минимального порога и 1-битного выхода он работает так: если в текущий момент сигнал возрастает (положительный фронт), то выход равен 1, если уменьшается (отрицательный фронт), то выход равен 0 (это похоже на дельта модуляцию). Данный метод хорошо работает, когда звук состоит из небольшого количества простых сигналов близкой громкости, например - из ряда прямоугольных тонов разной частоты, то есть аккорда. Звук очень громок и имеет подавленные НЧ. 5.В общем случае видимо неплохо будет работать метод, напоминающий обработку сигнала в вокодере. Входной сигнал должен быть пропущен через гребенку полосовых фильтров, в каждом из которых далее стоит симметричный ограничитель по методу 2, а затем идет цифровой сумматор. -------------------------------------------------------------------- Замечание : чтобы делать выводы о применимости того или иного метода малобитного преобразования, нужно обязательно послушать, как они работают на практике (с учетом эффектов экранирования). П.4. Пакет программ Multi Media Player. К данной работе прилагается файл mmplay.arj (версия 1.01, 270 кб) со следующим содержимым : README .TXT инструкция к пакету; MMPLAY .C мультимедиа-плейер анимационных и звуковых файлов MMPLAY .EXE с коррекцией искажений звука; BURA . звуковой файл, линейная запись; BOSSTALK.MOV анимационные VENUS .MOV mov-файлы; *.* пакетные и файлы настройки компилятора TC++ 1.01; TA120 .C программа проверки эффектов экранирования TA120 .EXE (ее результаты в табл. 1 настоящей работы); GVGA100 .C резидентный графический граббер экрана; GP100 .C плейер анимационных mov-файлов; GPP102 .C упаковщик картинок в mov-файл и плейер; -------------------------------------------------------------------- 1993г. Апрель: 1...30. Май: 1,2,4,5,10,18,21. Июль: 2. Август: 6,11. 1994г. Январь: 5.