Главная страница «Первого сентября»Главная страница журнала «Информатика»Содержание №1/2009


В мир информатики
Школа программирования

Использование звуковых файлов формата wav в программах на Бейсике

Как, очевидно, известно читателям, существуют звуковые файлы двух видов: формата wav (произвольная оцифрованная звукозапись, в том числе голосовая) и midi (формат midi предназначен для кодирования только мелодий аналогично нотной записи партитур для симфонического оркестра, причем во время воспроизведения компьютер как бы моделирует звучание каждого из требуемых музыкальных инструментов, соединяя затем все их “голоса” в один общий “хор”).

Учитывая обилие готовых wav-файлов, хочется попытаться написать собственную программу на Бейсике для их воспроизведения через встроенный динамик без использования звуковой карты. Для этого постараемся понять внутреннее строение wav-файла и разработаем алгоритм его обработки.

Wav-файл можно разделить на две основные части: заголовок и собственно коды звуковой последовательности. Заголовок занимает первые 44 байта и содержит сведения о скорости записи данного звукового файла и времени его звучания, а также другие специальные данные.

Способ же кодирования звуковой последовательности в wav-файле — простой: в процессе записи звука в файл через равные промежутки времени звуковая плата (точнее, имеющийся на ней аналого-цифровой преобразователь) измеряет мгновенное значение амплитуды поступающего звукового сигнала, масштабирует его и записывает в качестве значения очередного байта, причем нулевой уровень сигнала (нулевая громкость) соответствует коду (байту) 128. Воспроизведение записанного в файле звука производится обратным, цифро-аналоговым, преобразованием, при этом напряжение на входе подключенных к звуковой плате наушников или выносных динамиков пропорционально модулю разности значения текущего байта и числа 128, а полярность напряжения определяется знаком этой разности. Таким образом, wav-файл представляет собой адекватный образ подававшейся на микрофон звуковой волны (что и определило название формата: wav — от английского wave — волна). Если же поставить в соответствие каждому байту вертикальный отрезок, длина и направление которого (вверх или вниз от нулевой оси) зависят от соотношения значения этого байта и константы 128, получится наглядный график, который показан в середине окна программы Звукозапись (рис. 1).

Рис. 1. Окно программы Звукозапись

Теперь посмотрим, как же можно воспроизвести записанный в wav-файле звук без звуковой платы, за счет одного только встроенного динамика. Очевидно, что абсолютное значение разности байта записи и кода 128 нам не понадобится — ведь управлять громкостью получаемого на встроенном динамике звука мы не в состоянии. Тогда единственной важной для нас информацией остается знак этой разности, показывающий, в какую сторону нужно отклонить мембрану динамика в данный момент. Следовательно, простейший алгоритм воспроизведения wav-файла на встроенном динамике будет таким:

— считываем содержимое файла байт за байтом, начиная с адреса 44 относительно начала файла (отсчет байтов ведется с нуля);

— для очередного байта определяем знак разности его значения и константы 128;

— если разность больше нуля, подаем на встроенный динамик логическую единицу, иначе — логический нуль (если же данный байт содержит именно число 128, не изменяем логический уровень на входе динамика вовсе);

— отрабатываем цикл задержки до обработки следующего байта (длительность задержки нужно подобрать в зависимости от используемого языка программирования и тактовой частоты процессора);

— считываем следующий байт, обрабатываем его тем же способом, что и предыдущий, и так до конца wav-файла.

В результате на динамик будет подаваться последовательность нулей и единиц, заставляющая его мембрану колебаться в приблизительном соответствии с записанными в файле изменениями амплитуды звуковой волны, и мы услышим требуемый звук, хотя, конечно, качество его воспроизведения будет ниже, чем при наличии звуковой платы (рис. 2).

Рис. 2. Графики исходного аналогового и оцифрованного при вводе в компьютер сигнала, двоичная последовательность и соответствующие ей колебания мембраны динамика

Из рис. 2 видно, что уже при вводе звуковой последовательности в компьютер с помощью звуковой платы неизбежны искажения звука из-за дискретного характера кодирования амплитуды (например, в интервалах 2, 3, 5, 10, 11, 13), а быстрые звуковые колебания, происходящие во время паузы между двумя соседними измерениями, могут быть вообще не распознаны (интервал 12), т.е. мы сталкиваемся с ограничением по верхней границе частотного диапазона. При перекодировании же оцифрованного звука в двоичную последовательность искажения проявляются еще больше, тем не менее общий характер поведения графика двоичного сигнала совпадает с таковым для исходного аналогового сигнала. Следовательно, можно надеяться, что звук будет воспроизводиться встроенным динамиком хотя и с возможными искажениями, но достаточно разборчиво. И следующий наш шаг — попытка написать соответствующую программу на Бейсике.

