Страница 15 из 19
2.2.5 Генерация набора тонов. В этом подразделе показано как генерировать цепочку звуков, когда компьютер ничем другим не занят; в следующем будет показано как выполнить ту же задачу, когда компьютер занят другой работой. Когда компьютер ничем другим не занят, то можно выводить мелодию или производить специальные звуковые эффекты; когда же компьютер занят другой работой, то нельзя производить звуковые эффекты. Создание звуковых строк является одной из мощнейших возможнос- тей, предоставляемых Бейсиком. Построение же строк звуков в ас- семблере требует большой работы. Может быть использован любой из двух методов генерации звука, предложенных в [2.2.2] и [2.2.3]. Для обоих методов надо просто генерировать один тон в течении заданного времени, затем следующий и т.д. Каждая звуковая строка формируется из двух строк данных, одна из которых содержит часто- ты последовательных тонов, а другая хранит их длительности (при условии, что требуются разные длительности). Продолжительность звучания определяется с использованием счетчика времени суток BIOS [2.1.6].
Высокий уровень. Опреатор Бейсика PLAY предоставляет большие возможности. Опе- ратор сопровождается строкой нот, перемешанных с информацией о том, как эти ноты должны быть исполнены. Ноты записываются буква- ми A - G и последующими знаками для диезов и бемолей. Диезы обоз- начаются знаками # или +, а бемоли минусом (-). Операторы PLAY "CC#D" и PLAY "CD-D" эквивалентны, но нельзя использовать диезы и бемоли для обозначения белых клавиш. Второй способ задания нот состоит в вычислении кодового номера от 0 до 84, причем 0 соот- ветствует отсутствию звучания, а числа от 1 до 84 соответствуют 84 возможным нотам семи октав, начиная снизу. Номеру должна пред- шествовать буква N: PLAY "N3N72N44". Допустимый диапазон - семь октав, внутри каждой могут быть ноты от C(до) до B(си). Октавы пронумерованы от 0 до 6 и нота до первой октавы соответствует октаве 3. Текущая октава может быть изменена в любой момент, за счет вставки в строку буквы O, за которой следует номер октавы. Если не было начальной установки, то используется октава 4. Оператор PLAY "O3CO4CO5CO6C" выводит ноты до последовательных октав вверх. Другой способ изменения октавы состоит во включении в строку символов > или <, которые переключают тон вверх и вниз на октаву, соответственно. Оператор PLAY "O3C>C>C>C" приводит к тому же результату, что и предыдущий. Длительность исполнения нот также может быть изменена за счет вставки кодового номера, которому предшествует буква L. Все пос- ледующие ноты будут исполняться с этой длительностью до тех пор, пока не встретится другой код длины. Код - это число от 1 до 64, причем 1 соответствует целой ноте, а 64 - 1/64. Запись L4 соот- ветствует четверти. Темп с которым исполняются ноты регулируется кодом темпа, который состоит из буквы T, за которой следует число от 32 до 255, дающее число четвертей, исполняемых в минуту. Если эти параметры не указаны, то по умолчанию берется длительность L4 и темп 120. Для изменения длительности только одной ноты надо поместить значение длины после ноты и без буквы L. Оператор PLAY
"L4CDE16FG" исполнит E как шестнадцатую, а все остальные ноты как четверти. Длительность пауз берется такой же, как и длительность нот. Поместите номер от 1 до 64 после буквы P для паузы. P1 де- лает паузу интервалом в целую, а P64 - в 1/64. Помещение точки после ноты имеет тот же эффект, какой он имеет в обычной музы- кальной нотации: длительность ноты увеличивается наполовину. Вторая точка продолжит длительность еще наполовину. По умолчанию ноты играются 7/8 указанной длительности. Чтобы они исполнялись полную длительность (легато), поместите в строку ML. Чтобы они исполнялись 3/4 длительности (стаккато), поместите в строку MS. Чтобы вернуться к нормальному стилю надо указать MN. Обычно, вся прочая деятельность программы прекращается до тех пор, пока не будет сыграна строка. Для того чтобы выполнялись операторы, следующие за оператором PLAY, а строка исполнялась в фоновом режиме, поместите в строку MB. Для восстановления нор- мальной ситуации напишите MF. Наконец, оператор PLAY позволяет исполнять подстроки внутри длинной строки. Имеется в виду, что часть исполняемой строки может быть введена как обычная строковая переменная, а затем эта переменная может быть вызвана из строки сформированной в операто- ре PLAY. Например, если S$ = "EEEEE", то в операторе PLAY "CDXS$;FG" нота E будет повторена 5 раз. Отметим, что имени пере- менной должна предшествовать буква X, а за именем следовать точка с запятой (;). (Для компилируемых программ применяется другой метод, использующий переменную VARPTR$ - детали см. в руководстве по Бейсику).
В приведенном примере исполняется знакомый бой дедушкиных часов. В строке сначала устанавливается стиль исполнения легато, затем темп и начальная октава, и, наконец, четыре ноты, пауза, и те же самые четыре ноты, но в обратном порядке. Пробелы в строке включены исключительно для удобства программиста - Бейсик игнори- рует их.
100 PLAY "ML T40 O3 ECD<G P32 G>DEC"
Благодаря наличию генератора звука PCjr добавляет к оператору PLAY две возможности. Во-первых, допускается параметр V, устанав- ливающий громкость. Выражение V5 устанавливает (или изменяет) громкость на уровень 5. Допустимый диапазон от 0 до 15, причем по умолчанию берется 8. 0 полностью подавляет звук. Во-вторых, с помощью оператора PLAY можно одновременно исполнять три звуковых строки. Поместите все три строки в одну программную строку, раз- деляя их запятыми. Для того чтобы иметь возможность использовать эти специальные свойства, Вы должны предварительно разрешить внешний динамик с помощью оператора SOUND ON.
100 SOUND ON 110 PLAY "...........","..........","............"
Низкий уровень. В примере для генерации звука используется микросхема таймера 8253. Здесь просто исполняются 8 нот, но небольшая модификация может сильно расширить возможности этой процедуры. Имеется три строки данных. Первая устанавливает длительность каждой ноты, как кратное произвольного периода задержки (изменяя этот период за-
держки, можно изменять темп). Вторая строка содержит частоты каждой из 8 нот; эти значения должны быть помещены в регистр задвижки канала 2 микросхемы 8253 для исполнения желаемых тонов. Третья строка содержит мелодию в виде кодовых номеров от 1 до 8, которые соответствуют восьми частотам. Эта строка завершается кодом 0FFH, который служит признаком конца мелодии. Процедура просто читает очередную ноту мелодии, находит соответствующую частоту и помещает ее в канал 2. Затем длительность для этой ноты помещается в счетчик цикла задержки, который использует счетчик времени суток, а когда задержка кончается, то переходим к обра- ботке следующей ноты. На рис. 2-5 показана работа этой процедуры.
;---в сегменте данных BEAT DB 10,9,8,7,6,5,4,3,2 ;длительность нот FREQUENCY DW 2280,2031,1809,1709 ;таблица частот DW 1521,1353,1207,1139 ; MELODY DB 1,2,3,4,5,6,7,8,0FFH ;номер частоты ноты
;---инициализация PORT_B EQU 61H COMMAND_REG EQU 43H LATCH2 EQU 42H IN AL,PORT_B ;получаем текущий статус OR AL,00000011B ;разрешаем динамик и таймер OUT PORT_B,AL ;заменяем байт MOV SI,0 ;инициализируем указатель MOV AL,0B6H ;установка для канала 2 OUT COMMAND_REG,AL ;посылаем в командный регистр ;---смотрим ноту, получаем ее частоту и помещаем в канал 2 NEXT_NOTE: LEA BX,MELODY ;берем смещение для мелодии MOV AL,[BX][SI] ;берем код n-ной ноты строки CMP AL,0FFH ;проверка на конец строки JE NO_MORE ;если конец, то на выход CBW ;переводим в слово ;получение частоты MOV BX,OFFSET FREQUENCY ;смещение таблицы частот DEC AX ;начинаем отсчет с 0 SHL AX,1 ;умножаем на 2, т.к. слова MOV DI,AX ;адресуем через DI MOV DX,[BX][DI] ;получаем частоту из таблицы ;начинаем исполнение ноты MOV AL,DL ;готовим младший байт частоты OUT LATCH2,AL ;посылаем его MOV AL,DH ;готовим старший байт частоты OUT LATCH2,AL ;посылаем его ;---создание цмкла задержки MOV AH,0 ;номер функции чтения счетчика INT 1AH ;получаем значение счетчика MOV BX,OFFSET BEAT ;смещение таблицы длин MOV CL,[BX][SI] ;берем длину очередной ноты MOV CH,0 ; MOV BX,DX ;берем младшее слово счетчика ADD BX,CX ;определяем момент окончания
STILL_SOUND: INT 1AH ;берем значение счетчика CMP DX,BX ;сравниваем с окончанием JNE STILL_SOUND ;неравны - продолжаем звук INC SI ;переходим к следующей ноте JMP NEXT_NOTE ; ;---завершение NO_MORE: IN AL,PORT_B ;получаем статус порта B AND AL,0FCH ;выключаем динамик OUT 61H,AL ;заменяем байт
|