2. Оператор BEEP
Единственная возможность получения зву-
ка, которую предоставляет Spectrum-бей-
сик - это оператор BEEP. Его формат:
BEEP t, f
где t - длительность звука в секундах, а
f - высота в полутонах. Чтобы ноту повы-
сить или понизить на октаву, необходимо
ее значение соответственно увеличить или
уменьшить на 12.
Так, BEEP 0.5, 0 воспроизведет ноту ДО
первой октавы в течение полсекунды, а BEEP
0.5, 12 - ту же ноту ДО, но уже второй ок-
тавы.
Указанное нотоисчисление не очень точ-
но, поэтому взгляните на рис.3. Там в
верхней строчке приведены приблизительные,
а в нижней - точные параметры оператора
BEEP для первой октавы.
Музыкальный диапазон BEEPа достаточно
широк - от -60 до 69. Он охватывает 18,5
октав, но самые низкие и самые высокие из
них не представляют практического интере-
са для создания музыки, хотя вполне могут
использоваться в звуковых эффектах.
И в заключение можно добавить об удоб-
стве, которое Spectrum-бейсик предостав-
ляет нам в записи десятичных дробей. Если
такая дробь меньше единицы, то ноль перед
точкой можно не ставить. Таким образом,
BEEP 0.125,11
можно записать как
BEEP .125,11.
Дальше по тексту книги я именно так и
буду делать.
2.1. Создание эффектов на BEEPе
Для того, чтобы сделать что-либо поин-
тереснее простых гудков, оператор BEEP
обычно включается в какой-нибудь цикл, где
изменяются один или оба его параметра.
Простейший пример может выглядеть так:
10 FOR A=0 TO 60
20 BEEP .01,A
30 NEXT A
Эту маленькую программку можно долго и
упорно изменять, получая все новые и новые
эффекты. Попробуйте модифицировать преде-
лы, шаг, направление цикла, длительность в
операторе BEEP. Как это сделать, я думаю,
понятно всем, поэтому примеров приводить
не буду. Во время ваших экспериментов пом-
ните, что при маленьких длительностях низ-
кие ноты воспроизводиться не будут, и чем
ниже нота, тем больше должна быть дли-
тельность.
Когда Вам надоест занятие, предложенное
в предыдущем абзаце, можно переходить к
следующему этапу - изменению "внутреннос-
тей" цикла...
Можно увеличить число операторов BEEP.
Причем они могут быть настроены как на
одинаковые частоты и длительности, так и
на разные:
10 FOR A=0 TO 20
20 BEEP .007,A+7: BEEP .003,A
30 NEXT A
Диапазон звучания дополнительных BEEPов
можно ограничить:
10 FOR A=0 TO 69
20 BEEP .01,A
30 IF A>20 AND A<40 THEN BEEP .01,A+8
40 NEXT A
или так:
10 FOR A=0 TO 69
20 BEEP .0003,A-6: BEEP .001,A-3: BEEP
.01,A
30 NEXT A
Последний эффект интересен тем, что в нем
второй и третий BEEPы вступают постепенно
(см. сноску на предыдущей странице).
Эффект можно замедлить с помощью опера-
тора PAUSE:
10 FOR A=10 TO 40 STEP 2
20 BEEP .01,A: PAUSE 2
30 NEXT A
Можно в течение воспроизведения менять
длительность:
10 LET T=.01
20 FOR A=10 TO 60: BEEP T,A
30 LET T=T-.0002: NEXT A
10 FOR A=0 TO 60
20 BEEP A/500,60-A
30 NEXT A
В первом из этих примеров попробуйте поме-
нять шаг или направление изменения дли-
тельности, начальное ее значение.
Следующий вариант - вложенные циклы,
которых может быть сколько угодно. BEEPы
могут встречаться в любом из них:
10 FOR A=2 TO 5: BEEP .01,A
20 FOR B=20 TO 30: BEEP .01,B
30 NEXT B: NEXT A
10 FOR A=1 TO 40 STEP 10
20 FOR B=A TO A+20
30 BEEP .03,B
40 NEXT B: NEXT A
Попробуйте объединить несколько циклов.
Например:
10 FOR A=12 TO 69: BEEP .001,A
20 NEXT A
30 FOR A=69 TO 12 STEP -1
40 BEEP .001,A: NEXT A
И, наконец, во всю эту коллекцию можно
добавить элемент случайности:
10 FOR A=1 TO 10: LET F=RND*50
20 BEEP .1,F: BEEP .1,F+7: BEEP .1,F+4
30 NEXT A
10 FOR A=1 TO 20
20 BEEP .1,RND*20+40
30 NEXT A
10 FOR A=1 TO 20
20 BEEP RND/6,RND*60
30 NEXT A
Все перечисленные выше методы создания
эффектов могут использоваться совместно, в
любой комбинации.
Ищите, пробуйте, и Вы найдете среди
множества парочку подходящих для Вашей
программы эффектов.
2.2. Создание музыки на BEEPе
К сожалению, на операторе BEEP невоз-
можно создать сложную музыку, но наиграть
простенькую мелодию на нем можно.
Первое, что приходит в голову при по-
пытке создать мелодию - это составить це-
почку из BEEPов, которая обещает быть ве-
сьма неопределенных размеров. Этот способ
примитивен, неудобен, занимает много мес-
та и вообще не очень красив. Ему сущес-
твует несколько достойных замен. Например,
можно использовать такой цикл:
10 FOR A=1 TO 10
20 READ T,F: BEEP T,F
30 NEXT A
И где-нибудь в программу вставить строку,
начинающуюся с оператора DATA и содержа-
щую длительности и высоты нот мелодии. В
данном примере их должно быть по десять.
В некоторых музыкальных произведениях
бывают паузы. Чтобы исполнять такие мело-
дии, приведенный выше цикл придется немно-
го модифицировать:
10 FOR A=1 TO 10: READ T,F
20 IF T=0 THEN PAUSE F*50: NEXT A
30 BEEP T,F: NEXT A
Теперь достаточно в данные вставить 0, а
за ним длительность паузы в секундах.
Вы, наверное, заметили, что значение
паузы умножается на 50. Это делается пото-
му, что параметр оператора PAUSE исчис-
ляется в пятидесятых долях секунды. В таб-
лице 1 приведено соответствие нот дли-
тельностям операторов BEEP и PAUSE. В этой
таблице даны стандартные значения нот и
пауз, но в принципе можно использовать лю-
бые числа.
Вот, к примеру, программа, исполняющая
куплет детской песенки "В лесу родилась
елочка":
10 FOR A=1 TO 29: READ T,F
20 IF T=0 THEN PAUSE F*50: NEXT A
30 BEEP T,F: NEXT A
9000 DATA .25,7.02,.25,15.86,.25,
15.86,.25,14.039,.25,15.86
9010 DATA .25,12,.25,7.02,.25,7.02,
.25,7.02,.25,15.86,.25,15.86
9020 DATA .25,14.039,.25,20.84,.5,
19.02,0,.5,.25,19.02,.25,8.84
9030 DATA .25,8.84,.25,16.98,.25,
16.98,.25,15.86,.25,14.039,.25,
12
9040 DATA .25,7.02,.25,15.86,.25,
15.86,.25,14.039,.25,15.86,.5,
12
В эту программу можно ввести возмож-
ность изменения темпа. Для этого необходи-
мо первые три строки заменить следующими:
5 LET N=.5
10 FOR A=1 TO 29: READ T,F
20 IF T=0 THEN PAUSE F*N*50: NEXT A
30 BEEP T*N,F: NEXT A
Теперь Вы можете добиться желаемого
темпа исполнения мелодии, подставляя раз-
личные значения в пятую строку. Однако не
советую Вам вставлять туда 0 и очень боль-
шие числа.
Можно еще усовершенствовать эту прог-
раммку. Например, вставить контроль нажа-
тия клавиши, сделать ее более гибкой в от-
ношении длины мелодии, оформить как под-
программу и т.д. Конечный вариант может
выглядеть так:
9090 DATA 100
9100 LET N=.5: RESTORE 9000
9110 READ T,F
9120 IF T=100 OR INKEY$<>"" THEN RETURN
9130 IF T=0 THEN PAUSE F*N*50: GO TO
9110
9140 BEEP T*N,F: GO TO 9110
Удалите все строки с 5 по 30 предыдущей
программы и введите эти. Теперь Вы можете
вызывать мелодию на исполнение оператором
GO SUB 9100. Кроме того, теперь не надо
старательно вычислять количество нот в ме-
лодии: достаточно в ее конец вставить чис-
ло 100 (что, собственно, и сделано в стро-
ке 9090). Также Вы можете в любой момент
прервать исполнение, нажав любую клавишу.
Если мелодия кончится - подпрограмма так-
же закончит свою работу. При повторном за-
пуске мелодия начнется сначала, но если
убрать оператор RESTORE 9000, то она про-
должится с того места, где была прервана
(если, конечно, Вы не использовали опера-
тор READ или RESTORE после ее вызова).
Можно сделать проигрывание цикличес-
ким. Для этого придется поменять еще пару
строк:
9120 IF INKEY$<>"" THEN RETURN
9125 IF T=100 THEN GO TO 9100
Теперь вернуться из подпрограммы можно
только по нажатию клавиши. Зато мелодия
будет звучать, пока кому-нибудь совсем не
надоест.
Программы такого типа идеальны для
простого исполнения, без замены и сохране-
ния мелодии, но если Вы хотите записать
свое произведение на магнитофон и загру-
жать его прямо из работающей программы, то
Вам подойдет следующий фрагмент:
10 FOR A=3 TO D(1)*2+2 STEP 2
20 IF D(A)=0 THEN PAUSE D(A+1)*D(2)*50:
NEXT A
30 BEEP D(A)*D(2),D(A+1)
40 NEXT A
Для того, чтобы он заработал, перед его
запуском необходимо объявить и заполнить
массив D, содержащий такую информацию о
мелодии:
D(1) - количество нот
D(2) - темп исполнения
D(3) - длительность 1
D(4) - нота 1
.
.
.
D(N) - длительность N
D(N+1) - нота N
Его можно загрузить с кассеты, подав пря-
мую команду
LOAD "name" DATA D()
или заполнить из строчек DATA следующей
программкой:
10 DIM D(20): RESTORE
20 FOR A=1 TO 20: READ D(A)
30 NEXT A
Обратите внимание, что первые две цифры
данных должны быть количеством нот и тем-
пом.
Созданный таким образом массив можно
сохранить на ленте командой
SAVE "name" DATA D()
Приведу еще один пример подобной прог-
раммы, оформленный по последнему писку мо-
ды:
9100 LET A=2
9110 IF D(A)=100 THEN GO TO 9100
9120 IF INKEY$<>"" THEN RETURN
9130 IF D(A)=0 THEN PAUSE D(A+1)*D(1)*
50: GO TO 9150
9140 BEEP D(A)*D(1),D(A+1)
9150 LET A=A+2: GO TO 9110
Массив для этой подпрограммы должен быть
таким:
D(1) - темп исполнения
D(2) - длительность 1
D(3) - нота 1
.
.
.
D(N) - длительность N
D(N+1) - нота N
D(N+2) - 100
Заметьте, что количество нот указывать
не надо. На основе этого примера можно
сделать даже музыкальный редактор.
Теперь вернемся к составлению цепочек
данных.
Допустим, на нотном стане Вы увидели
ноту точь-в-точь, как на рис.4. Это ЛЯ
первой октавы. Из рисунка 1 видно, что ее
частота запишется как 8.84.
Это одна четвертая, и, взглянув на таб-
лицу 1, можно определить, что ее длитель-
ность будет .25. Таким образом, пара дан-
ных для этой ноты будет .25,8.84. Для всех
последующих нот вычисления будут такими
же.