Передовица » Макулатура » ИиО » Агат, ассемблер, музыка.

Агат, ассемблер, музыка. (N5/1989)

М. Алексеев, А. Рябова. г. Миасс. Группа сайта просит вас связаться с нами! (ЗАЧЕМ ЭТО?)

Наверное, многие согласятся, что одно из наиболее ярких впечатлений от первого знакомства с ПЭВМ "Агат" оставляет исполнение тест-программой мелодии Баха. А как самим запрограммировать мелодию? Ведь в штатном Бейсике "Агата" нет соответствующих операторов. Но нет худа без добра - это прекрасный повод поближе узнать машину и язык ассемблера.

За динамик в "Агате" отвечает ячейка с адресом ¤C030. При каждом обращении к ней на чтение или запись на динамик подаётся короткий импульс напряжения, и, если это делать в цикле - должен получиться звук определённой частоты. Но в цикле
FOR I=1 ТО N: РОКЕ ¤C030,0: NEXT I
мы услышим только перестук, интерпретатор работает слишком медленно. Вставленный же в Бейсик-программу фрагмент на ассемблере будет работать гораздо быстрее.

Язык ассемблера - мощный и гибкий инструмент, позволяющий реализовать буквально любой замысел. Мы же воспользуемся лишь несколькими простейшими ассемблерными командами, подобными, кстати, командам программируемого калькулятора. Они описывают операции с объявленными однобайтовыми ячейками и регистрами A, X, Y. Так, по команде LDX содержимое указанной ячейки помещается в X, а по команде STA в указанную ячейку помещается содержимое A. Для уменьшения содержимого ячейки на 1 предназначена команда DEC, то же делают с X и Y команды DEX и DEY. Понадобятся нам также команды ветвления: BNE - условный переход на указанную метку в случае ненулевого результата предыдущей операции, BEQ - то же при нулевом результате; RTS - возврат в вызывающую программу.

Входными параметрами нашей первой простейшей программы будут ПЕРИОД - условный интервал между обращениями к динамику, соответствующий периоду звуковых колебаний, и ДЛИНА - условная продолжительность звука, соответствующая числу периодов (русские буквы выбраны для наглядности, возможно, кто-то предпочтёт имена типа DLINA или LENGTH). Место для размещения параметров и программы в памяти следует выбрать так, чтобы не испортить систему и свои данные. Возьмём, например, адрес ¤2000.

10 ЗВУК=¤2000
20 ПЕРИОД=ЗВУК-1
30 ДЛИНА=ЗВУК-2
70 * ЗВУК    : REM                алг ЗВУК(цел ПЕРИОД, ДЛИНА)
80  REM	                          нач
120 REM	                          пока	ДЛИНА>0
130 ! ДИНАМИК: LDA ¤C030	; нц импульс
140 !	       LDX ПЕРИОД       ;   для X от ПЕРИОД до 1 шаг -1
150 ! ЦИКЛ    :DEX	        ;   нц
160 !	       BNE	ЦИКЛ	;   кц
170 !	       DEC	ДЛИНА	;   ДЛИНА=ДЛИНА-1
250 !	       BNE	ДИНАМИК	; кц
260 !	       RTS	        ; кон
270 !	      :
300 РОКЕ ПЕРИОД, 255
310 РОКЕ ДЛИНА, 255
320 CALL ЗВУК

Необходимо иметь в виду различное использование имён в Бейсике и ассемблере. Например, в Бейсике ПЕРИОД - это переменная, в которую заносится число ¤1FFF, а в ассемблере ПЕРИОД - это ячейка, расположенная по адресу ¤1FFF, куда перед вызовом ЗВУКа необходимо оператором РОКЕ занести соответствующий байт.

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

Для исправления этого недостатка в новой версии будем измерять продолжительность звука не периодами, длительность которых отсчитывается уменьшением содержимого регистра X на 1 в цикле от значения, записанного в ячейку ПЕРИОД, до 0, а независимыми от входных параметров интервалами, равными максимально возможному периоду (256) и отсчитываемыми уменьшением Y в цикле от 0 (256) до 0 (дело в том, что если Y=0, то команда DEY делает его равным 255).

Ещё один недостаток - несохранение исходного значения параметра ДЛИНА. Это довольно неудобно, поэтому заведём рабочую ячейку ДЛ.

10 ЗВУК=¤2000
20 ПЕРИОД=ЗВУК-1
30 ДЛИНА=ЗВУК-2
40 ДЛ=ЗВУК-3
70 * ЗВУК       : REM	        алг ЗВУК(цел ПЕРИОД, ДЛИНА)
80 REM	                        нач
100 !	         LDY #0	     ;	Y=0	(Y=256)
110 !	         LDA ДЛИНА   ;	ДЛ=ДЛИНА
120 !            STA ДЛ	     ;	пока ДЛ>0
130 !	ДИНАМИК :LDA ¤C030   ;  нц   импульс
140 !	         LDX ПЕРИОД  ;	  для X от ПЕРИОД до 1 шаг -1
150 !	ЦИКЛ	:DEY	     ;	  нц  Y=Y-1
160 !            BNE СЧЕТХ   ;	    если Y=0 то (Y=256)
210 !	         DEC ДЛ	     ;	      ДЛ=ДЛ-1
220 !            ВЕQ ВЫХОД   ;	      если ДЛ=0 то выход все
230 !	СЧЕТХ   :DEX	     ;	    все
240 !	         BNE ЦИКЛ    ;	  кц
250 !	         BEQ ДИНАМИК ;  кц
260 !	ВЫХОД	:RTS	     ;  кон
270 !	        :
300 РОКЕ ПЕРИОД, 255
310 РОКЕ ДЛИНА, 255
320 CALL ЗВУК

