ZX Forum #04
19 ноября 1997

Мир звуков Спектрума - глава 6.2: Программирование эффектов и музыки под музыкальный сопроцессор AY- 3-8910 (AY-3-8912).

<b>Мир звуков Спектрума</b> - глава 6.2: Программирование эффектов и музыки под музыкальный сопроцессор AY-
3-8910 (AY-3-8912).

          6.2. Программирование

   Все звуковые эффекты и музыка  програм-
мируются путем постоянной  смены  значений
регистров с необходимыми задержками.  Осу-
ществить это  может, например, такая  под-
программа:
1415.
 10            LD      HL,60000   ; HL=адрес данных
 20  LOOP      LD      A,(HL)     ; A=байт данных
 30            INC     HL         ; HL=HL+1
 40            CP      255        ; A=255 ?
 50            RET     Z          ; если да, то возврат
 60            CP      16         ; A=16 ?
 70            JR      NZ,REG     ; если нет, то перейти на REG
 80            LD      B,(HL)     ; B=длительность паузы
 90  PAUSE     HALT               ; ожидание прерывания
100            DJNZ    PAUSE      ; цикл
110            JR      CONT       ; перейти на CONT
120  REG       LD      BC,65533   ; BC=адрес порта регистра
130            OUT     (C),A      ; записать номер регистра
140            LD      B,191      ; BC=адрес порта данных
150            LD      A,(HL)     ; A=значение регистра
160            OUT     (C),A      ; записать данные в регистр
170  CONT      INC     HL         ; HL=HL+1
180            JR      LOOP       ; переход к началу
2
   Эта  программа  довольно  примитивна, и
для воспроизведения музыки не очень подхо-
дит, но для создания  простых эффектов - в
самый раз. Перед ее запуском  не  забудьте
подготовить блок данных по  адресу  60000,
состоящий из пар данных и  заканчивающийся
числом 255. Первым значением в каждой  па-
ре  должен быть номер регистра, а вторым -
число, которое нужно записать в  этот  ре-
гистр.  Кроме того, если  первое  значение
равно 16, то второе  интерпретируется  как
задержка (в пятидесятых долях секунды).
   Для воспроизведения музыки  используют-
ся гораздо более сложные подпрограммы, как
правило, работающие во втором режиме  пре-
рываний. Данные для этих подпрограмм обыч-
но хранятся в  значительно  более  удобной
форме, раздельно для каждого из трех кана-
лов. Привести полностью хотя  бы  простей-
ший пример такой подпрограммы в этой  кни-
ге не представляется возможным  из-за  его
сложности, но, если Вы умеете обращаться с
ассемблером, Вам ничего не стоит  сочинить
такую подпрограмму, а я  могу  подсказать,
как это сделать.
   Сначала разберемся с форматом данных. Я
предлагаю следующую систему:  мелодия  бу-
дет задаваться тремя  (по  числу  голосов)
основными блоками данных. Так как  практи-
чески любая мелодия состоит из  одинаковых
фрагментов, повторяющихся в разном  поряд-
ке, логично было бы в главных блоках зада-
вать не саму мелодию, а адреса таких фраг-
ментов. Эти фрагменты обычно называют пат-
тернами (pattern - трафарет, шаблон).
   Итак, в  главных  блоках  могут  содер-
