4.5. Многоголосые мелодии
Хотя в предыдущей главе я старательно
доказывал Вам тщетность попыток программи-
рования музыки на ассемблере, Вы все-таки
должны знать основные принципы этого заня-
тия.
Сейчас я опишу создание многоголосой
музыки, то есть музыки, в которой может
звучать две или больше ноты одновременно.
Первым примером будет подпрограмма,
имитирующая двухголосое звучание:
1415.
10 DI ; запрет прерываний
20 LD D,200 ; D=частота 1
30 LD E,50 ; E=частота 2
40 LD H,150 ; H=длительность
50 XOR A ; A=бордюр для голоса 1 (0)
60 EX AF,AF' ; смена регистров A и F на
альтернативные
70 XOR A ; A=бордюр для голоса 2 (0)
80 LD C,E ; C=счетчик 1
90 LD B,D ; B=счетчик 2
100 BEEP EX AF,AF' ; смена регистров A и F
(смена голоса)
110 DEC C ; C=C-1
120 JR NZ,CONT ; если C<>0, то перейти на
CONT
130 LD C,E ; восстановить счетчик 1
140 XOR 16 ; инвертировать бит D4 голоса
1
150 CONT OUT (254),A ; вывести A в порт 254
160 EX AF,AF' ; смена регистров A и F
(смена голоса)
170 DEC B ; B=B-1
180 JR NZ,CONT2 ; если B<>0, то перейти на
CONT2
190 LD B,D ; восстановить счетчик 2
200 XOR 16 ; инвертировать бит D4 голоса
2
210 CONT2 OUT (254),A ; вывести A в порт 254
220 INC L ; L=L+1
230 JR NZ,BEEP ; если L<>0, то перейти на
BEEP
240 NOP ; резерв
250 NOP ; резерв
260 DEC H ; H=H-1
270 JR NZ,BEEP ; если H<>0, то перейти на
BEEP
280 EI ; разрешение прерываний
290 RET ; возврат
2
Теперь поясню некоторые детали.
Два альтернативных регистра A использу-
ются первым и вторым голосами для хранения
цвета бордюра и состояния динамика.
Странная операция с регистром L перед
завершением цикла предназначена для "рас-
тягивания" длительности. Если ее убрать,
то звучание этой подпрограммы станет нас-
только кратковременным, что Вы можете его
даже не услышать.
Два байта резерва (операции NOP) Вы мо-
жете использовать для изменения частоты
обоих голосов во время воспроизведения.
Для этого вместо "NOP" нужно вставить INC
D или DEC D для первого голоса и INC E или
DEC E для второго.
Эту подпрограмму можно использовать на
ассемблере (см. предыдущую главу) или на
бейсике (в данном случае параметры сле-
дует заносить оператором POKE в следующие
ячейки : ADDR+2 - частота 1, ADDR+4 - час-
тота 2, ADDR+6 - длительность, где ADDR -
адрес расположения подпрограммы в памяти).
Следующие две многоголосые подпрограм-
мы очень похожи друг на друга, но первая
звучит значительно тише и несколько чище
второй.
Вот они:
1415.
10 DI ; запрет прерываний
20 LD HL,2000 ; HL=длительность
30 LOOP1 LD IX,FRQS ; IX=адрес таблицы частот
40 LD B,5 ; B=число голосов
50 LOOP2 DEC (IX+0) ; байт по адресу IX+0
уменьшить на 1
60 JR NZ,NOSIGN ; если не 0, то перейти на
NOSIGN
70 LD A,24 ; A=цвет бордюра + 24
80 OUT (254),A ; вывод A в порт 254
90 LD A,(IX+5) ; обновление счетчика
100 LD (IX+0),A ; текущего канала
110 XOR A ; A=цвет бордюра (0)
120 OUT (254),A ; вывод A в порт 254
130 NOSIGN INC IX ; IX=IX+1
140 DJNZ LOOP2 ; цикл
150 DEC HL ; HL=HL-1
160 LD A,H ; HL=
170 OR L ; 0 ?
180 JR NZ,LOOP1 ; если нет, то цикл
190 EI ; разрешение прерываний
200 RET ; возврат
210 FRQS DEFB 1,1,1,1,1 ; счетчики для 5 каналов
220 DEFB 10,20,30 ; частоты для
230 DEFB 40,50 ; 5 каналов
10 DI ; запрет прерываний
20 LD HL,2000 ; HL=длительность
30 LOOP1 LD IX,FRQS ; IX=адрес таблицы частот
40 LD B,5 ; B=число голосов
50 LOOP2 DEC (IX+0) ; байт по адресу IX+0
уменьшить на 1
60 JR NZ,NOSIGN ; если не 0, то перейти на
NOSIGN
70 LD A,(IX+5) ; A=содержимое IX+5
80 XOR 1 ; инвертирование бита D0
90 LD (IX+5),A ; содержимое IX+5=A
100 LD A,0 ; A=цвет бордюра
110 JR Z,NOSIGN ; если D0 содер. IX+5=0, то
перейти на NOSIGN
120 OR 24 ; установить в 1 биты D3 и
D4 регистра A
130 OUT (254),A ; вывод A в порт 254
140 LD A,(IX+10) ; обновление счетчика
150 LD (IX+0),A ; текущего канала
160 NOSIGN INC IX ; IX=IX+1
170 DJNZ LOOP2 ; цикл
180 DEC HL ; HL=HL-1
190 LD A,H ; HL=
200 OR L ; 0 ?
210 JR NZ,LOOP1 ; если нет, то цикл
220 EI ; разрешение прерываний
230 RET ; возврат
240 FRQS DEFB 1,1,1,1,1 ; счетчики для 5 каналов
250 DEFB 0,0,0,0,0 ; буферы для 5 каналов
260 DEFB 10,20,30 ; частоты для
270 DEFB 40,50 ; 5 каналов
2
Эти подпрограммы заводят счетчики для
каждого из каналов и последовательно их
уменьшают. Если какой-либо из счетчиков
становится равным 0, на динамик выводится
сигнал, а в данный счетчик заносится час-
тота из таблицы.
В данных примерах подпрограммы вос-
производят по пять голосов, но Вы може-
те легко изменить их число, модифицировав
значения в строках 40 и 90 для первой под-
программы или 40,70,90 и 140 (в строку 140
надо вставить число голосов, умноженное на
2) - для второй. При этом надо также скор-
ректировать таблицы частот.
Хотя голосов может быть довольно мно-
го (до 85), увлекаться их количеством не
стоит, так как чем их больше, тем хуже ка-
чество. Впрочем, вряд ли найдется гений,
способный написать мелодию на 85 голосов.
Если Вы хотите использовать многоголо-
сие, но в конкретный момент времени Вам
надо воспроизвести меньшее число голосов,
чем задано, то неиспользуемым голосам на-
до присвоить частоты, совпадающие с часто-
тами используемых голосов.