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.
Другие статьи номера:
Похожие статьи:
В этот день... 12 декабря