RUSH #01
29 мая 1999

Spectrum программинг - Звуковые эффекты для музыкального процессора и их совмещение с основной мелодией.

(C)1997-99, А.Безуглый (Ticklish Jim/BIS/
Rush)

    ЗВУКОВЫЕ ЭФФЕКТЫ ДЛЯ МУЗЫКАЛЬНОГО
       ПРОЦЕССОРА И ИХ СОВМЕЩЕНИЕ
           С ОСНОВНОЙ МЕЛОДИЕЙ

    Итак,  музпроцессор... Давно прошли те
времена,   когда   народ   довольствовался
непритязательными   бибиканьями   динамика
SPECCY  во  время игры. Сейчас всякий, кто
пишет свою игру обязательно включает в нее
музыку. Естественно, для AY'а. Кто-то идет
дальше    и    поддерживает   LPT   COVOX,
SOUNDRIVE,   GENERAL  SOUND...  У  кого-то
музыка лучше, у кого-то хуже, но дело не в
этом  -  сейчас программа без музыкального
сопровождения  для  AY вызывает по меньшей
мере  удивление.  Впрочем, музыка музыкой,
однако  иногда ее бывает недостаточно. Так
хочется  услышать  шарканье  ног героя или
капанье  воды,  например, а слышишь только
какой-то затянутый мотив (хорошо еще, если
музыку   можно  отключить).  Но  вдруг  ты
все-таки слышишь заветный шорох ветра и...
Замечаешь,   что   вокруг   царит  мертвая
тишина, которую не могут оживить даже твои
шаги.     Тут     поневоле     вспоминаешь
непревзойденный  цикл  игр  о  DIZZY,  где
сквозь    музыку   явственно   пробиваются
звуки... на динамика бипера. В общем, куда
ни  кинь  - всюду клин. Да, изредка все же
встречаются  программы, в которых звуковые
эффекты  выводятся  параллельно с музыкой,
но таких примеров довольно мало.
    Надеюсь, данная статья поможет кому-то
при написании своей собственной игрушки. Я
не   претендую   на   истину  в  последней
инстанции,  более того, уверен, что кто-то
решил/решит  данную проблему изящнее меня,
но все-таки...
    Во  время  работы над "CSC: Deja Vu" в
