Музыка на прерываниях. Часть 2

Scene+ #25

Музыка на прерываниях. Часть 2

Ну что ж, большинство из вас уже знает, как воспроизводить треки из Soundtracker в режиме прерываний IM 2 — статья в одном из прошлых номеров и прилагавшаяся программа должны были принести свои плоды, ведь в этом действительно нет ничего сложного. Но теперь мы перейдём к кое-чему более запутанному.

Представим, что вы написали программу — например, стратегическую игру, которая занимает почти всю память 48K, и свободными остаются буквально байт 400. А вам при этом хочется вставить музыку размером в 8 КБ!

Если под рукой есть Speccy 128K, то теперь это не проблема: мы просто берём свободную страницу памяти. Погодите! Слышу ваши возгласы: мол, если переключить страницу, вся остальная программа окажется невидимой для компьютера? В теории и на практике это действительно так, именно поэтому я и придумал способ обойти данное ограничение.

Если подумать, реализовать это довольно просто даже для неопытных кодеров вроде меня: процедуру прерываний в том виде, в каком она использовалась раньше, можно оставить без изменений. Потребуется лишь крошечная дополнительная подпрограмма: каждый раз, когда нужно проиграть музыку, она переключает банк, проигрывает кусочек трека и тут же переключает банк обратно. Остальная программа этого даже не заметит, так как само переключение страниц отнимает ничтожно мало процессорного времени. Собственно время отнимает сам плеер. Но если у вас есть один из современных саундтрекеров с «Ближнего Востока» — к примеру, Soundtracker Pro (увы, только для пользователей Beta Disk), то там сразу встроен более быстрый плеер, как и сам ST-компилятор. К сожалению, эта версия Soundtracker, несмотря на такой же интерфейс, не совсем совместима с нашим ST. Зато ProTracker подходит ничуть не хуже всего остального!

Вот листинг вместе с описанием:
(В качестве номера банка я использую значение, которое подаётся на порт переключения, то есть не просто номер банка, а номер банка + 16 — так гораздо проще).

Сначала, перед тем как диспетчер прерываний вызовет процедуру, нужно занести значения по следующим адресам (POKE):

  • 23388: номер текущего банка, в который нужно вернуться после проигрывания музыки (чаще всего 16);
  • 23549: номер банка, в котором находится сам музыкальный трек.
    (Можно использовать банки 16, 17, 19, 20, 22 и частично 23, но только 16, 20 и 22 являются так называемыми «быстрыми» банками, не тормозящимися второй ULA; на Пентагоне же вообще без разницы, какие банки выбирать, там все быстрые).

Эти адреса не являются строго обязательными — это лишь рекомендации. Это могут быть любые два адреса между 16384 и 49151, но я знаю, что делаю, и выбрал их осознанно. Первый адрес — это системная переменная, в которую 128K Basic и так заносит номер текущего банка. Второй адрес расположен в обычном буфере принтера, ровно на 1 меньше минимального адреса, который PK-Lite обычно использует для процедуры распаковки. Это сделано на случай, если кому-то придёт в голову сжать части программы для ещё более эффективного использования памяти.

Предположим, что музыка находится в банке 17 и начинается с 49152 (начало страницы памяти), а мы находимся в банке 16. Загружаем музыку (в режиме USR):

OUT 32765,17: LOAD *"MUSIK" CODE: RANDOMIZE USR 49152 (инициализация музыки)
OUT 32765,16: POKE 23388,16: POKE 23549,17

Генератор прерываний должен быть заранее настроен так, чтобы он не конфликтовал с переключением страниц и не вызывал снега на экране (ULA-snow) — лучше всего разместить его начиная с 32768. Адреса текущего и музыкального банков можно свободно менять, так как всё это работает только в режиме USR 0; штатное переключение банков в режиме 128K постоянно работает в IM 2 и вызовет зависание системы. Если вы хотите этого избежать, придётся писать всё остальное также на ассемблере.

Переключатель банков:

ORG 33050 (этот адрес — лишь предложение!)

33,253,91   LD HL,23549    ; Загрузить номер банка с музыкой в HL
1,253,127   LD BC,32765    ; Порт переключения страниц (#7FFD)
86          LD D,(HL)
237,81      OUT (C),D      ; Включаем банк с музыкой
205,6,192   CALL 49158     ; Вызов плеера (49152+6)
33,92,91    LD HL,23388    ; Загрузить старый номер банка в HL
1,253,127   LD BC,32765    ; Порт переключения страниц
86          LD D,(HL)
237,81      OUT (C),D      ; Возвращаем исходный банк
201         RET            ; Выход из процедуры

Вообще-то команда OUT (C),D должна была бы звучать как OUT (BC),D, но такой инструкции не существует. Однако присутствующая и использованная здесь команда делает именно то, что нужно: значение D выводится не на 8-битный адрес C, а на полный 16-битный адрес шины BC!

Просто, правда? Разумеется, это не предел оптимизации, а самый наглядный вариант, и при переключении на другие страницы нужно быть внимательным. Но я думаю, эта небольшая статья показала, что даже новичок в машинном коде вполне способен программировать интересные вещи. Кроме того, теперь вы знаете, как переключать банки в ассемблере.

Демонстрация всего этого дела со всеми процедурами (PD) находится в рубрике «РАЗНОЕ» под названием «MUSIC-I».

Вот, собственно, и всё по этой теме, приятного времяпрепровождения!

(Поскольку всё это используется в режиме USR 0, пользователи +3 не смогут работать со своими дисководами — хотя с +D или MB02 вполне смогут, — впрочем, +3 далеко не идеал в плане конструкции и вывода звука).

L. C. D. / Tiger's Claw
Жду ваших писем...

Поделитесь вашим мнением о статье