Программирование в системе Express Pascal
В языке Бейсик КУВТ "Корвет" нет специальных средств, позволяющих программировать мелодии. Однако с помощью оператора ВЕЕР этот пробел можно устранить.
После выполнения процедур начальной инициализации в системной области памяти ПК8020 появляются четыре 8-разрядных ячейки, работая с которыми можно при помощи встроенного динамика генерировать широкий по высоте и длительности диапазон звуков. Это ячейки со следующими адресами:
- F715, F716 - высота сигнала BELL;
- F717, F718 - длительность сигнала BELL.
Первоначально в первые две ячейки заносится число 25А0, а во вторые - число 0800, что заставляет динамик генерировать звук частотой 800 Гц и длительностью 0.25 с.
Указанные выше факты позволили установить следующие соотношения: чтобы динамик генерировал звук с частотой F (Гц) и длительностью D (с), необходимо в ячейки с адресами F715, F716 записать число A=9632*800/F, а в ячейки с адресами F717, F718 - число B=2048*4*D. При этом по адресам F715 и F717 записываются младшие разряды указанных чисел.
Полученные формулы носят эмпирический характер, однако прослушивание профессиональными музыкантами мелодий, исполняемых компьютером, подтвердило их правильность.
Хотя соотношения для частоты и длительности уже позволяют программировать музыку, необходимый при этом перевод нот в форму многоразрядных чисел оказывается делом затруднительным. Поэтому возникла идея написать прикладную программу, имитирующую оператор PLAY расширенного Бейсика IBM PC, который предусматривает применение специального музыкального языка для программирования мелодий.
В силу особенностей ПК8020 удалось реализовать не все из 19 подкоманд оператора PLAY, однако наиболее важные были запрограммированы. Кроме того, исполнение мелодий в режиме реального времени, как это делается в операторе PLAY, вызвало затруднения из-за относительно медленной работы интерпретатора языка Бейсик ПК8020. Поэтому были написаны две программы: PLAY и MELOD.
Программа PLAY - своего рода компилятор, который каждую ноту представляет в виде четырех целых десятичных чисел и вместе с названием мелодии записывает на ГМД в файл с именем, выбранным пользователем. Она "понимает" следующие команды:
нота | - | з вучание указанной (С, D, Е, F, G, А, В) ноты в нужной октаве с диезом (знак +), бемолем (знак -) либо чистой (знак пробела); |
O | - | задание номера от 0 до 7; |
N (номер) | - | звучание ноты с номером от 01 до 17; |
L (длительность) | - | задание длительности всех последующих нот от целой 01 до шестьдесят четвертой 64. Как вариант этот параметр может следовать за конкретной нотой, указывая ее длительность; |
Р (длительность) | - | пауза. Параметр указывается, как и в команде L; |
Т (число ударов) | - | задание темпа произведения от 30 до 260; |
MN | - | исполнение нон легаго (обычное); |
ML | - | исполнение легато; |
MS | - | исполнение стаккато. |
Внешне эти команды аналогичны подкомандам оператора PLAY. Однако есть ряд отличий.
Команда "." в явном виде отсутствует. Чтобы увеличить длительность звучания ноты в число раз, кратное 1,5, необходимо показатель кратности поставить в 5-6-ю позиции команды "нота" (например, D+0801); в 6-7-ю позиции подкоманды "N" (например, N050801); в 4-5-ю позиции подкоманд "L", "Р" (например, L0802 или Р1601).
Ноты В- и А+, А- и G+, G- и F+, Е- и D+, D- и С+ в подкоманде "N" имеют разные номера, хотя при исполнении мелодии звучат одинаково.
Мелодии могут записываться в восьми октавах, из которых две лежат ниже первой (номера 0 и 1), а пять - выше.
Программа MELOD озвучивает с помощью оператора ВЕЕР откомпилированные программой PLAY мелодии. Для этого указанный пользователем файл с мелодией считывается в оперативную память и перед каждым использованием оператора ВЕЕР в ячейки F715 - F718 заносятся целые числа, характеризующие очередную ноту.
Некоторую сложность представляет реализация пауз при исполнении мелодии. Специальные средства для этого отсутствуют; однако если в ячейки с адресами F715 и F716 записать число 2, то будут генерироваться импульсы с частотой 3,9 МГц, т. е. не воспроизводимые динамиком и не слышимые ухом. Это обстоятельство и было использовано.
Для иллюстрации приведем команды для исполнения на ПК8020 песни "Тонкая рябина".
Т76,O2,Е 02,G 04,В 02,O3,С 04,O2,В 04, А ,Р01,D+02,F+04,O3,С 02,O2,В 04,А 04, G ,Р01,Е 04,G 04,В 04,ОЗ,Е 02, D 04, D 04,C ,P01,D 02,С 04,O2,В 02,А 04, В 04,Е ,Р01,Е 04,G 04,В 04,ОЗ,Е 02, D 04,D 04,C ,P01,D 02,C 04,O2,В 02, А 04,В 04,ОЗ,Е 01
Ниже приведены также полные тексты программ PLAY и MELOD.
5 REM *******"PLAY"*******
10 REM ПРЕПРОЦЕССОР МЕЛОДИЙ
15 REM АВТОР АРТАМОНОВ В.С.
17 REM ********************
20 CLS:PCLS:LOCATE 20,2,1:PRINT "ПРЕПРОЦЕССОР МЕЛОДИЙ":CLEAR 2000
22 PRINT "ВВЕДИТЕ УНИКАЛЬНОЕ ИМЯ ФАЙЛА ДЛЯ ХРАНЕНИЯ МЕЛОДИИ,"
24 PRINT "ПОСЛЕ ПОЯВЛЕНИЯ НА ЭКРАНЕ '0k' НАБЕРИТЕ:GOTO 27<ВК>:"
25 INPUT NM¤:OPEN "О",#1,"FILE.BAS":NM¤="52 OPEN "+CHR¤(34)+"O"+CHR¤(34)+",#1,"+CHR¤(34)+NM¤+CHR¤(34):PRINT #1,NM¤:CLOSE 1
26 MERGE "FILE.BAS"
27 PRINT "НАЗВАНИЕ МЕЛОДИИ:":INPUT M¤:PRINT "АВТОР":INPUT A¤
29 DIM B(17)
30 B(1)=65.405:B(2)=69.41:B(3)=69.41:B(4)=73.415:B(5)=77.91
35 B(6)=77.91:B(7)=82.405:B(8)=87.305:B(9)=92.6525:B(10)=92.6525
40 B(11)=98!:B(12)=104!:B(13)=104!:B(14)=110!:B(15)=116.735:B(16)=116.735:B(17)=123.47
45 DEF FNH(A¤,S¤)=(INSTR(S¤,LEFT¤(A¤,1))-1)*16+INSTR(S¤,RIGHTS(A¤,1))-1
50 S¤="0123456789ABCDEF"
52 OPEN "O",#1,"AAAAAA""
54 PRINT #1,М¤,A¤
55 O=2:T=2048*24:REM ПО УМОЛЧАНИЮ 2-Я ОКТАВА.ТЕМП-LARGHISSIMO
57 KF=1:REM ПО УМОЛЧАНИЮ ДЛИТЕЛЬНОСТЬ РАВНА 1
58 Z=1:REM ПО УМОЛЧАНИЮ ПРИЕМ- LEGATO.
59 GOSUB 1000:NT=0
60 LOCATE 1,15,0:PRINT SPC(60):L0CATE 1,15,0:INPUT "КОМАНДА"; AG¤:IF AG¤="***" OR AG¤="" THEN 999
65 G¤=LEFT¤(AG¤,1)
70 IF G¤="O" THEN GOSUB 100:GOTO 60
72 IF G¤="T" THEN GOSUB 200:GOTO 60
74 IF G¤="N" THEN GOSUB 300:GOTO 60
76 IF G¤="L" THEN GOSUB 400:GOTO 60
78 IF G¤="P" THEN GOSUB 600:GOTO 60
80 IF G¤="M" THEN GOSUB 500:GOTO 60
85 GOSUB 2000:GOTO 60
100 REM П/П ВЫЧИСЛЕНИЯ ОКТАВЫ.
110 O=LEN(AG¤)-1:O¤=RIGHT¤(AG¤,O):O=VAL(O¤)
120 IF O<0 THEN O=0
130 IF O>7 THEN O=7
140 RETURN
200 REM П/П ВЫЧИСЛЕНИЯ ТАКТА.
210 T=LEN(AG¤)-1:T¤=RIGHT¤3(AG¤,T):T=VAL(T¤)
220 IF T<=0 THEN T=40
230 T=2048*240/T
235 T=T*4
240 RETURN
300 REM П/П ОЗВУЧИВАНИЯ HOT.
310 W=LEN(AG¤)-1:W¤=RIGHT¤(AG¤,W):N=VAL(LEFT¤(W¤,2))
320 KN=VAL(MID¤(W¤,3,2))
321 IF KN=0 THEN 330
322 IF KN<1 THEN KN=1
324 IF KN>>64 THEN KN=64
330 IF N<1 THEN N=1
340 IF N>>17 THEN N=17
350 KT=VAL(MID¤(W¤,5,2))*1.5
360 IF KN>0 THEN DL=T*Z/KN:PUZ=T*(1-Z)/KN:GOTO 380
370 DL=T*Z*KF:PUZ=T*(1-Z)*KF
380 IF KT>0 THEN DL=DL*KT
382 DL¤=HEX¤(DL):IF LEN(DL3)<4 THEN DL¤="0"+DL¤
384 IF LEN(DL¤)<4 THEN DL¤="0"+DL¤
386 PRINT #1,STR¤(FNH(LEFT¤(DL¤,2),S¤)):PRINT #1,STR¤(FNH(RIGHT¤(DL¤,2),S¤))
388 F=9632*800/(B(N)*(2^(O+1))):F¤=HEX¤(F):IF LEN(F¤)<4 THEN F¤="0"+F¤
389 IF LEN(F¤)<4 THEN F¤="0"+F¤
390 PRINT #1,STR¤(FNH(LEFT¤(F¤,2),S¤)):PRINT #1,STR¤(FNH(RIGHT¤(F¤,2),S¤))
391 IF PUZ=0 THEN NT=NT+4:G0T0 396
392 PUZ¤=HEX¤(PUZ):IF LEN(PUZ¤)<4 THEN PUZ¤="0"+PUZ¤
393 IF LEN(PUZ¤)<4 THEN PUZ¤="0"+PUZ¤
394 PRINT #1,STR¤(FNH(LEFT¤(PUZ¤,2),S¤)):PRINT #1,STR¤(FNH(RIGHT¤(PUZ¤,2),S¤))
395 PRINT #1,STR¤(0):PRINT #1,STR¤(2):NT=NT+8
396 LOCATE 40,15:PRINT SPC(5):LOCATE 40,15 PRINT NT04:FOR IN=1 TO 99:NEXT IN:RETURN
400 REM П/П ОПРЕДЕЛЕНИЯ ДЛИТ.
410 L=LEN(AG¤)-1:L¤=RIGHT¤(AG¤,L):L=VAL(LEFT¤(L¤,2))
420 IF L<1 THEN L=1
440 IF L>64 THEN L=64
445 LT=VAL(MID¤(L¤,3,2))*1.5
450 KF=1/L:IF LT>0 THEN KF=KF*LT
455 RETURN
500 REM П/П ПРИЕМА ИЗВЛ. ЗВУКА.
505 REM STACCATO
510 IF AG¤="MS" THEN Z=3/4:RETURN
515 REM LEGATO
520 IF AG¤="ML" THEN Z=1:RETURN 525
REM NON LEGATO
530 IF AG¤="MN" THEN Z=7/8:RETURN
540 Z=1:PRINT "НЕВЕРНАЯ КОМАНДА !"
550 RETURN
600 REM П/П ОПРЕД. ПАУЗ В СЕК.
610 P=LEN(AG¤)-1:P¤=RIGHT¤(AG¤,P) :P=VAL(LEFT¤(P¤,2))
620 IF P<1 THEN P=1
630 IF P>64 THEN P=64
640 PZ=T/P
642 PT=VAL(MID¤(P¤,3,2))*1.5:IF PT>0 THEN PZ=PZ*PT
643 PZ¤=HEX¤(PZ):IF LEN(PZ¤)<4 THEN PZ¤="0"+PZ¤
645 IF LEN(PZ¤)<4 THEN PZ¤="0"+PZ¤
650 PRINT #1,STR¤(FNH(LEFT¤(PZ¤,2),S¤)):PRINT #1,STR¤(FNH(RIGHT¤(PZ¤,2),S¤))
655 PRINT #1,STR¤(0):PRINT #1,STR¤(2):NT=NT+4
660 LOCATE 40,15:PRINT SPC(5):LOCATE 40,15:PRINT NTO4:FOR IN=1 TO 99:NEXT IN:RETURN
999 CLOSE 1:END
1000 REM П/П ИНСТРУКЦИЙ.
1005 CLS:LOCATE 25,1,1 PRINT "ИНСТРУКЦИЯ":PRINT "ВЫ МОЖETE ВВОДИТЬ СЛЕДУЮЩИЕ КОМАНДЫ:"
1010 PRINT "1. ОХ,ГДЕ Х-НОМЕР ОКТАВЫ;PRINT "2. ТХХХ.ГДЕ ХХХ-ТЕМ П МЕЛОДИИ;"
1015 PRINT "3. NXXYYZZ,ГДЕ XX-НОМЕР НОТЫ, Yf-ДЛИТЕЛЬНОСТЬ, ZZ-УВЕЛИЧЕНИЕ ДЛИТЕЛЬНОСТИ В ZZ*1.5 РАЗ;"
1020 PRINT "4. LXXZZ,ГДЕ XX-ДЛИТЕЛЬНОСТЬ ПО УМОЛЧАНИЮ,ZZ-УВЕЛИЧЕНИЕ ДЛИТЕЛЬНОСТИ В ZZ*1.5 РАЗ;"
1025 PRINT "5. PXXZZ,ГДЕ XX-ДЛИТЕЛЬНОСТЬ ПАУЗ,ZZ-УВЕЛИЧЕНИЕ ДЛИТЕЛЬНОСТИ В ZZ*1.5 РАЗ;"
1030 PRINT "6. MS,ML,MN-ПРИЕМЫ ИЗВЛЕЧЕНИЯ ЗВУКА(STACCATO, LEGATO, NON LEGATO);"
1032 PRINT "7. YXZZUU,ГДЕ Y-ОБОЗНАЧЕНИЕ НОТЫ,X(+,-,ПРОБЕЛ), ZZ-ДЛИТЕЛЬНОСТЬ,UU-УВЕЛИЧЕНИЕ ДЛИТЕЛЬНОСТИ В UU*1.5 РАЗ."
1040 RETURN
2000 REM П/П ОПРЕД. НОМЕРА НОТЫ.
2010 Q¤="C C+D-D D+E-E F F+G-G G+A-A А+В-В "
2015 G¤=G¤+MID¤(AG¤,2,1):NN=INSTR(Q¤,G¤)
2020 IF NN=0 THEN LOCATE 20,15:PRINT "НЕВЕРНАЯ КОМАНДА !":FOR IN=1 TO 50:NEXT IN:RETURN
2025 NN=(NN+1)/2:NN¤=STR¤(NN):NN¤=MID¤(NN¤,2,LEN(NN¤)-1):IF LEN(NN¤)<2 THEN NN¤="0"+NN¤
2030 G¤=MID¤(AG¤,3,2):GG=VAL(G¤):G¤=STR¤(GG):G¤=MID¤(G¤,2,LEN(G¤)-1):IF LEN(G¤)<2 THEN G¤="0"+G¤
2035 DD¤=MID¤(AG¤,5,2):DD=VAL(DD¤):DD¤=STR¤(DD):DD¤=MID¤(DD¤,2,LEN(DD¤)-1):IF LEN(DD¤)<2 THEN DD¤="0"+DD¤
2040 AG¤="N"+NN¤+G¤+DD¤:G¤="N"
2045 LOCATE 20,15:PRINT AG¤:FOR IN=1 TO 50:NEXT IN
2050 GOSUB 300
2060 RETURN
3 REM ******"MELOD"*******
4 REM ПРОГРАММА ПРОИГРЫВАНИЯ МЕЛОДИЙ.
5 REM АВТОР АРТАМОНОВ В.С.
6 REM ********************
7 GOSUB 100:MERGE "FILE.BAS"
9 CLEAR 2000
17 Z=1:PRINT "КОЭФФИЦИЕНТ ДЛИТЕЛЬНОСТИ (1 ИЛИ ЧИСЛО МЕНЬШЕЕ 15)":INPUT Z
20 I=1:DIM М(5000):INPUT #1,M¤
22 PCLS:CLS:PRINT M¤
24 IF EOF(1) THEN 30
26 INPUT #1,M(I)
28 I=I+1:GOTO 24
30 I=I-1:FOR J=1 TO I STEP 4
40 A=M(J):B=M(J+l):C=M(J+2):D=M(J+3)
45 A=A*Z
47 IF A>>255 THEN A=255
50 POKE &HF718,A
60 POKE &HF717,B
70 POKE &HF716,C
80 POKE &HF715,D
90 BEEP
95 NEXT
99 CLOSE 1:END
100 REM ПОДПРОГРАММА С ИНСТРУКЦИЯМИ.
110 PCLS:CLS:LOCATE 20,2,1:PRINT "ЭЛЕКТРОННЫЙ ОРКЕСТР"
120 PRINT "ВВЕДИТЕ ИМЯ ФАЙЛА С MEЛОДИЕЙ,:PRINT "ПОСЛЕ ПОЯВЛЕНИЯ НА ЭКРАНЕ 'Ок' ВВЕДИТЕ:GOTO9<BK>"
130 INPUT NM¤
140 NM¤="10 OPEN "+CHR¤(34)+"I"+CHR¤(34)+",#1,"+CHR¤(34)+NM¤+CHR¤(34)
150 OPEN "O",#1,"FILE.BAS"
155 PRINT #1,NM¤:CLOSE 1
160 RETURN