ZXNet эхоконференция «music.zx»
тема: Правильное изменение частоты огибающей в Pro Tracker 3
от: Ivan Roshin
кому: All
дата: 07 Dec 2000
Hello, All!
═══════════════════ env_freq.1 ══════════════════
(c) Иван Рощин, Москва
Fido : 2:5020/689.53
ZXNet : 500:95/462.53
E-mail: asder_ffc@softhome.net
WWW : http://www.zx.ru/echo/roschin
Правильное изменение частоты огибающей в Pro Tracker 3
──────────────────────────────────────────────────────
("Радиолюбитель. Ваш компьютер" 10/2000, 11/2000)
Здесь я хочу рассказать о недостатке музыкального редактора
Pro Tracker 3 и о том, как его преодолеть.
Допустим, в мелодии используется sample, в котором для
формирования звука используется только огибающая (sample
зациклен на позиции 00):
┌────────────────────────────────────────┐
│ EDIT SAMPLE 01 │
│ ▒00 000 -0000 00 --Е ............... 0 │
При звучании такого sample, если в регистре R13 установлена
форма огибающей #E, сигнал на выходе музыкального сопроцессора
будет выглядеть следующим образом (приведенный график
соответствует сопроцессору AY, у которого при использовании
огибающей формируется 16 уровней сигнала; у сопроцессора YM
формируется 32 уровня):
A┼
│
│ ▄██▄ ▄██▄
│ ▄██████▄ ▄██████▄
│ ▄██████████▄ ▄██████████▄
│ ▄██████████████▄ ▄██████████████▄
│ ▄██████████████████▄ ▄██████████████████▄
│ ▄██████████████████████▄ ▄██████████████████████▄
│ ▄██████████████████████████▄ ▄█████████████████████████
0└─▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀──▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀─>
<─────────── период ───────────> t
В одном из каналов мелодии (пусть это будет канал A)
поставим последовательность нот с использованием рассмотренного
sample и с разными значениями делителя частоты огибающей.
Получим паттерн примерно такого вида:
│00│003F│..│E-5 1E..│
│01│....│..│--- ....│
│02│....│..│--- ....│
...................
│15│....│..│--- ....│
│16│003C│..│F-5 .E..│
│17│....│..│--- ....│
...................
│31│....│..│--- ....│
│32│0033│..│G-5 .E..│
│33│....│..│--- ....│
...................
│47│....│..│--- ....│
│48│0030│..│A-5 .E..│
│49│....│..│--- ....│
...................
При проигрывании этого паттерна мы будем слышать в канале A
последовательно сменяющие друг друга четыре звука разной
частоты.
Тут-то и начинаются неприятности: в моменты, когда один звук
сменяет другой, отчетливо слышен треск. Попробуем разобраться,
почему это происходит. Для этого рассмотрим форму сигнала на
выходе музыкального сопроцессора при смене звуков:
A┼
│
│ ▄██▄ ▄██▄ ▄██▄
│ ▄█████ ▄████▄ ▄████▄
│ ▄███████ ▄██████▄ ▄██████▄ ▄
│ ▄█████████ ▄████████▄ ▄████████▄ ▄█
│ ▄███████████ ▄██████████▄ ▄██████████▄ ▄██
│ ▄█████████████ ▄████████████▄ ▄████████████▄ ▄███
│ ▄███████████████ ▄██████████████▄ ▄██████████████▄ ▄████
0└─▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀─▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀──▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀──▀▀▀▀▀─>
│ t
момент смены звуков
Видно, что в момент смены двух звуков (а именно - в момент,
когда в регистр формы огибающей R13 записывается число #E)
музыкальный сопроцессор начинает новый цикл огибающей, несмотря
на то, что старый цикл еще не закончился. Такова особенность
сопроцессора - он реагирует на сам факт записи в регистр R13,
даже если туда записывается то же самое число, которое там уже
было. На графике отчетливо виден резкий перепад амплитуд в этот
момент, что и воспринимается на слух как щелчок.
В то же время, если изменять лишь частоту огибающей, не
трогая R13, результат будет как раз таким, как надо:
A┼
│
│ ▄██▄ ▄██▄ ▄██▄
│ ▄█████▄ ▄████▄ ▄████▄
│ ▄████████▄ ▄██████▄ ▄██████▄
│ ▄███████████▄ ▄████████▄ ▄████████▄
│ ▄██████████████▄ ▄██████████▄ ▄██████████▄
│ ▄█████████████████▄ ▄████████████▄ ▄████████████▄
│ ▄████████████████████▄ ▄██████████████▄ ▄██████████████▄
0└─▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀──▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀──▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀─>
│ t
момент смены звуков
════════════════════════════════════════════════
С уважением, Иван Рощин.
[ZX] [BestView 3.0 - 26%]
от: Ivan Roshin
кому: All
дата: 07 Dec 2000
Hello, All!
═══════════════════ env_freq.2 ══════════════════
Да вот беда - Pro Tracker не позволяет установить новое
значение частоты огибающей без записи значения в регистр формы
огибающей. Если мы попробуем написать так, как это показано
ниже, Pro Tracker "не поймет" этой записи и не будет изменять
частоту огибающей:
│00│003F│..│E-5 1E..│
│01│....│..│--- ....│
│02│....│..│--- ....│
...................
│15│....│..│--- ....│
│16│003C│..│--- ....│
│17│....│..│--- ....│
...................
│31│....│..│--- ....│
│32│0033│..│--- ....│
│33│....│..│--- ....│
...................
│47│....│..│--- ....│
│48│0030│..│--- ....│
│49│....│..│--- ....│
...................
Другие музыкальные редакторы, может быть, и позволяют так
сделать, да только не хочется никуда переходить с Pro Tracker'a,
потому что его интерфейс кажется мне (и не только мне) самым
удобным.
Я прослушал большое количество написанных в Pro Tracker'е
мелодий и пришел к выводу, что их авторы смирились с этим, как
с чем-то неизбежным. В то же время, есть способ преодоления этой
проблемы, не требующий перехода на другой редактор.
Воспользуемся тем, что в Pro Tracker'е есть команды
увеличения и уменьшения значения делителя частоты огибающей:
9 - Enable portamento up
A - Enable portamento down
В позиции 2 для этих команд указывается величина delay
(количество прерываний между двумя изменениями), а в позициях
3 и 4 указывается шаг изменения.
Вот пример действия команды "9810" для случая, когда
начальное значение делителя частоты было #0050:
делитель ┼
частоты │
#80 │ ▒▒▒▒▒▒▒▒
#70 │ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
#60 │ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
#50 │█████████████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
#40 │█████████████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
#30 │█████████████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
#20 │█████████████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
#10 │█████████████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
0 └─────────────┼───────┼───────┼────────┼───────>
x x+8 x+16 x+24 t
│
└─момент начала действия команды
Как видим, после этих команд значение делителя частоты
будет все время изменяться. А нам надо приспособить эти команды
для решения следующей задачи: в момент начала ноты с порядковым
номером n изменить значение делителя частоты с p1 на p2, если
скорость мелодии равна s.
Сделать это можно следующим образом: на ноту с порядковым
номером n-1 ставим команду 9, если p2>p1, и команду A, если
p1>p2. Параметры команды: во второй позиции указываем s, а в
позициях 3 и 4 указываем │p2-p1│. Тогда в момент, когда нота с
порядковым номером n-1 закончится и начнется нота n, значение
делителя частоты изменится с p1 на p2. Для того, чтобы
остановить дальнейшее изменение делителя частоты, на ноту n
ставим команду 9s00 или As00 (т.е. изменение с шагом 0).
Если применить этот способ к рассмотренному ранее примеру
(в предположении, что скорость мелодии равна четырем), то мы
получим следующее (команды для удобства приведены в правой
колонке, на самом деле при работе в редакторе они не видны):
│00│003F│..│E-5 1E..│ │
│01│....│..│--- ....│ │
│02│....│..│--- ....│ │
...................
│15│....│..│---▒....│A403│ (#3F-#3C=3)
│16│003C│..│---▒....│9400│
│17│....│..│--- ....│ │
...................
│31│....│..│---▒....│A409│ (#3C-#33=9)
│32│0033│..│---▒....│9400│
│33│....│..│--- ....│ │
...................
│47│....│..│---▒....│А403│ (#33-#30=3)
│48│0030│..│---▒....│9400│
│49│....│..│--- ....│ │
...................
Рекомендую загрузить Pro Tracker и проверить на практике,
насколько лучше стало звучание.
Теперь разберем случай, когда мелодия, состоящая из
этого же единственного паттерна, зациклена на начало. Обратите
внимание на то, что для правильного звучания придется изменить
приведенный выше паттерн и добавить еще один. Ведь если
использовать только приведенный выше паттерн, то при переходе
к его началу в R13 будет записываться #E, а значит, будет
слышен щелчок.
════════════════════════════════════════════════
С уважением, Иван Рощин.
[ZX] [BestView 3.0 - 26%]
от: Ivan Roshin
кому: All
дата: 07 Dec 2000
Hello, All!
═══════════════════ env_freq.3 ══════════════════
Итак, получим вот что (мелодия должна быть зациклена на
pattern 1):
Pattern 0: │00│003F│..│E-5 1E..│ │
│01│....│..│--- ....│ │
│02│....│..│--- ....│ │
...................
│15│....│..│---▒....│A403│ (#3F-#3C=3)
│16│....│..│---▒....│9400│
│17│....│..│--- ....│ │
...................
│31│....│..│---▒....│A409│ (#3C-#33=9)
│32│....│..│---▒....│9400│
│33│....│..│--- ....│ │
...................
│47│....│..│---▒....│А403│ (#33-#30=3)
│48│....│..│---▒....│9400│
│49│....│..│--- ....│ │
...................
│62│....│..│--- ....│ │
│63│....│..│---▒....│940F│ (#3F-#30=#F)
Pattern 1: │00│....│..│---▒....│9400│
│01│....│..│--- ....│ │
│02│....│..│--- ....│ │
...................
│15│....│..│---▒....│A403│ (#3F-#3C=3)
│16│....│..│---▒....│9400│
│17│....│..│--- ....│ │
...................
│31│....│..│---▒....│A409│ (#3C-#33=9)
│32│....│..│---▒....│9400│
│33│....│..│--- ....│ │
...................
│47│....│..│---▒....│А403│ (#33-#30=3)
│48│....│..│---▒....│9400│
│49│....│..│--- ....│ │
...................
│62│....│..│--- ....│ │
│63│....│..│---▒....│940F│ (#3F-#30=#F)
Как видим, при использовании такого метода число паттернов
в мелодии может увеличиться. Да и с вычислением разностей и с
установкой команд придется повозиться, зато качество звучания
станет гораздо лучше! Я рекомендую сначала писать мелодию "как
обычно", не обращая внимания на щелчки при проигрывании, а потом
уже преобразовать ее к "правильному" виду.
И еще несколько слов: как вы, наверно, могли заметить,
рассмотренный sample одинаково звучит как при использовании
формы огибающей #E, так и при использовании формы огибающей #A.
Но в мелодии рекомендуется использовать именно форму #E - как
видно из графика, при использовании формы #A в начале мелодии
будет слышен щелчок из-за резкого перепада амплитуд:
A┼
│
│ █▄ ▄██▄
│ ███▄ ▄██████▄
│ █████▄ ▄██████████▄
│ ███████▄ ▄██████████████▄
│ █████████▄ ▄██████████████████▄
│ ███████████▄ ▄██████████████████████▄
│ █████████████▄ ▄██████████████████████████▄
0└─────────────▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀──▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀─>
<─────────── период ───────────> t
│
начало мелодии
Ну а как же прослушать без треска уже написанные PT3-модули,
ничего в них не изменяя? Это можно сделать с помощью моей
программы BestView 2.9, включив фильтр огибающей (признак его
активности - значок '√' в правом нижнем углу экрана, включение/
выключение - с помощью клавиши "V"). В версии 2.9 фильтр
работает лишь при проигрывании модулей PT3, поэтому, если вы
хотите избавиться от треска при проигрывании модулей, написанных
в Sound Tracker, S.T.Pro, Pro Tracker 2, то их необходимо
преобразовать в формат PT3 (что успешно делается с помощью
самого PT3). В последующих версиях BestView все эти форматы
будут поддержаны непосредственно.
С использованием этой возможности многие PT-модули зазвучали
по-новому - например, музыкальный альбом "Explosion" by
ViSuAl^Extreme.
Может быть, кто-то из читателей этой статьи хотел бы
написать свой музыкальный плеер, или просто добавить в свою
программу возможность проигрывания PT3-модулей (скажем, в
качестве фоновой музыки). В таком случае приведенная ниже
информация наверняка окажется полезной. Итак, как же работает
этот самый фильтр огибающей в BestView 2.9?
Сначала определим используемые переменные. ENV_FIL (byte)
показывает, включен ли фильтр (1 - да, 0 - нет). Эта переменная
может изменяться пользователем прямо во время проигрывания.
Переменная Z_FIRST (byte) показывает, производилась ли запись в
R13 хотя бы один раз с начала мелодии (1 - да, 0 - нет). Ее надо
обнулять перед инициализацией модуля.
Рассмотрим фрагмент стандартного плеера PT3-модулей, в
котором происходит запись новых значений в регистры музыкального
сопроцессора:
...... .......
#C73C: LD B,D
#C73D: OUT (C),L
#C73F: LD B,E
#C740: OUTI
#C742: LD A,0
#C744: OR A
#C745: JR Z,#C751
#C747: LD B,D ;!
#C748: OUT (C),L ;!
#C74A: LD B,E ;!
#C74B: OUT (C),A ;!
#C74D: XOR A
#C74E: LD (#C743),A
#C751: LD LY,#3A
...... .......
Отмеченные '!' команды непосредственно записывают новое
значение в R13. Перед их выполнением в аккумуляторе находится
записываемое значение, D=#FF, E=#BF, L=13.
Поставим по адресу #C747 команду CALL PATCH. Тогда, как
только плеер захочет записать что-то в R13, будет вызвана
наша подпрограмма PATCH. А она уже решит: производить запись в
R13 или нет, и если производить, то что именно туда записывать.
════════════════════════════════════════════════
С уважением, Иван Рощин.
[ZX] [BestView 3.0 - 26%]
от: Ivan Roshin
кому: All
дата: 07 Dec 2000
Hello, All!
═══════════════════ env_freq.4 ══════════════════
Вот ее текст с подробными комментариями:
PATCH LD B,D ;это те самые две команды, вместо которых
OUT (C),L ;в плеере теперь стоит CALL PATCH
;Если фильтр выключен - запись в R13
;должна быть (и устанавливаем Z_FIRST
;в 1):
LD B,A
LD A,(ENV_FIL)
AND A
JR Z,SET_ZFS
;Фильтр включен.
;Замена формы огибающей #A на #E
;(но только если период меньше #200):
LD A,(#C30C)
CP 2
JR NC,ENV_NEA
LD A,B
CP #A
JR NZ,ENV_NEA
LD B,#E
ENV_NEA
;Если вызов первый после INIT -
;запись в R13 должна быть:
LD A,0
Z_FIRST EQU $-1
AND A
SET_ZFS LD A,1
LD (Z_FIRST),A
LD A,B
RET Z
;Если в R13 записывается не то же
;значение, какое там было - запись
;должна быть:
LD B,D
IN B,(C)
CP B
RET NZ
;Если до этого огибающая была выключена,
;запись должна быть:
PUSH AF ;Эти команды нуждаются в некотором
LD B,#7F ;пояснении. В BestView имеется
LD A,SS_BANK ;специальная переменная EN_USED,
OUT (C),A ;которая изменяется после каждого
LD A,(EN_USED) ;вызова процедуры PLAY. Эта пере-
AND A ;менная устанавливается в 1, если
LD A,#10 ;на каком-либо канале используется
OUT (C),A ;огибающая, и в 0, если огибающая
JR NZ,PR_PERI ;не используется. В момент выполне-
;ния этих команд, следовательно,
;EN_USED показывает, использовалась
;ли огибающая до текущего вызова
;процедуры PLAY.
POP AF
RET
;Если период >=#200 - запись должна быть:
PR_PERI LD A,(#C30C)
CP 2
JR C,NEN_WKL
POP AF
RET
;Отменяем запись в R13:
NEN_WKL POP AF
;увеличиваем адрес возврата на 3
;(чтобы пропустить LD B,E: OUT (C),A
;в плеере):
EX (SP),HL
INC HL
INC HL
INC HL
EX (SP),HL
RET
При проигрывании PT3-модулей, компилированных с плеером,
рекомендую брать частотную таблицу непосредственно из модуля
(как это и сделано в BestView). Во-первых, частотные таблицы в
разных версиях Pro Tracker 3 немного различаются, а во-вторых,
стоит предусмотреть возможность того, что автор мелодии
использовал свою собственную частотную таблицу, не совпадающую
ни с одной из стандартных (например, использовал природный
звукоряд, а не темперированный).
При проигрывании модулей, компилированных без плеера,
рекомендую использовать частотные таблицы из Pro Tracker 3.4
final, так как именно в этой версии редактора они рассчитаны с
максимальной точностью. В программе достаточно хранить лишь
первые 24 байта каждой таблицы, что соответствует двенадцати
нотам первой октавы. Для каждой следующей октавы частоты будут
вдвое больше - ну а значения в таблице, соответственно, вдвое
меньше. Учитывая, что всего таблиц четыре, а в каждой - значения
для восьми октав, при этом удастся сэкономить 4*7*24=672 байта!
Это немало - особенно если учесть, что подобные таблицы
практически не пакуются.
Также рекомендую исправить имеющуюся в стандартном плеере
ошибку обработки команды vibrato (см. мою статью "Ошибка в
плеере Pro Tracker 3 и ее исправление" в 8-м номере журнала).
Для этого необходимо поместить байт #1D по смещению #A34 от
начала плеера.
В плеере PT3 имеется и еще одна ошибка, заключающаяся в
перепутывании параметров команды vibrato. Желающим ее исправить
рекомендую прочесть статью ((c) Max/CBX/BDA) в девятом номере
электронного журнала DEJA VU.
════════════════════════════════════════════════
С уважением, Иван Рощин.
[ZX] [BestView 3.0 - 26%]
|