ZX Forum
#04
19 ноября 1997 |
|
Мир звуков Спектрума - глава 4.9: воспроизведение звука на прерываниях.
4.9. Звук на прерываниях У всех подпрограмм, приведенных в пре- дыдущих главах, есть один общий недоста- ток: на время их звучания выполнение ос- новной программы приостанавливается. Это можно исправить, хотя и с трудом, исполь- зуя второй режим прерываний. Те, кто зна- ет, что это такое, могут смело пропустить следующие несколько абзацев. Как уже говорилось раньше, пятьдесят раз в секунду процессор получает сигнал о необходимости вызова прерывания. При этом он вызывает некоторую подпрограмму, после чего продолжает обрабатывать основную про- грамму. Существует три различных режима преры- ваний: 0, 1 и 2, которые выбираются коман- дами IM 0, IM 1 и IM 2. Стандартный режим имеет номер 1. О нем уже было рассказано в главе 3, но на всякий случай напомню, что в этом режиме в качестве обработчика пре- рываний используется подпрограмма ПЗУ по адресу 56 (#38), которая следит за клавиа- турой и счетчиком времени. Режим 0 нам не интересен, так как в ZX-Spectrum он анало- гичен режиму 1. А вот режим 2 и есть са- мое интересное! Во втором режиме прерываний пятьдесят раз в секунду происходит следующее: мик- ропроцессор считывает с шины данных байт, называемый вектором прерывания. Он пере- дается в младший байт шины адреса, а в старший байт записывается содержимое ре- гистра I. По полученному таким образом ад- ресу процессор считывает из памяти два байта, которые интерпретируются как адрес подпрограммы обработки прерывания. ZX-Spectrum устроен так, что вектор прерывания обычно равен 255 (#FF), но не- которые внешние устройства, например, AMX- mouse, могут генерировать другие векто- ра. Кроме того, в некоторых некачественных спектрумах вектор прерывания может изме- няться абсолютно случайным образом. Исходя из всего вышесказанного, можно предложить следующую последовательность действий для установки собственной под- программы обработки прерываний: 1. Запретить прерывания. 2. Записать в память адрес обработчика прерываний. 3. Задать в регистре I старший байт ад- реса указателя на обработчик. 4. Установить второй режим прерываний. 5. Разрешить прерывания. А для возврата к стандартному режиму обработки прерываний нужно выполнить такие действия: 1. Запретить прерывания. 2. Записать в регистр I число 63. 3. Установить первый режим прерываний. 4. Разрешить прерывания. Так как вектор прерывания может изме- няться, вместо записи двух байтов по опре- деленному адресу выстраивается целая таб- лица размером 257 байт с таким расчетом, чтобы при любом значении вектора считывал- ся один и тот же адрес. Понятно, что для этого все байты таблицы должны быть одина- ковыми. При составлении процедур обработки пре- рываний следует придерживаться некоторых правил. Во-первых, обработчик прерывания должен выполняться за достаточно короткий промежуток времени. Во-вторых, все регис- тры, используемые в обработчике, перед возвратом должны принять значения, нахо- дившиеся в них до вызова прерывания. В связи с этим не рекомендуется обращаться к подпрограммам ПЗУ, по крайней мере до тех пор, пока Вы не знаете совершенно точно, какие в них используются регистры и какие системные переменные при этом могут быть изменены. Вызов подпрограмм ПЗУ не желате- лен еще и потому, что некоторые из них разрешают прерывания, что совершенно не допустимо во избежание вызова обработчика из самого себя. Любой обработчик должен работать при запрещенных прерываниях. Однако использовать команду DI в самом начале процедуры не обязательно, так как это делается автоматически и Вам надо по- заботиться только о разрешении прерываний перед выходом. Если Вы не хотите лишаться возможнос- тей, предоставляемых стандартным обработ- чиком прерываний, можете использовать в своей подпрограмме команду RST 56. А при использовании прерываний в бейсик-програм- мах это просто необходимо, иначе будет заблокирована клавиатура. Теперь разберемся, чем нам могут быть полезны прерывания. Если задать некоторую последователь- ность звуков и в каждом прерывании вос- производить короткую ее часть, то получит- ся довольно хороший эффект параллельного с программой звука. Причем каждая часть дол- жна быть действительно очень короткой, иначе толку от прерываний не будет. Условимся, что последовательность зву- ков будем задавать блоком данных в следую- щем формате: для каждой ноты в блоке данных должно быть по два байта. Первый байт - частота (1...253), а второй байт - длительность (0...255). Кроме того, могут встречаться такие контрольные коды: 0 - переключение тон/шум 254 - начало цикла 255 - конец блока Изначально программа настроена на вы- вод чистого тона, но, если Вам необходимо получить шум, Вы можете переключить ее на воспроизведение шума, вставив в данные байт, равный 0. Для повторного переключе- ния на тон байт 0 должен встретиться еще раз. Когда программа встретит байт 255, вы- вод звука либо прекратится, либо вся пос- ледовательность повторится снова - в зави- симости от заданного числа повторений. Если в блоке данных встретится код 254, то при очередном повторении эффект начнет- ся не с начала, а с места, где этот код встретился. Теперь сама программа. Она является за- конченным комплексом и может быть оттран- слирована ассемблером без малейших измене- ний: 1415. 10 ORG 60000 20 JP SINIT ; подключение прерываний 30 JP SSTOP ; отключение прерываний 40 JP NEWFX ; инициализация эффекта 50 MUTE LD (COUNT),A ; "заглушка" 60 RET 70 SINIT XOR A 80 LD (COUNT),A 90 LD A,24 ; код команды JR 100 LD (65535),A 110 LD A,195 ; код команды JP 120 LD (65524),A 130 LD HL,INTR ; HL=адрес обработчика 140 LD (65525),HL 150 LD HL,65024 160 LD DE,65025 170 LD BC,256 180 LD (HL),255 ; адрес прерывания - 65535 190 LD A,H 200 LDIR ; заполнение таблицы 210 DI 220 LD I,A 230 IM 2 240 EI 250 RET 260 SSTOP DI ; отключение прерываний 270 LD A,63 280 LD I,A 290 IM 1 300 EI 310 RET 320 NEWFX DI ; инициализация эффекта 330 LD (COUNT),A 340 XOR A 350 LD (FLAG),A 360 LD (ADDR),HL 370 LD (CURADD),HL 380 EI 390 RET 400 ADDR DEFW 0 ; начальный адрес блока данных 410 CURADD DEFW 0 ; текущий адрес в блоке данных 420 COUNT DEFB 0 ; количество повторений 430 FLAG DEFB 0 ; флаг тон/шум 440 INTR PUSH AF ; обработчик прерывания 450 PUSH BC ; сохранение регистров 460 PUSH DE 470 PUSH HL 480 TEST LD A,(COUNT) ; A=счетчик повторений 490 OR A ; есть что играть ? 500 JR Z,EXIT 510 LD HL,(CURADD); HL=текущий адрес 520 NEXT LD A,(HL) 530 INC HL 540 CP 254 ; A=254 ? (начало цикла) 550 JR NZ,CONT1 560 LD (ADDR),HL ; изменение начального адреса 570 JR NEXT 580 CONT1 CP 255 ; A=255 ? (конец) 590 JR NZ,CONT2 600 LD HL,(ADDR) ; восстановление начального 610 LD (CURADD),HL; адреса блока данных 620 LD HL,COUNT 630 DEC (HL) ; уменьшение счетчика повторений 640 JR TEST 650 CONT2 OR A ; A=0 ? (переключатель) 660 JR NZ,CONT3 670 LD A,(FLAG) 680 CPL ; инвертирование A 690 LD (FLAG),A 700 JR NEXT 710 CONT3 LD B,A ; B=частота 720 LD C,(HL) ; C=длительность 730 INC HL 740 LD (CURADD),HL; сохранение текущего адреса 750 LD A,(FLAG) ; A=флаг 760 OR A ; A=0 ? 770 LD A,7 ; A=цвет бордюра 780 JR NZ,NOISE 790 TONE XOR 16 ; воспроизведение тона 800 OUT (254),A 810 PUSH BC 820 PAUSE DJNZ PAUSE 830 POP BC 840 DEC C 850 JR NZ,TONE 860 JR EXIT 870 NOISE LD HL,1000 ; воспроизведение шума 880 LD D,A 890 NOIS2 LD A,(HL) 900 AND 248 910 OR D 920 OUT (254),A 930 PUSH BC 940 PAUS2 DJNZ PAUS2 950 POP BC 960 INC HL 970 DEC C 980 JR NZ,NOIS2 990 EXIT POP HL ; восстановление регистров 1000 POP DE 1010 POP BC 1020 POP AF 1030 RST 56 ; вызов стандартного обработчика 1040 RET ; возврат 2 Порядок использования этого пакета дол- жен быть следующим. В начале работы нужно вызвать подпрограмму SINIT, которая вклю- чит 2-ой режим прерываний. В тот момент, когда Вам нужно получить звук, надо занес- ти в регистр HL адрес блока данных, в ре- гистр A - число повторений и вызвать под- программу NEWFX. Затем, если Вам по ка- кой-либо причине надо выключить звук или продлить его звучание, занесите в регистр A новое число повторений и вызовите под- программу MUTE. Кроме того, эту подпрог- рамму можно использовать для включения последнего звучавшего эффекта. По оконча- нии работы (или если в программе предус- мотрены обращения к дисководу) следует вызвать подпрограмму SSTOP, которая вос- становит стандартный режим прерываний. Серия команд JP в начале пакета сдела- на для удобства. Благодаря ей все подпрог- раммы этого пакета могут вызываться по со- седним адресам: SINIT - 60000 (#EA60) SSTOP - 60003 (#EA63) NEWFX - 60006 (#EA66) MUTE - 60009 (#EA69) К сожалению, с помощью прерываний не- возможно получить достаточно чистый тон. Поэтому, а также из-за совсем не музыкаль- ного формата данных, эта программа вряд ли может использоваться для создания музыки. Но для звуковых эффектов она в самый раз. Вот пример использования приведенной программы: 1415. 10 ORG 50000 20 CALL 60000 30 LD HL,SNDFX 40 LD A,3 50 CALL 60006 60 RET 70 SNDFX DEFB 200,5,250,4,200,5,100,10,75,13,50,20,255 2 Строку 70 можно заменить на следующую: 1415. 70 SNDFX DEFB 50,20,75,13,100,10,200,5,250,4,50,20,255 2 И последнее. Если в Вашей программе не очень много движущихся объектов на экране и длительность звукового эффекта достаточ- но мала (около полсекунды или меньше), то его можно использовать без всяких прерыва- ний - задержка заметна не будет.
Другие статьи номера:
Похожие статьи:
В этот день... 21 ноября