В таком виде программа уже годится для исполнения быстрых мелодий, но генерировать долгие звуки она не способна. Всё происходит слишком быстро даже при максимальном значении (256) однобайтового параметра ДЛИНА. Введём ещё один параметр - МНОЖИТЕЛЬ - для увеличения длительности звука, определяемой параметром ДЛИНА, в заданное число раз, и рабочую ячейку МН. Программа дополнится такими строками:

50 МНОЖИТЕЛЬ=ЗВУК-4
60 МН=ЗВУК-5
290 РОКЕ МНОЖИТЕЛЬ,16

80  !	       LDA МНОЖИТЕЛЬ ; нач
90  ! 	       STA МН	     ; МН=МНОЖИТЕЛЬ

Тело цикла станет таким:

160 !	      BNE СЧЕТХ     ;   если Y=0 то (Y=256)
170 !	      DEC МН	    ;	  MH=MH-1
180 !	      BNE СЧЕТХ	    ;	  если МН=0 то
190 !	      LDA МНОЖИТЕЛЬ ;	    МН=МНОЖИТЕЛЬ
200 !	      STA МН	    ;	    ДЛ=ДЛ-1
210 !	      DEC ДЛ	    ;	    если ДЛ=0 то выход
220 !	      BEQ ВЫХОД	    ;	  все
230 ! СЧЕТХ  :DEX	    ;	все

Подобным образом можно увеличить и период колебаний, чтобы понизить частоту звука до басов и даже перестука, но мы пока перестанем совершенствовать программу и займёмся задачей извлечения "нефальшивых" звуков. Отношение частот соседних нот (полутон) равно корню 12-й степени из 2, значит, значения параметра ПЕРИОД должны принадлежать соответствующей геометрической прогрессии. Построим прогрессию на три октавы, взяв за начало 256 (0) - самый низкий звук.

300 DIM НОТА%(37) : HOTA%(1)=0
310 A=256 : P=2^(1/12)
320 FOR 1=2 ТО 37
330 A=A/P
340 НОТА%(I)=INT(А+0.5)
350 NEXT I

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

400 СДВИГ=5
410 READ КОД
420 IF КОД<0 THEN РОКЕ ДЛИНА,-64/КОД : GOTO 410
430 КОД=КОД*СДВИГ
440 IF КОД>37 OR КОД<1 THEN END
450 РОКЕ ПЕРИОД, НОТА%(КОД)
460 CALL ЗВУК
470 GOTO 410
500 REM МАЛЕНЬКАЯ ЕЛОЧКА
510 DATA -8,8,-16,5,5,-8,8,-16,5,5,8,6,5,3,-4,1,-8,
         10,-16,13,10,-8,8,-16,5,5,8,6,5,3,-4,1,256

Экспериментируя со сдвигом тональности, можно убедиться, что слишком высокие ноты звучат хуже, слышится фальшь, вызванная ошибками округления до целого. Для сравнения распечатайте члены прогрессии с округлением и без него. Работая с параметром МНОЖИТЕЛЬ, можно изменять темп исполнения - andante, allegro и т.п.; вставляя между всеми звуками небольшие паузы, можно получить staccato. Вообще кодирование паузы (видимо, нулём) и её отработку тоже обязательно надо предусмотреть. И собрать мелодии в библиотеку, и сделать каталог мелодий, и музыкальный редактор, и ещё, и ещё... Развивать эту тему можно бесконечно.

Конечно, в некоторых версиях Бейсика есть специальные операторы SOUND и PLAY, а в Рапире - стандартные процедуры ЗВУК и НОТА, облегчающие программирование музыки. Но, овладев ассемблером, вы можете попытаться сымитировать звук выстрела, или удара, шум мотора и даже синтезировать речь. Желаем успехов!

Литература
 Техническое описание ПЭВМ "Агат". Книга 2. Фr.3.032.002.T01-3. ППП "Школьница". Описания Рапиры и Отладчика.
 Морер У. Язык ассемблера для персонального компьютера Эпл. М.: Мир, 1987.

* * *

Использование материалов проекта agatcomp без получения предварительного письменного разрешения agatcomp запрещено.


Почта для обратной связи: mail@agatcomp.ru


Живое общение по теме Агата: Telegram группа Agatcomp.


Накопленные знания и проекты: тематический ФОРУМ.


© 2004-2024 agatcomp.su / agatcomp.ru

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *