4.4. Программирование музыки
Программирование музыки в кодах - заня-
тие неблагодарное. Лучше это делать с по-
мощью какого-нибудь музыкального редакто-
ра. Но редактор может не удовлетворить все
Ваши потребности, так что освоить програм-
мирование в кодах все же желательно.
Принцип тот же - последовательно чи-
таются данные и вызывается процедура вос-
произведения. При этом необходимо предус-
мотреть прерывание исполнения (чаще всего
в этих целях контролируется нажатие ка-
кой-нибудь клавиши). Например:
1415.
10 START LD HL,60000 ; HL=адрес данных
20 NEXT LD E,(HL) ; DE=
30 INC HL ; дли-
40 LD D,(HL) ; тель
50 INC HL ; ность
60 LD A,D ; DE
70 CP 255 ; =
80 JR NZ,CONT ; 65535
90 LD A,E ; ?
100 CP 255 ; если да,
110 JR Z,START ; то мелодия сначала
120 CONT LD A,D ; DE=
130 OR E ; 0 ?
140 JR NZ,BEEP ; если нет, то перейти на BEEP
150 LD E,(HL) ; DE=
160 INC HL ; длитель-
170 LD D,(HL) ; ность
180 INC HL ; паузы
190 PAUSE HALT ; ожидание прерывания
200 DEC DE ; DE=DE-1
210 LD A,D ; DE=
220 OR E ; 0 ?
230 JR NZ,PAUSE ; если нет, то цикл
240 JR NEXT ; переход на обработку след.
данных
250 BEEP LD C,(HL) ; BC=
260 INC HL ; час-
270 LD B,(HL) ; то-
280 INC HL ; та
290 PUSH HL ; сохранение HL
300 PUSH BC ; поместить BC в стек
310 POP HL ; поместить значение из стека
в HL
320 CALL 949 ; вызов подпрограммы
воспроизведения
330 CALL 654 ; контроль клавиатуры
340 POP HL ; восстановление HL
350 LD A,E ; A=E
360 CP 255 ; если нажата клавиша,
370 RET NZ ; то возврат в бейсик
380 JR NEXT ; переход на обработку след.
данных
2
При вызове этой подпрограммы из машин-
ных кодов обратите внимание, что прерыва-
ния должны быть разрешены! Иначе, если в
данных первой будет стоять пауза, компью-
тер "зависнет".
Перед использованием этой довольно
страшненькой подпрограммы необходимо соз-
дать для нее массив данных (это и есть са-
мое веселое). В данном случае он должен
располагаться с адреса 60000 (#EA60), но
Вы можете легко изменить его местонахожде-
ние, поменяв число в первой строке этой
подпрограммы.
Данные для каждой ноты должны быть сле-
дующими: сначала два байта длительности
(первый - младший), затем два байта часто-
ты. Если вместо длительности поместить два
нуля, то следующая пара байт будет рас-
сматриваться как длина паузы. Чтобы отме-
тить конец мелодии, вставьте в данные вме-
сто очередной длительности два байта 255.
Длительность паузы измеряется в пятиде-
сятых долях секунды, а в чем измеряется
длительность ноты - не знает, наверное,
никто, хотя рассчитать необходимое значе-
ние все же можно (см. главу 4).
Теперь о недостатках, которых, честно
говоря, хоть отбавляй. Два из них уже бы-
ли упомянуты выше: трудность составления
мелодии и довольно странное измерение дли-
тельности нот. Кроме того, длительность
зависит от частоты. Например, если Вы вве-
дете такие данные: 0,1,100,0,0,1,0,5,255,
255, то не услышите две разные ноты одина-
ковой длины, как ожидали.
Еще один недостаток - возможность прер-
вать исполнение только в промежутке между
нотами. Впрочем, это можно легко испра-
вить:
1415.
10 START LD HL,60000 ; HL=адрес данных
20 NEXT LD E,(HL) ; DE=
30 INC HL ; дли-
40 LD D,(HL) ; тель
50 INC HL ; ность
60 LD A,D ; DE
70 CP 255 ; =
80 JR NZ,CONT ; 65535
90 LD A,E ; ?
100 CP 255 ; если да,
110 JR Z,START ; то мелодия сначала
120 CONT LD A,D ; DE=
130 OR E ; 0 ?
140 JR NZ,BEEP ; если нет, то перейти на BEEP
150 LD E,(HL) ; DE=
160 INC HL ; длитель-
170 LD D,(HL) ; ность
180 INC HL ; паузы
190 PAUSE XOR A ; A=0 (контроль всей клавиа-
туры)
200 IN A,(254) ; опрос клавиш
210 CPL ; инвертирование A
220 AND 31 ; сброс лишних битов
230 RET NZ ; если нажата клавиша, то воз-
врат
240 HALT ; ожидание прерывания
250 DEC DE ; DE=DE-1
260 LD A,D ; DE=
270 OR E ; 0 ?
280 JR NZ,PAUSE ; если нет, то цикл
290 JR NEXT ; переход на обработку след.
данных
300 BEEP LD C,(HL) ; BC=
310 INC HL ; час-
320 LD B,(HL) ; то-
330 INC HL ; та
340 PUSH HL ; сохранение HL
350 PUSH BC ; поместить BC в стек
360 POP HL ; поместить значение из стека
в HL
370 CALL PLAY ; вызов подпрограммы
воспроизведения
380 POP HL ; восстановление HL
390 RET NZ ; то возврат в бейсик
400 JR NEXT ; переход на обработку след.
данных
410 PLAY DI ; запрет прерываний
420 LD A,(23624) ; A=
430 SRL A ; цвет
440 SRL A ; бор-
450 SRL A ; дюра
460 LOOP1 XOR 16 ; инвертирование бита D4
470 OUT (254),A ; вывод A в порт 254
480 LD C,A ; сохранение A
490 PUSH HL ; сохранение HL
500 LOOP2 XOR A ; A=0 (контроль всей клавиа-
туры)
510 IN A,(254) ; опрос клавиш
520 CPL ; инвертирование A
530 AND 31 ; сброс лишних битов
540 JR Z,CONT2 ; если клавиша не нажата, то
продолжить
550 POP HL ; снять значение со стека
560 EI ; разрешение прерываний
570 RET ; возврат
580 CONT2 DEC HL ; HL=HL-1
590 LD A,H ; HL=
600 OR L ; 0 ?
610 JR NZ,LOOP2 ; если нет, то цикл
620 POP HL ; восстановление HL
630 DEC DE ; DE=DE-1
640 LD A,D ; DE=
650 OR E ; 0 ?
660 LD A,C ; восстановление A
670 JR NZ,LOOP1 ; если DE<>0, то цикл
680 EI ; разрешение прерываний
690 RET ; возврат
2
Обратите внимание на то, что одинаковые
данные будут воспроизводиться по-разному
этой и предыдущей подпрограммами.
И, наконец, самый очевидный недоста-
ток - музыка, которая получается с помощью
этих подпрограмм, слишком примитивна. На
ассемблере можно сделать что-нибудь и по-
серьезнее.
Надеюсь, что убедил Вас не пытаться
программировать музыку напрямую в кодах, а
вместо этого приобрести хороший музыкаль-
ный редактор.
Все подпрограммы, приведенные в этой
главе, можно использовать и для создания
эффектов. Для этого достаточно вместо нот
закодировать отдельные ступени эффекта.
Желательно, чтобы каждая ступень была как
можно короче, тогда эффект будет звучать
плавно.