Прежде всего давайте посмотрим, какими из звуковых операторов Бейсика мы сможем воспользоваться для решения поставленной задачи. И здесь нас поджидает разочарование: очевидно, что ни один из рассмотренных ранее в статье [1] операторов — ни PLAY, ни SOUND, ни тем более BEEP — нам не подходят, так как все они не позволяют произвольно изменять состояние мембраны динамика, подавая на нее логические нули и единицы. Но ведь, как подтвердят “старшие товарищи” (родители, учителя и др.), в играх, применявшихся на компьютерах без звуковой платы, реализовывались достаточно сложные звуковые эффекты и даже речь. Секрет разработчиков игр довольно прост: хотя аппаратные возможности компьютера допускают прямое обращение к динамику (в том числе и требуемое нам), языки программирования высокого уровня, такие, как Паскаль, Си или QBasic, берут управление динамиком на себя. С одной стороны, это существенно упрощает работу со звуком (скажем, не будь в Бейсике оператора SOUND, нам пришлось бы в цикле подавать на динамик 0 и 1 с точно рассчитанной для требуемого значения частоты задержкой между ними, да еще не забыть отследить нужную длительность сигнала), а с другой — скрывает от пользователя изначальный механизм генерации звука. Все сказанное наталкивает нас на мысль, что для решения поставленной задачи необходимо или использовать в качестве языка программирования ассемблер (этот путь мы оставим для самостоятельного освоения более опытными читателями), либо производить прямые обращения к регистрам динамика. В языке Бейсик это можно сделать с помощью команд INP и OUT.

Немного поговорим об этих командах. Все они служат для чтения содержимого ячеек оперативной памяти с указанным адресом или для записи в них требуемого числового значения:

INP (<порт>) — читает байт из порта компьютера (<порт> — адрес порта из диапазона от 0 до 65 535);

OUT <порт>,<данные> — записывает в порт с указанным адресом байт <данные> (от 0 до 255).

В IBM-совместимом компьютере поддержка динамика осуществляется двумя микросхемами: это таймер (микросхема 8253) и адаптер интерфейса с периферией (микросхема 8255). Таймер используется для различных целей и содержит несколько отдельно программируемых каналов, для каждого из которых можно задать частоту генерируемой двоичной последовательности и ее длительность. Канал 2 этого таймера непосредственно связан с динамиком, поэтому достаточно переслать в него значения частоты и длительности, чтобы получить однотонный звук (причем, заметьте, независимо от процессора, который в это время может выполнять другие команды программы). Очевидно, что такой способ доступа к динамику аналогичен работе оператора SOUND.

Второй способ заключается в прямой записи логических нулей и единиц в связанный с динамиком бит 1 порта В микросхемы адаптера интерфейса периферии 8255. Адрес порта В равен 61Н, где Н — признак шестнадцатеричного числа. Но обычно динамик “подключен” к таймеру, поэтому для использования бита 1 порта В мы должны “отсоединить” динамик от таймера, подав 0 в нулевой бит того же порта В. Алгоритм генерации звукового тона посредством прямого обращения к биту динамика можно проиллюстрировать следующим листингом (предполагая, что большинство читателей не знакомы с ассемблером, будем записывать команды на некоем условном языке, по уровню соответствующем машинным командам):

начало

кол-во_циклов = 1000 'Длительность звука

частота = 300 'Задержка между сменой 0 и 1

порт_В = 61Н 'Адрес порта В микросхемы 8255

буфер1 = кол-во_циклов 'Счетчик циклов

буфер2 = прочитать (порт_В) 'Считываем прежнее содержимое порта

буфер2 = буфер2 AND 11111110 'Обнуляем нулевой бит числа

1: буфер2 = буфер2 OR 00000010 'Записываем 1 в первый бит

записать (порт_В, буфер2) 'Заносим полученное число в порт В

буфер3 = частота 'Счетчик задержки

2: пока буфер3 не равен 0

буфер3 = буфер3 - 1 'Задержка

переход к метке 2

буфер2 = буфер2 AND 11111101 'Записываем 0 в первый бит

записать (порт_В, буфер2) 'Заносим полученное число в порт В

буфер3 = частота 'Обновляем счетчик задержки

3: пока буфер3 не равен 0

буфер3 = буфер3 - 1 'Задержка

переход к метке 3

буфер1 = буфер1 - 1 'Уменьшаем счетчик циклов на 1

если буфер1 не равен 0, переход к метке 1

конец программы

При программировании на ассемблере рекомендуется запрещать на время генерации тона все прерывания1, так как компьютер с частотой 18,2 раза в секунду “отрывается” от любой работы для отслеживания текущего времени, и это отрицательно сказывается на воспроизведении звуков высокой частоты (так как отработка прерываний снижает реальную скорость работы процессора). Нам же придется проигнорировать этот совет, поскольку в Бейсике отсутствуют команды разрешения/запрета прерываний.

Теперь, когда мы выяснили в общих чертах механизм прямого доступа к динамику, можно попытаться написать собственные подпрограммы “побитовой” работы со звуком. Их мы рассмотрим в следующем выпуске.

Литература

1. Усенков Д.Ю. Звук в программах на Бейсике. / “В мир информатики” № 102–103 (“Информатика” № 2–3/2008).


1 Прерывание — особый момент в работе процессора, когда он приостанавливает выполнявшийся процесс и начинает обрабатывать поступивший запрос от какого-то устройства или программы. — Прим. ред.

Дм. Юр. Усенков

TopList