жаться следующие двухбайтовые значения:

 65535 (#FFFF) - конец мелодии
 0     (#0000) - начало цикла
 addr  (#XXXX) - адрес следующего паттерна

   Код "начало цикла" (0) отмечает  место,
с которого начнет  воспроизводиться  мело-
дия при повторении.
   Теперь  займемся  паттернами.  Не  вда-
ваясь в теорию, приведу разработанный мной
формат:

 128           (#80)           - конец паттерна
 129,n         (#81,#XX)       - установить длительность n
 130,n         (#82,#XX)       - шум с частотой n (0...31)
 131,n1,n2     (#83,#XX,#XX)   - шум с частотой n (0...31) +
                                 нота (0...100)
 132,n1,n2     (#84,#XX,#XX)   - прямое задание частоты тона
                                 (0...4095)
 133,addr      (#85,#XXXX)     - задание блока изменения частоты
                                 тона
 134,addr      (#86,#XXXX)     - задание блока изменения частоты
                                 шума
 135,addr      (#87,#XXXX)     - задание блока изменения
                                 громкости
 136,n1,n2,n3  (#88,#XX,#XXXX) - управление генератором
                                 огибающей
 0...100       (#00...#64)     - ноты от ЛЯ субконтроктавы

   Поясню некоторые коды:

129 - Как Вы, наверное, заметили, при  за-
      дании ноты ее длительность не указы-
      вается. Дело в том, что  использует-
      ся длительность, установленная зара-
      нее с  помощью  этой  команды.  Дли-
      тельность измеряется  в  пятидесятых
      долях секунды.
131 - С помощью этого кода Вы  можете  од-
      новременно воспроизводить тон и шум.
133,134,135 -  Эти  коды  задают  дополни-
      тельные  блоки  данных,  указывающие
      способ изменения  частоты тона, час-
      тоты шума и громкости на  протяжении
      звучания ноты. Если после кодов  133
      или 134 вместо адреса блока находит-
      ся 0, то изменение частот отключает-
      ся.  Число от 0 до 15 после кода 135
      указывает на необходимость поддержа-
      ния  постоянного  уровня  громкости,
      соответствующего этому числу.
136 - Этот код управляет генератором  оги-
      бающей.  После  него  должно   нахо-
      диться однобайтовое число от 0 до 7,
      указывающее  на  форму  огибающей  в
      соответствии с таблицей 5 и двухбай-
      товое число, задающее период измене-
      ния огибающей.
0...100 - Эти  коды  задают  ноты.  Код  0
      соответствует ноте ЛЯ  субконтрокта-
      вы, 1 - ЛЯ#, 2 - СИ и т.д.

   В блоке, описывающем изменение  частоты
тона, используются следующие значения:

 128        (#80)       - конец блока
-127...127  (#81...#79) - смещения частоты

   Блок изменения частоты шума будет зада-
ваться в следующем формате:

 128        (#80)       - конец блока
-31...31    (#E1...#1F) - смещения частоты

   А блок изменения громкости пусть  зада-
ется так:

 128      (#80)       - конец блока
 0...15   (#00...#0F) - значения громкости

   Вполне логично было бы сделать эту про-
цедуру работающей во втором режиме  преры-
ваний. Исходя из этого, а также из предло-
женного формата данных, можно  понять, что
для каждого из каналов понадобится  массив
переменных. Я предлагаю следующий его фор-
мат:

  смещение  размер  значение

      0       2     начальный адрес основного блока данных
      2       2     текущий адрес в основном блоке данных
      4       2     начальный адрес блока изменения частоты тона
      6       2     текущий адрес в блоке изменения частоты тона
      8       2     начальный адрес блока изменения частоты шума
     10       2     текущий адрес в блоке изменения частоты шума
     12       2     начальный адрес блока изменения громкости
     14       2     текущий адрес в блоке изменения громкости
     16       2     текущий адрес в текущем паттерне
     18       1     значение текущей длительности
     19       1     счетчик длительности
     20       1     число оставшихся повторений

   Кроме того, понадобится еще по три бай-
та на каждый  канал  для  хранения  темпа,
счетчика темпа и флага разрешения звука.
   В этот пакет  будут  входить  следующие
процедуры:

SINIT - Инициализация  таблиц, подключение
        второго режима прерываний.
SSTOP - Выключение сопроцессора, восстано-
        вление стандартного режима  преры-
        ваний.
SNEW  - Запуск всех трех каналов. При  вы-
        зове этой  подпрограммы  в  регис-
        трах HL, DE и BC должны быть адре-
        са главных блоков данных для кана-
        лов A, B и C соответственно. В ре-
        гистре A должно  находиться  число
        повторений мелодии от 1 до 254 или
        255, если  Вы хотите, чтобы  мело-
        дия повторялась бесконечно.
SNEWA - Запуск канала  A.  В  регистре  HL
        должен быть  адрес блока данных, а
        в регистре A  -  число  повторений
        (аналогично SNEW). Работу  каналов
        B и C эта процедура  не затрагива-
        ет.
SNEWB - Запуск канала  B.  Все  аналогично
        SNEWA.
SNEWC - Запуск канала  C.  Все  аналогично
        SNEWA.
MUTE  - Запрет/разрешение работы. В регис-
        тре A должен быть номер канала  от
        0 до 2 или 3, если Вы  обращаетесь
        ко всем каналам. В регистре B дол-
        жен быть код режима  работы:  0  -
        остановка, 1 - беззвучная  работа,
        2 - воспроизведение.
STATUS - Получение состояния канала. В ре-
        гистре A должен быть номер  канала
        от 0 до 2. По возвращению из  про-
        цедуры STATUS регистр  A  содержит
        код режима работы выбранного кана-
        ла (аналогично B в MUTE).
TEMPO - Установка темпа. В регистре A дол-
        жен быть номер канала от  0  до  2
        или 3, если Вы обращаетесь ко всем
        каналам. В регистре B должно нахо-
        диться значение темпа.

  Итак, начало пакета может выглядеть так:
1415.
  10           ORG     60000
  20           JP      SINIT
  30           JP      SSTOP
  40           JP      SNEW
  50           JP      SNEWA
  60           JP      SNEWB
  70           JP      SNEWC
  80           JP      MUTE
  90           JP      STATUS
2
   Процедура TEMPO может выглядеть так:
1415.
 100  TEMPO    DI
 110           PUSH    HL
 120           PUSH    AF
 130           LD      HL,TEMPS   ; HL=указатель на темпы
 140           CP      A,3
 150           JR      Z,TEMP3
 160           ADD     A,L
 170           LD      L,A
 180           JR      NC,TEMP1
 190           INC     H
 200  TEMP1    LD      (HL),B
 210           INC     HL
 220           INC     HL
 230           INC     HL
 240           LD      (HL),B
 250  TEMP2    POP     AF
 260           POP     HL
 270           EI
 280           RET
 290  TEMP3    PUSH    DE
 300           LD      D,6
 310  TEMP4    LD      (HL),B
 320           INC     HL
 330           DEC     D
 340           JR      NZ,TEMP4
 350           POP     DE
 360           JR      TEMP2
2
   Раз уж пошли обращения к  данным,  надо
привести строки с их описанием:
1415.
 370  CHAN_A   DEFS    21       ; массив переменных для канала A
 380  CHAN_B   DEFS    21       ; массив переменных для канала B
 390  CHAN_C   DEFS    21       ; массив переменных для канала C
 400  MUTS     DEFS    3        ; флаги разрешения звука
 410  TEMPS    DEFS    3        ; темпы
 420  CURTS    DEFS    3        ; счетчики темпов
 430  AYREGS   DEFS    14       ; копии регистров сопроцессора
 440  ENVS     DEFB    0,4,11,13,8,12,14,10    ; формы огибающей
 450  SVOLS    DEFW    #8000,#8001,#8002       ; таблицы измене-
 460           DEFW    #8003,#8004,#8005       ; ния громкости
 470           DEFW    #8006,#8007,#8008       ; для стандартных
 480           DEFW    #8009,#800A,#800B       ; значений
 490           DEFW    #800C,#800D,#800E
 500           DEFW    #800F
 510  NOTES    DEFW    ... ; сюда необходимо записать все значе-
                           ; ния из таблицы 9 от левого верхнего
                           ; угла в порядке сверху - вниз, спра-
                           ; ва - налево
2
   Строка 430 содержит область данных, ко-
торая используется для вывода звука.  Сна-
чала в ней формируются значения  всех  ре-
гистров сопроцессора с  помощью  следующей
подпрограммы:
1415.
 520  SETAY    PUSH    HL
 530           PUSH    AF
 540           LD      AL,AYREGS
 550           ADD     A,L
 560           LD      L,A
 570           JR      NC,SETAY1
 580           INC     HL
 590  SETAY1   LD      (HL),B
 600           POP     AF
 610           POP     HL
 620           RET
2
   Ей надо передать номер регистра в  A  и
его значение в B.
   Затем содержимое этой области копирует-
ся в реальные регистры сопроцессора другой
подпрограммой:
1415.
 630  AYOUT    PUSH    HL
 640           PUSH    DE
 650           PUSH    BC
 660           LD      HL,AYREGS+13
 670           LD      D,13
 680  AYOUT1   LD      BC,65533
 690           OUT     (C),D
 700           LD      B,191
 710           LD      E,(HL)
 720           OUT     (C),E
 730           DEC     HL
 740           DEC     D
 750           JP      P,AYOUT1   ; если D>=0, то перейти на
                                    AYOUT1
 760           POP     BC
 770           POP     DE
 780           POP     HL
 790           RET
2
   Любой из регистров в этой области можно
также прочитать:
1415.
 800  GETAY    PUSH    HL
 810           PUSH    AF
 820           LD      HL,AYREGS
 830           ADD     A,L
 840           LD      L,A
 850           JR      NC,GETAY1
 860           INC     H
 870  GETAY1   LD      B,(HL)
 880           POP     AF
 890           POP     HL
 900           RET
2
   Этой подпрограмме нужно передать  номер
требуемого регистра в A и она  вернет  его
значение в B.

   Строка 440 понадобится  для  дешифрации
кода огибающей. Если любое число из табли-
цы 5 прибавить к метке ENVS и по  получен-
ному адресу прочитать один байт, Вы  полу-
чите значение, которое надо записать в R13.
   Строка 450 будет нужна  для  дешифрации
стандартных уровней громкости.  Для  этого
надо число от 0 до 15 умножить на 2  (мож-
но использовать команду SLA) и прибавить к
метке SVOLS. Полученное значение нужно ис-
пользовать в качестве адреса блока измене-
ния громкости.
   Строка 510 будет полезна  для  дешифра-
ции нот. Если код ноты (от 0 до 100) умно-
жить на 2 (команда SLA) и прибавить к мет-
ке NOTES, а по полученному адресу  считать
двухбайтовое число, Вы  получите  значения
младшего и старшего регистров частоты.
   Теперь займемся основными процедурами:
1415.
 910  STATUS   PUSH    HL
 920           LD      HL,MUTS
 930           ADD     A,L
 940           LD      L,A
 950           JR      NC,STAT1
 960           INC     H
 970  STAT1    LD      A,(HL)
 980           POP     HL
 990           RET
2
   Эта  маленькая, но  полезная  процедура
поможет программисту узнать, в каком  сос-
тоянии находится тот или иной канал.  Нап-
ример, чтобы найти, какой из них свободен.
   Следующая процедура - MUTE:
1415.
1000  MUTE     DI
1010           PUSH    HL
1020           PUSH    AF
1030           LD      HL,MUTS
1040           CP      A,3
1050           JR      Z,MUT2
1060           ADD     A,L
1070           LD      L,A
1080           JR      NC,MUT1
1090           INC     H
1100  MUT1     LD      (HL),B
1110           POP     AF
1120           POP     HL
1130           EI
1140           RET
1150  MUT2     LD      (HL),B
1160           INC     HL
1170           LD      (HL),B
1180           INC     HL
1190           JR      MUT1
2
   Эта  процедура  понадобится,  например,
для временной остановки работы  одного  из
каналов.
   Теперь - процедуры инициализации  кана-
лов:
1415.
1200  SNEWC    PUSH    IX
1210           LD      IX,CHAN_C
1220           PUSH    BC
1230           LD      B,2
1240           JR      SNEW1

1250  SNEWB    PUSH    IX
1260           LD      IX,CHAN_B
1270           PUSH    BC
1280           LD      B,1
1290           JR      SNEW1

1300  SNEWA    PUSH    IX
1310           LD      IX,CHAN_A
1320           PUSH    BC
1330           LD      B,0
1340  SNEW1    DI
1350           PUSH    BC
1360           PUSH    DE
1370           PUSH    HL
1380           PUSH    IX
1390           POP     HL
1400           PUSH    HL
1410           POP     DE
1420           INC     DE
1430           LD      BC,20
1440           LD      (HL),B
1450           LDIR
1460           POP     HL
1470           PUSH    HL
1480           LD      (IX+20),A
1490           LD      (IX+0),L
1500           LD      (IX+1),H
1510           LD      (IX+19),0
1520           LD      E,(HL)
1530           INC     HL
1540           LD      D,(HL)
1550           INC     HL
1560           LD      (IX+2),L
1570           LD      (IX+3),H
1580           LD      (IX+16),E
1590           LD      (IX+17),D
1600           LD      HL,SVOLS+30
1610           LD      (IX+12),L
1620           LD      (IX+13),H
1630           LD      (IX+14),L
1640           LD      (IX+15),H
1650           LD      (IX+18),13   ; длительность по умолчанию
                                      = 1/4
1660           POP     HL
1670           POP     DE
1680           POP     BC
1690           LD      A,B
1700           LD      B,2
1710           CALL    MUTE
1720           LD      B,1
1730           CALL    TEMPO
1740           POP     BC
1750           POP     IX
1760           EI
1770           RET
2
   И, наконец, инициализация всех трех ка-
налов:
1415.
1780  SNEW     PUSH    HL
1790           CALL    SNEWA
1800           PUSH    DE
1810           POP     HL
1820           CALL    SNEWB
1830           PUSH    BC
1840           POP     HL
1850           CALL    SNEWC
1860           POP     HL
1870           RET
2
   Подпрограммы инициализации  подготавли-
вают в массивах переменных  все  необходи-
мые для работы данные.  Они  устанавливают
адреса блоков изменения частоты тона и шу-
ма в положение "не используется"  (заносят
в  них  0).  Выбирают  постоянный  уровень
громкости (15). А также устанавливают дли-
тельность нот по умолчанию равной 1/4  се-
кунды.
   Вот  подпрограмма  подключения  второго
режима прерываний:
1415.
1880  SINIT    LD      A,24
1890           LD      (65535),A
1900           LD      A,195
1910           LD      (65524),A
1920           LD      HL,INTR    ; HL=адрес обработчика
1930           LD      (65525),HL
1940           LD      HL,65024
1950           LD      DE,65025
1960           LD      BC,256
1970           LD      (HL),255
1980           LD      A,H
1990           LDIR
2000           DI
2010           LD      I,A
2020           IM      2
2030           LD      HL,MUTS    ; запрет
2040           XOR     A
2050           LD      (HL),A     ;  работы
2060           INC     HL
2070           LD      (HL),A     ;   всех
2080           INC     HL
2090           LD      (HL),A     ;    каналов
2100           EI
2110           RET
2
   А это подпрограмма, возвращающая  стан-
дартный  режим  прерываний  и  выключающая
сопроцессор:
1415.
2120  SSTOP    DI
2130           LD      A,63
2140           LD      I,A
2150           IM      1
2160           EI
2170           LD      HL,AYREGS
2180           LD      DE,AYREGS+1
2190           LD      BC,13
2200           LD      (HL),B    ; B=0
2210           LDIR              ; очистка области регистров
2220           LD      A,7
2230           DEC     B         ; B=255
2240           CALL    SETAY     ; R7=255 (выключение микшера)
2250           JP      AYOUT     ; вывод регистров в сопроцессор
2
   Теперь займемся  обработчиком  прерыва-
ний. Так как он должен обслуживать три ка-
нала, а массивы переменных легче всего ад-
ресовать  регистром  IX, можно  предложить
такую подпрограмму:
1415.
2260  INTR     PUSH    AF         ; сохранение регистров
2270           PUSH    HL
2280           PUSH    DE
2290           PUSH    BC
2300           PUSH    IX
2310           LD      IX,CHAN_A  ; подготовка регистров
2320           XOR     A
2330           CALL    DISPAT     ;  сопроцессора
2340           LD      IX,CHAN_B
2350           LD      A,1        ;   для всех каналов
2360           CALL    DISPAT
2370           LD      IX,CHAN_C
2380           LD      A,2
2390           CALL    DISPAT
2400           CALL    AYOUT    ; вывод регистров в сопроцессор
2410           POP     IX       ; восстановление регистров
2420           POP     BC
2430           POP     DE
2440           POP     HL
2450           POP     AF
2460           RST     56       ; вызов стандартного обработчика
2470           RET
2
   Этот обработчик для каждого из  каналов
вызывает процедуру-диспетчер (DISPAT), за-
нося в регистр A номер канала, а в регистр
IX - адрес массива его переменных.
   Роль процедуры DISPAT заключается в об-
работке переменных TEMPS, CURTS и MUTS для
указанного канала, а также в вызове основ-
ной подпрограммы создания звука - GETSND.
   Вот текст процедуры DISPAT:
1415.
2480  DISPAT   PUSH    AF
2490           LD      E,A
2500           LD      D,0
2510           CALL    STATUS
2520           OR      A          ; канал остановлен ?
2530           JR      NZ,DISP1
2540           POP     AF
2550           LD      B,A
2560           JR      DISP3
2570  DISP1    LD      HL,CURTS
2580           ADD     HL,DE
2590           LD      A,(HL)
2600           OR      A
2610           JR      Z,DISP2
2620           DEC     (HL)       ; уменьшение счетчика темпа
2630           POP     AF
2640           RET
2650  DISP2    DEC     HL         ; обновление
2660           DEC     HL
2670           DEC     HL         ;  счетчика
2680           LD      A,(HL)
2690           INC     HL         ;   темпа
2700           INC     HL
2710           INC     HL
2720           LD      (HL),A
2730           POP     AF
2740           CALL    GETSND     ; вызов основной процедуры
2750           LD      B,A
2760           CALL    STATUS
2770           CP      1          ; надо "заглушать" ?
2780           RET     NZ
2790  DISP3    LD      C,B        ; "заглушение"
2800           LD      HL,AYREGS+6
2810           LD      A,9        ; канала
2820  DISP4    SLA     A
2830           DJNZ    DISP4
2840           OR      (HL)
2850           LD      (HL),A
2860           INC     HL
2870           ADD     HL,BC
2880           LD      (HL),0
2890           RET
2
   Итак, все сервисные процедуры  приведе-
ны. Осталась только одна - GETSND:
1415.
2900  GETSND   ...
2
   Вот ее-то написание я и предлагаю  Вам.
Но не пугайтесь - я все подробно объясню.
   Скорее  всего, процедура  GETSND  будет
достаточно велика. Может быть, даже больше
всех приведенных процедур, вместе  взятых.
Но ничего трудного в ней нет, а  ее  объем
обусловлен  достаточно  сложным   форматом
данных.
   Задача процедуры GETSND сводится к фор-
мированию в определенных  ячейках  области
AYREGS данных одного из каналов для после-
дующего копирования их в  регистры  сопро-
цессора.
   В качестве  параметров  этой  процедуре
передается номер канала в регистре A (что-
бы она знала, в  каких  ячейках  размещать
данные для частоты, громкости  и  т.п.)  и
адрес массива переменных  в  регистре  IX.
Обратите внимание, что она обязана  сохра-
нить  значение регистра  A!  Возможно, Вам
придется даже завести дополнительную пере-
менную для его хранения.
   Итак,  порядок  действий  в   процедуре
GETSND следующий:

 1. Проверить, не равен  ли  нулю  счетчик
    длительности (IX+19).
 2. Если нет, то продолжить  воспроизведе-
    ние текущей ноты.
 3. Если равен, то выбрать  новую  ноту  и
    начать ее воспроизведение.

   В понятие  "продолжить  воспроизведение
текущей ноты" входит следующее:

 1. Уменьшить счетчик длительности.
 2. Если адрес  одного  из  дополнительных
    блоков равен 0, то  пункты  3...5  для
    этого блока выполнять не надо.
 3. Выбрать очередные значения  из  блоков
    изменения частот и  громкости, исполь-
    зуя переменные  IX+6/IX+7, IX+10/IX+11
    и IX+14/IX+15.
 4. В соответствии с выбранными  значения-
    ми и номером  канала  обновить  с  по-
    мощью процедур GETAY и  SETAY  область
    AYREGS (обратите внимание, что  смеще-
    ния частот могут быть и  отрицательны-
    ми).
 5. Обновить переменные  по адресам  IX+6/
    IX+7, IX+10/IX+11 и IX+14/IX+15 в  со-
    ответствии с пунктом 3.

   "Начать воспроизведение ноты"  включает
в себя только один пункт:

 1. Переписать переменные по адресам IX+4/
    IX+5, IX+8/IX+9, IX+12/IX+13 и IX+18 в
    их счетчики - дубли (IX+6/IX+7, IX+10/
    IX+11, IX+14/IX+15 и IX+19).

   А вот пункт "выбрать новую ноту" - пос-
ложнее:

 1. Выбрать  очередной  байт  из  текущего
    паттерна (адрес - IX+16/IX+17).
 2. Если он не равен  0...100, 130, 131  и
    132 - обработать  как  соответствующий
    управляющий код и перейти к пункту 1.
 3. Соответственно с байтом или его  пара-
    метрами и номером канала обновить  об-
    ласть AYREGS и переменную IX+16/IX+17.

   Теперь об обработке управляющих кодов:

   Код 128:

 1. Выбрать адрес следующего  паттерна  из
    основного блока (адрес в основном бло-
    ке содержится в IX+2/IX+3).
 2. Обновить переменную IX+2/IX+3.
 3. Если адрес паттерна равен нулю, скопи-
    ровать переменную IX+2/IX+3 в IX+0/IX+
    1 и перейти к пункту 1.
 4. Если  адрес  равен  65535, скопировать
    переменную  IX+0/IX+1  в  IX+2/IX+3  и
    уменьшить счетчик повторений  (IX+20).
    Если счетчик  повторений  равен  нулю,
    установить канал в состояние "останов-
    лен" с помощью процедуры MUTE. Перейти
    к пункту 1.
 5. Записать выбранный адрес в IX+16/IX+17
    и "выбрать новую ноту".

   Код 129:

 1. Взять байт, следующий за этим кодом, и
    занести в IX+18. "Выбрать новую ноту".

   Код 133 (134):

 1. Взять адрес, следующий за этим  кодом,
    и поместить его  в IX+4/IX+5 (IX+8/IX+
    9). "Выбрать новую ноту".

   Код 135:

 1. Взять адрес, следующий за этим кодом.
 2. Если он меньше 16, вычислить  соответ-
    ствующий адрес в таблице SVOLS.
 3. Поместить полученный адрес в IX+12/IX+
    13.
 4. "Выбрать новую ноту".

   Код 136:

 1. Установить в регистре громкости задан-
    ного канала значение 16.

 2. Записать в IX+14/IX+15 ноль.
 3. Взять байт, следующий за этим кодом.
 4. Вычислить по таблице ENVS значение R13
    и обновить область AYREGS.
 5. Взять  два байта, следующие  за  кодом
    формы, и занести их в ячейки 11  и  12
    области AYREGS.
 6. "Выбрать новую ноту".

   Теперь о том, как можно рассчитать  но-
мера регистров для заданного канала.  Что-
бы рассчитать номер регистра частоты, дос-
таточно номер канала умножить  на  2  (ADD
A,A). Полученное число будет  номером  ре-
гистра младшего байта частоты. Чтобы полу-
чить номер регистра старшего байта  часто-
ты, полученное значение надо увеличить  на
1 (INC A).
   Чтобы вычислить номер регистра громкос-
ти, надо к номеру канала прибавить 8  (ADD
A,8).
   Если Вы  напишете  процедуру  GETSND, в
Ваших руках окажется довольно мощная прог-
рамма, пригодная для написания как музыки,
так и эффектов.
   И в конце описания этой программы - со-
веты по составлению для нее блоков данных.
   Чтобы ноту повысить или понизить на ок-
таву, необходимо ее значение соответствен-
но увеличить или уменьшить на 12. Ноте  ДО
первой октавы соответствует число 39.
   Значения длительностей Вы можете  взять
из таблицы 11.
   Теперь несколько советов по  программи-
рованию сопроцессора. Для формирования но-
вых тембров можно  использовать  генератор
огибающей, настроенный на периодически из-
меняющуюся громкость  и  большую  частоту.
Особенно  хороших  результатов  можно  до-
биться, настроив его  на  частоту, кратную
частоте основного сигнала.
   Для заглушения музыкального сопроцессо-
ра довольно часто используется  запрещение
всех функций микшера (вывод  байта  255  в
R7), но такой  способ  не  очень  надежен.
Если генератор огибающей настроен  на  пе-
риодически изменяющуюся громкость, то этот
трюк не пройдет:  останется  слышным  щел-
канье. Для полного заглушения  сопроцессо-
ра могу посоветовать такую подпрограмму:
1415.
 10            LD      HL,DATA    ; HL=адрес данных
 20            LD      E,10       ; E=номер первого регистра
 30  LOOP      LD      BC,65533   ; BC=адрес порта регистров
 40            OUT     (C),E      ; вывод E в порт BC
 50            LD      A,(HL)     ; A=значение очередного
                                    регистра
 60            LD      B,191      ; BC=адрес порта данных
 70            OUT     (C),A      ; вывод A в порт BC
 80            INC     HL         ; HL=HL+1
 90            DEC     E          ; E=E-1
100            LD      A,E        ; E=
110            CP      6          ;   6 ?
120            JR      NZ,LOOP    ; если нет, то цикл
130            RET                ; возврат
140  DATA      DEFB    0,0,0,255  ; данные для регистров AY
2
   Во многих случаях требуется определить,
присутствует ли сопроцессор в данном  ком-
пьютере. Некоторые делают это проверяя тип
компьютера (48K/128K), но этот  способ  не
совсем справедлив, ведь AY может стоять  и
на старом добром Спектруме.  Вот  подпрог-
рамма, определяющая присутствие  сопроцес-
сора более достоверно:
1415.
 10            LD      BC,65533   ; BC=адрес порта регистров
 20            XOR     A          ; A=0
 30            OUT     (C),A      ; выбор регистра 0
 40            LD      B,191      ; BC=адрес порта данных
 50            OUT     (C),A      ; вывод 0 в выбранный регистр
 60            LD      B,255      ; BC=адрес порта регистров
 70            IN      A,(C)      ; ввод значения из выбранного
                                    регистра
 80            OR      A          ; A=0 ?
 90            RET                ; возврат
2
   Если  после  вызова  этой  подпрограммы
флаг Z  сброшен,  то  сопроцессор  присут-
ствует. В противном случае - нет.
   И напоследок хочу рассказать  об  одном
довольно интересном приеме. Он очень  час-
то используется во многих программах.  Чи-
тая данные из регистров громкости и преоб-
разовывая  их  соответствующим  образом  в
графическую информацию одновременно с вос-
произведением музыки, можно сделать цвето-
музыку или пиковые индикаторы уровня  сиг-
нала.



Другие статьи номера:

Help - Описание оболочки электронного издания "ZX-FORUM 4".

Секреты успешного дизайна - глава для книги "Дизайн Ваших программ"

Экранные эффекты - Бегущая строка из R-Type.

Экранные эффекты - гашения экрана из Zynaps.

Экранные эффекты - "сворачивание" экрана из Comando Tracer.

Экранные эффекты - плавное "затухание" экрана из Сommando Tracer.

Экранные эффекты - модификация символьного набора для получения оригинального стилизованного шрифта из игры Rockstar.

Экранные эффекты - "выбегающая строка" из игры Rockstar.

Экранные эффекты - "наливающийся" экран из игры Rockstar.

Экранные эффекты - сложный многоступенчатый эффект из игры Bubbler.

Новые 40 лучших процедур - скроллинг экрана, слияние двух картинок, инвертирование экрана, поворот символов, замена атрибутов, заливка замкнутого контура, вычисление адресов в экране, копирование части экрана и т.д.

Технология спрайтов - часть 1: введение.

Технология спрайтов - часть 2: охота на спрайты (поиск и выдирание).

Технология спрайтов - часть 3: форматы спрайтов.

Технология спрайтов - часть 4: форматы спрайтов с маской.

Технология спрайтов - часть 5: структура спрайтовых блоков (как уживаются в памяти спрайт и маска, какие данные помогают нам оперативно находить адрес спрайта в памяти и многое другое.)

Технология спрайтов - часть 6: подготовка данных к печати.

Технология спрайтов - часть 8: печать спрайтов (координаты заданы в знакоместах).

Технология спрайтов - часть 9: печать спрайтов (координаты заданы в пикселях).

Технология спрайтов - часть 10: обзор программ для работы со спрайтами и графикой.

Мир звуков Спектрума - глава 1: Физика звука.

Мир звуков Спектрума - глава 2: Оператор BEEP, Создание эффектов на BEEPе, Создание музыки на BEEPе.

Мир звуков Спектрума - глава 3: Как получается звук (устройство BEEP'ра и способы звукоизвлечения).

Мир звуков Спектрума - глава 4: Программирование звука на ассемблере.

Мир звуков Спектрума - глава 4.1: Программирование звуковых эффектов - Тон, Шум, Комплексы эффектов.

Мир звуков Спектрума - глава 4.2: Программирование звуковых эффектов - Управление громкостью.

Мир звуков Спектрума - глава 4.3: Программирование звуковых эффектов - Управление тембром.

Мир звуков Спектрума - глава 4.4: Программирование звуковых эффектов - Программирование музыки.

Мир звуков Спектрума - глава 4.5: Программирование звуковых эффектов - Многоголосые мелодии (полифония).

Мир звуков Спектрума - глава 4.6: Обработка внешних сигналов - оцифровка.

Мир звуков Спектрума - глава 4.7: Обработка внешних сигналов - Реверберация.

Мир звуков Спектрума - глава 4.8: Синтезирование речи.

Мир звуков Спектрума - глава 4.9: воспроизведение звука на прерываниях.

Мир звуков Спектрума - глава 5: Оператор PLAY для музыкального сопроцессора AY- 3-8910 (AY-3-8912).

Мир звуков Спектрума - глава 5.1: Создание эффектов оператором PLAY.

Мир звуков Спектрума - глава 5.2: Создание музыки на PLAYе.

Мир звуков Спектрума - глава 6.1: описание регистров музыкального сопроцессора AY- 3-8910 (AY-3-8912).

Мир звуков Спектрума - глава 6.2: Программирование эффектов и музыки под музыкальный сопроцессор AY- 3-8910 (AY-3-8912).

Мир звуков Спектрума - глава 7: Обзор программного обеспечения ZX-Spectrum для создания звуков и музыки.

Мир звуков Спектрума - глава 7.1: Редактор звуковых эффектов SUPER SOUND.

Мир звуков Спектрума - глава 7.2: Музыкальный редактор Wham the Music Box.

Мир звуков Спектрума - приложения 1, 2: листинги звуковых эффектов SUPER SOUND'а, советы по использованию ассемблера.


Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Newвости - Как обстоят дела у Могилевской группы Fenomen.
Авторское описание - Описание MMD v2.21
Тема - Enlight'97 - глазами очевидца.
phONOmania - база данных по телефонным номерам активных ZX сценеров.
От авторов - Последний номер в этом году...

В этот день...   16 апреля