определенный   момент   встал   вопрос   о
музыкальном  сопровождении  игры.  Помня о
реакции  публики на отсутствие AY-музыки в
CSC-1  (кстати,  есть уже версия для машин
со  128К  ОЗУ.  Причем музыка играет как в
меню,   так   и   во   время  игры.)  было
единогласно  решено  озвучить  новую игру.
Через  некоторое  время  стало  ясно,  что
просто   музыки   не   достаточно.   Panda
выстренько  состряпал  с  десяток эффектов
и...  Работа  застопорилась. Никто не знал
как   совместить  музыку  и  эффекты.  Все
попытки  заканчивались неудачей - шипение,
хрипы  и  больше  ничего.  Даже  работа со
специально     написанной    двухканальной
музыкой  ничего  не  дала. Хотя удивляться
нечему: Panda музыку пишет, но и только, а
я  вообще  далекий  от этого дела человек.
Так  или  иначе, но вопрос об эффектах был
отложен  на  неопределенное  время.  Да  и
вообще,  где-то  в  конце мая '97го работа
над  игрой  прекратилась.  Виной тому были
мои   собственные  и  ничьи  более  глюки.
Где-то   в  середине  осени  1997  года  я
побывал  в Севастополе, где познакомился с
Dismaster'ом  и  Squizer'ом (это не считая
банды  SMASH'евцев).  В  то  время я опять
начал  подумывать о продолжении работы над
CSC  (к  тому  моменту  возникла программа
АВТОМАСКИ,  но  поломался  мой компьютер),
поэтому    не   преминул   воспользоваться
случаем   и   договорился  с  Dismaster'ом
насчет  специального player'а для музыки и
спецэффектов. Договорился, уехал... Прошло
три  месяца...  Dis'а,  вероятно, обо всем
забыл  (я,  впрочем,  тоже хорош, так и не
удосужился  написать  письмо ни Squizer'у,
ни Dis'е), а на клич Mighty Hacker'а никто
и  не  думал  откликаться.  Короче говоря,
помощи  ждать  было  не  от  кого,  вот  и
пришлось  самому  вплотную заняться данной
проблемой.
    Ниже   приводится   пример   небольшой
программки,      которую     я     снабдил
исчерпывающими,     на     мой     взгляд,
комментариями.  Думаю,  разобраться  что к
чему  особого  труда не составит. Да, пока
не  забыл - моя программа расчитана на то,
что  звуковые  эффекты выводятся по каналу
'B',   а   музыка   двухканальная.  Можно,
конечно,  убрать последнее ограничение, но
тогда   придется   пожертвовать   чистотой
звучания   спецэффекта   и   смириться   с
наложением,  которое  неизбежно возникнет.
Но   каждый   делает  по-своему,  так  что
смотрите   сами.   Литература,  которой  я
пользовался,  пока  разбирался  с  работой
AY'ка  немногочисленна:  ZX-РЕВЮ  #5'95  и
незабвенная   "ZX-SPECTRUM  и  TR-DOS  для
пользователей  и программистов" А.Ларченко
и Н.Родионова.

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

 10 RANDOMIZE USR 49152:  LET A=65533:
    LET B=0: REM Звуковой эффект  написан
    в ProTracker'е и выгружен на  диск
    вместе с проигрывателем по адресу
    49152
 20 RANDOMIZE USR 49158: LET B=B+1:
    OUT  A,9:  PRINT AT 0,0;"Громкость
    канала B=";IN A;" "';"Номер текущей
    ноты=";B;" ": REM В этой строке считы-
    вается информация о  громкости   для
    канала  В;  об  окончании звучания
    говорит  0  на экране и тишина в
    динамике;  число  В является длиной
    LEN, о котой  речь  будет  ниже.
 30 PAUSE  0: IF INKEY$  <> "q" AND
    INKEY$ <> "Q" THEN GOTO  20:   REM
    Эта   строка   необходима  для
    пошагового исполнения спецэффекта.

Вычислив  длину (число В) можно переходить
к процедурам на Ассемблере. Загружаем файл
FX   (можно   не   грузить,   если  память
компьютера  не  была  очищена после работы
Бейсик-программы)   с  нужным  эффектом  и
последовательно   выполняем   подпрограммы
MAKE   и  PACKER.  Первая  необходима  для
создания   в  памяти  массива  данных  для
регистров  музпроцессора,  а  вторая - для
небольшой   оптимизации   данного  массива
(оптимизация неполная, т.к. можно выиграть
еще один байт с каждой ноты).
    После  этого  сохраняем  готовый  блок
данных  с  адреса,  на  который  указывает
переменная  SOUND  (40000),  длиной  LEN*4
(упакованный,   хотя,   как  сказал  выше,
возможен и LEN*3).
    Теперь         можно        переходить
непосредственно    к   демонстрации.   Как
установить  музыку  на  прерывания, думаю,
никому   об'яснять   не   надо.  Но  перед
инициализацией   проигрывателя  необходимо
внести  в  него  небольшие  изменения. Для
этого  надо  перебросить блок TO_PLAYER по
адресу, равному адрес_загрузки_музыки+1351
(для  проигрывателя из PT2.1). Длина блока
97 байт.
    Кто-то    может    удивиться:   "Зачем
полностью  убирать обработку целого канала
из  проигрывателя, если там и так пусто?!"
В  качестве  ответа я могу лишь предложить
поробовать    НЕ   вносить   изменений   в
проигрыватель - послушаете и сравните.
    Ладно, с этим разобрались. Сейчас пару
слов    о    программе,    отвечающей   за
проигрывание  спецэффекта.  Я  сделал так,
чтобы  звук  выдавался  на  AY при нажатии
клавиши  FIRE  на кемпстоне (кстати, чтобы
завершить  работу  программы  надо  нажать
одновременно  UP, DOWN, LEFT, RIGHT на том
же   кемпстоне).   Конечно,   в  игре  вам
придется добавить процедуру выбора нужного
звука  и  т.д.  и  т.п. Но в данном случае
этого  не  требуется, поэтому считаем, что
есть лишь один SFX, который должен звучать
при  нажатии  определенной  клавиши  и  не
прерываться  до тех пор, пока не прозвучит
последняя  нота.  Вполне  естественно, что
нота   SFX   должна   звучать  после  ноты
композиции,   т.е.  раз  в  прерывание.  В
общем,    смотрите    комментарии,    т.к.
собственно  описание работы моей программы
подошло к концу.

(C)1998, T.J. 

MUS             ORG 49152
;               .INCBIN MUSIC
                ORG 40000
;               .INCBIN fx2 
                ;PACK LENGT=136 bytes

EFFECT          ORG 49152
;               .INCBIN FX
                ;PT-module WITH SFX

FXBUF           EQU 32768

                ORG 25000
                JR BEGIN  
                ;PLAY MUSIC & SFX

                CALL MAKE
                ;MAKE SOUND FX
;WORK WITH FILE AS LOADED AT
;"EFFECT"-ADRESS
                JP PACKER
                ;PACK SOUND FX

BEGIN           DI
                LD HL,TO_PLAYER
                LD DE,MUS+1351
                LD BC,97
                LDIR
;Внесли изменения в проигрыватель мелодии
                LD A,#25
                LD I,A
                IM 2
                LD A,195
                LD HL,IMMER
                LD (23670),A
                LD (23671),HL
;Включили прерывания 2го рода
                CALL MUS
;Инициализировали проигрыватель
                EI
                HALT
M1              XOR A
                IN A,(31)
                CP 15
                JR Z,EXIT
;Если нажаты 4 клавиши кемпстона,
;то перейти на процедуру завер-
;шения работы программы
                CP 16
                JR NZ,M1
;Если не нажата клавиша ОГОНЬ,
;то перейти на начало цикла
                LD A,1
                LD (SND_PR),A
;Выбрали номер SFX
K1              CALL NASTR
;Указали параметры для данного SFX
;(адрес массива данных и длина SFX)
                LD A,#3A
                LD (K1),A
;Блокировали  вызов процедуры обновления
;параметров с той целью,
;чтобы SFX доиграл до конца, прежде чем
;придет  очередь следующего  SFX
;(конечно,  можно  выполнить блокировку 
;поизящнее,но, повторяю, в данном случае
;это не играет роли, поэтому меня уст-
;раивает превращение CALL NASTR в
;LD A,(NASTR)) и перешли на на-
;чало цикла.
                JR M1

;Процедура остановки работы
;демо-программы.
;Перед  завершением  устанавливаются
;прерывания 1го рода, отклю-
;чается проигрыватель  музыки,
;глушится  канал  SFX и возврат в
;основную программу.

EXIT            DI
                LD A,#3F
                LD I,A
                IM 1
                CALL MUS        ;MUSIC OFF
                LD BC,65533
                LD A,9
                OUT (C),A
                XOR A
                LD B,#BF  ;CHANNEL 'B' OFF
                OUT (C),A
                EI
                RET

;Процедура обработки прерываний. Надеюсь,
;объяснять ничего не требуется

IMMER           DI
                PUSH HL
                PUSH DE
                PUSH BC
                PUSH AF
                EX AF,AF'
                PUSH AF
                EXX
                PUSH HL
                PUSH DE
                PUSH BC
                EXX
                PUSH IX
                PUSH IY
                CALL MUS+6
;Вызов проигрывателя SFX
                CALL PLR
                POP IY
                POP IX
                EXX
                POP BC
                POP DE
                POP HL
                EXX
                POP AF
                EX AF,AF'
                POP AF
                POP BC
                POP DE
                POP HL
                EI
                RET

SOUND           DEFW 40000
SND_PR          DEFB 0
LEN             DEFB 8  ;LENGT OF SFX (/4)

;PLAYER FOR SOUND FXS
;WORK ONLY WITH CHANNEL 'B'!!!

;Проигрыватель для SFX.

PLR             LD A,(SND_PR)
                OR A
                RET Z
;Возврат, если по адресу SND_PR находится
;0, т.е. никакой SFX не
;выбран
ADR_SND         LD HL,40000
;В HL адрес начала SFX
;(устанавливается п/п NASTR)
                LD DE,#BFFF
                LD A,80
;В А длина SFX (также устанавливается п/п
;NASTR)
X3              EX AF,AF'
;Далее следует вывод данных в регистры
;сопроцессора 2,3,6,7 и 9,
;причем данные для 3 и 9 распаковываются
;из одного байта
                LD C,253
                LD B,E
                LD A,2  
                ;SELECT CHANNEL 'B'
                OUT (C),A
                LD A,(HL)
                LD B,D
                OUT (C),A
                INC HL
                LD A,6
                LD B,E
                OUT (C),A
                LD A,(HL)
                LD B,D
                OUT (C),A
                INC HL
                LD A,7
                LD B,E
                OUT (C),A
                IN A,(C) 
                ;OLD CONSEQUENCE
                OR (HL)  
                ;ADD NEW & OLD
;Эти две строки нужны были для того,
;чтобы наш SFX не заглушил
;остальные каналы, используемые
;для вывода основной мелодии
                LD B,D
                OUT (C),A
                INC HL
                LD A,3       ;SEL. CH. 'B'
                LD B,E
                OUT (C),A
                LD A,(HL)
                RRA
                RRA
                RRA
                RRA
                AND #0F
;Значение для R3 сохранялось в старшем 
;полубайте
                LD B,D
                OUT (C),A
                LD A,9      
                ;VOLUME OF CH 'B'
                LD B,E
                OUT (C),A
                LD A,(HL)
                AND #0F 
;WITHOUT 4th BIT! (огибающая)
;Значение для R9 сохранялось
;в младшем полубайте
                LD B,D
                OUT (C),A
                INC HL
                EX AF,AF'
                DEC A
                LD (SND_PR),A
;До тех пор пока SFX не прозвучит
;полностью, переменная не будет
;обнуляться.
                JR NZ,HLP     
                ;ONLY FOR INTERRUPTS
;Корректируем значения адреса и длины SFX
;для следующей ноты,
;которая будет звучать в следующем 
;прерывании
                LD A,#CD
                LD (K1),A
;По окончании звучания SFX необходимо
;восстановить вызов процедуры выбора па-
;раметров для следующего SFX (CALL NASTR)
                RET
NASTR           LD A,(LEN)
                LD HL,(SOUND)
HLP             LD (X3-1),A
                LD (ADR_SND+1),HL
                RET
;Таблица  TABL содержит список регистров
;AY, которые используются моей программой.
;Т.к.  для  эффектов  у  нас отведен
;только канал В, то нам необходим лишь 
;регистры 2,3 (чистого и  грубого  тона
;соответственно), 6 (шума), 7 (смеситель)
;и 9 (громкость для В).
;Я не использовал регостры 11,12 и 13
;(частота и  тип огибающей)
;в целях экономии памяти, но кто пожелает,
;тому не составит труда переделать мою
;программу по своему вкусу  (хотя, как
;показывает практика, при  создании  муз.
;спецэффектов  без  огибающей можно вполне
;обойтись), не  стоит забывать, что это
;просто элементарный пример работы со
;звуком.
;Данная таблица используется только 
;процедурами MAKE и PACK.

TABL            DEFB 2,6,7,3,9
                DEFB 255

;Подпрограмма создания массива данных.

MAKE            CALL EFFECT
;Инициализировали проигрыватель
                LD IX,FXBUF
;В IX заносим адрес буфера
                LD A,(LEN)
                LD B,A    
;В В - количество нот
M11             PUSH BC
                PUSH IX
                CALL EFFECT+6
;Проиграли ноту
                POP IX
                LD HL,TABL
M3              LD BC,65533
                LD A,(HL)
                CP 255
                JR Z,M2
                OUT (C),A
                IN A,(C)
;Считали данные из нужного регистра
                LD (IX+0),A
;Занесли в буфер
                INC HL
                INC IX
                JR M3
M2              POP BC
                DJNZ M11    ;Повторяем
                CALL EFFECT
;Отключили проигрыватель
                RET

;Подпрограмма упаковки массива данных

PACKER          LD IX,FXBUF  
;В IX адрес буфера
                LD HL,(SOUND) 
;В HL адрес, с какого будет рас-
;пологаться упакованный блок
                LD A,(LEN)
                LD B,A 
;В В - количество нот
L1              LD A,(IX+0)
                LD (HL),A      ;R2
                INC HL
                LD A,(IX+1)
                LD (HL),A      ;R6
                INC HL
                LD A,(IX+2)
                LD (HL),A      ;R7
                INC HL
                LD A,(IX+3)
                AND #0F
                RLA
                RLA
                RLA
                RLA
                LD C,A
                LD A,(IX+4)
                AND #0F
                OR C
                LD (HL),A      ;R3+R9
                INC HL
;Вместо 5 байт на одну ноту мы получили 4.
;Полная длина готового блока равна LEN*4.
;Если же  использовать  огибающую,  то 
;придется  отказаться  от
;совмещения  R3  и  R9 (т.к. в 9м регистре
;необходимо будет учитывать  4й  бит,
;хотя можно будет об'единить R3 и R13 - 
;в обоих
;используются только младшие 4 бита.)
                LD DE,5
                ADD IX,DE
                DJNZ L1 ;Повторяем цикл
                RET

;CHANGES FOR ProTracker2.1 PLAYER
;ADRES=LOAD_ADR+1351 
;(for PT2.1 by Golden Disk)
;     =LOAD_ADR+1857 
;(for PT2.4 by GD & Fantom Family)
;LENGT=97 bytes
;CHANNEL 'B' NOT USED!!!
 IT'S ONLY FOR SOUND FXS!!!

;Новый блок для проигрывателя

TO_PLAYER       LD B,D
                OUT (C),A       ;R13
                LD B,E
                OUTD
                DEC A
                LD B,D
                OUT (C),A       ;R12
                LD B,E
                OUTD
                DEC A
                LD B,D
                OUT (C),A       ;R11
                LD B,E
                OUTD
                DEC A
                LD B,D
                OUT (C),A       ;R10
                ; (VOLUME 'C')
                LD B,E
                OUTD
                DEC A           ;R9
                ; (VOLUME 'B')!!!
                DEC HL
;Предыдущие две строки гарантируют,
;что никакие данные из данной
;композиции не будут выдаваться на 
;канал В.
                DEC A
                LD B,D
                OUT (C),A       ;R8
                ; (VOLUME 'A')
                LD B,E
                OUTD
                DEC A
                LD B,D
                OUT (C),A       ;R7 
                ; (MIXER!!!)
                LD B,E
;А здесь мы  делаем  так,  чтобы
;наши собственные параметры для
;канала  В нашли  путь  к  слушателю
;(обнуляем биты 1 и 4, т.е.
;разрешаем выдачу тона и шума для
;канала В)
                LD A,(HL)
                AND #2D         ;!!!
                ; (FOR 'B')
                LD (HL),A
                OUTD
                LD A,6
                LD B,D
                OUT (C),A       ;R6
                LD B,E
                OUTD
                DEC A
                LD B,D
                OUT (C),A       ;R5
                LD B,E
                OUTD
                DEC A
                LD B,D
                OUT (C),A       ;R4
                LD B,E
                OUTD
;Корректируем Аккумулятор так,
;чтобы в нем оказалась 1.
;Это  необходимо  для  того,
;чтобы обойти выдачу данных, предус-
;мотренных  исполняемой  композицией,
;в  регистры чистого и гру-
;бого тона канала В.
                SUB 3
                DEC HL          ;R3 
                ; (FOR 'B'!!!)
                DEC HL          ;R2
                LD B,D
                OUT (C),A       ;R1
                LD B,E
                OUTD
                DEC A
                LD B,D
                OUT (C),A       ;R0
                LD B,E
                OUTD
                DEFS 11
;Последняя строчка необходима  для
;дополнения блока до 97 байт.

 Для новой версии редактора PT3.31
 by Golden Disk изменения вносятся
по адресу LOAD_ADR+1825:

                AND 45
                ;отключаем канал "B"
                OUT (C),A
                INC L
                LD B,D
                OUT (C),L
                LD B,E
                OUTI
                INC L
                DEFS 3

    Думаю,   разобраться  будет  несложно.
Лишь  отмечу, что данный способ совмещения
музыки  и  эффетов  на мой взгляд является
простейшим, т.к. используется традиционный
плейер и небольшая процедурка выдачи звука
в    канал.    Самая   сложная   часть   -
непосредственно  создание  звука.  Точнее,
создать-то  как  раз  просто  -  в  том же
редакторе,  но  относительно  сложно потом
получить  данные.  Может, только для меня,
не    спорю.    Да,    напиши   кто-нибудь
человеческую  программку,  я  был бы очень
рад,  но за неимением лучшего... Возможно,
у  кого-то  подобный  soft есть, но мне не
встречался.  В  основном,  как  я понимаю,
авторы  пишут либо собственные плейеры для
мелодий  и эффектов (например, так сделали
ребята  из  BITMUNCHERS  в  своей  игрушке
KLIDEMINER),   или   дико  извращаются  со
стандартными  (демоверсия  MARIO  BROS  от
OMEGA  HACKERS).  Не  знаю,  каким образом
поступает  Слава Медноногов - не задавался
целью узнать.
    В любом случае, что хотел я рассказал,
т.к.  до  сих  пор  так  нигде  и не видел
статьи, посвященной данной теме. Опять же,
либо все все знают, либо всем все пофиг.
    Данный  материал в свое время постигла
та  же  участь, что и статью об АВТОМАСКЕ.
Хочется надеяться, что хоть сейчас, спустя
два  года, это кто-то прочитает и применит
на практикe.




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

Похожие статьи:
Новости - Комикс, городской конкурс, областной конкурс, untergrund.net, нeмного о музыкe.
Мир звуков Спектрума - глава 1: Физика звука.
От авторов - Редакция.

В этот день...   25 сентября