еще немного про пт3, конкретно - про портаменто и переполнения в орнаментах.
WARNING: примеры кода могут быть ошибочными, я хочу спать
![smile :)](./images/smilies/smile.gif)
Портаменто в PT3 - одна из самых глючных команд, имхо, однако по большей части (когда надо перейти от одной ноте к другой) она работает корректно. В PT 3.5 и ниже команда работает корректно только в том случае, если слайд идет от одной ноты к другой, и между ними нет команд 1/2 (т.е. глиссов):
- Code: Select all
--- .... ....
--- .... ....
C-4 .... ....
--- .... ....
--- .... ....
--- .... ....
--- .... ....
--- .... ....
C-5 .... 3110 <- глиссов между командами нет, все нормально
--- .... ....
--- .... 2120 <- а вот и глисс - до портаменто он работает как положено....
--- .... ....
--- .... ....
--- .... ....
C-4 .... 3110 <- а здесь он игнорируется - на слух как скачок
--- .... ....
то есть предельное отклонение вычисляется как
- Code: Select all
chan[i].cmd.slide.limit = notetab[chan[i].newnote] - notetab[chan[i].oldnote]
chan[i].cmd.slide.add = ((chan[i].cmd.slide.limit) < 0 ? -parm : parm); // здесь parm - шаг портаменто
сhan[i].cmd.slide.acc = 0; // сбрасываем предыдущее накопление от глиссов
chan[i].portanote = chan[i].newnote; chan[i].note = chan[i].oldnote; // на время портаменто действует старая нота!
В файле, кстати, предел посчитан заранее и хранится вместе с шагом (или скоростью, кому как
- параметры 3-4, т.е. 3110 - портаменто с задержкой в 1 фрейм и шагом 10 периодов за...кхм...фрейм обработки команды ![smile :)](./images/smilies/smile.gif)
) для быстроты плеера, однако это приводит к ошибкам ограничения портаменто, если эта команда стоит в начале паттерна, на чем и спотыкается родной pt3-плеер (бульбовский пересчитывает пределы на лету)
В PT 3.6 и выше портаменто учитывает смещения от глиссов, поэтому выше приведенный пример будет работать правильно, а предел считается как:
- Code: Select all
chan[i].cmd.slide.limit = notetab[chan[i].newnote] - notetab[chan[i].oldnote]
chan[i].cmd.slide.add = ((chan[i].cmd.slide.limit - chan[i].cmd.slide.acc) < 0 ? -parm : parm);
chan[i].portanote = chan[i].newnote; chan[i].note = chan[i].oldnote; // на время портаменто действует старая нота!
// nb: chan[i].cmd.slide.acc не обнуляется!
небольшая закуска из мануала к Vortex Tracker II:
- Code: Select all
Музыканты ожидают более гибкого поведения команды 3. Здравый смысл подсказывает,
что скольжение должно начинаться не от частоты предыдущей ноты, а от текущей
частоты, которая могла быть сдвинута до этого предыдущими командами 1,2 и 3.
Например, в такой ситуации
D-5 1F.F ....
--- .... 11.1
D-5 .... 31.1
в первой строке устанавливается нота D-5, во второй строке запускается команда
понижения частоты, а в третьей строке опять устанавливается нота D-5;
устанавливая при этом команду 3, музыкант надеется, что частота постепенно
выправится, однако в Pro Tracker 3.5 и более старых этого не происходит. Не
зависимо от наличия или отсутствия там команды 3 эти версии Pro Tracker 3 сразу
же (без всякого постепенного перехода), начинает играть ноту D-5. Pro Tracker
3.6 и выше данную ситуацию обрабатывает правильно, однако он не может правильно
это откомпилировать: такая команда портаменто просто удаляется (маскируется
соответствующая ошибка в стандартном плеере).
wbcbz7 note: справедливости ради, в PT 3.7 проблемы с удалением команды нет, и все играется как надо, но эта версия ВНЕЗАПНО не имеет компилятора, поэтому как её будет играть плеер - загадка
Да, на время портаменто действует старая нота, и орнаменты считаются от нее
![wink ;)](./images/smilies/wink.gif)
Конец портаменто обрабатывается так (код взят из pmd2psg, pt3md совместим по портаменто с
pt3.6+ вортексом, но модули от pt3.6+ тоже играются верно):
- Code: Select all
if (chan[ch].cmd.slide.active) {
if (!(--chan[ch].cmd.slide.count)) {
// update
chan[ch].cmd.slide.count = chan[ch].cmd.slide.delay;
chan[ch].cmd.slide.acc += chan[ch].cmd.slide.add;
if ((chan[ch].cmd.slide.porta) &&
(((chan[ch].cmd.slide.add >= 0) && (chan[ch].cmd.slide.acc >= chan[ch].cmd.slide.limit)) ||
((chan[ch].cmd.slide.add < 0) && (chan[ch].cmd.slide.acc <= chan[ch].cmd.slide.limit)))) {
// disable portamento
chan[ch].note = chan[ch].cmd.slide.portanote; // в portanote - новая нота, сохраненная для
chan[ch].cmd.slide.active = false; // восстановления в конце портаменто
chan[ch].cmd.slide.acc = 0;
}
}
}
Здесь есть еще одна хитрость - если портаменто шло от оооочень "далекой" ноты
I к другой
II и, не успев закончиться, началось портаменто к третьей ноте
III, то в качестве oldnote выступает I-я, а как newnote - III-я, и при этом накопление от старого портаменто не отбрасываем! Хороший детектор ошибок в реализации команды - олежин
aquatic - я три для бился над тем, чтобы этот музон заиграл как надо, в то время как остальные и так играли корректно.
Портаменто без ноты в протрекерах всех версий вообще игнорируется напрочь, играет только Vortex и бульбоплеер (инструмент не сбрасывается, происодит переход к той ноте, что была раньше). Со случаями вроде "портаменто к той же ноте" всё вообще не ясно - вортекс играет все корректно, а вот pt3 - как повезет (выдержка из мануала к PT 3.71:)
- Code: Select all
PT3.69:
*при компиляции убивается 3xxx на ту же ноту
*в компиляции возвращен старый алгоритм поиска исходной ноты
при 3xxx в начале паттерна (независимо от отсортированности
паттернов в позициях). Поясню на примере. Трек из интро к ADV13
не играется плейерами PT36x из-за 3xxx с ноты A-5 на одноименную
ноту (44-я и 54-я секунды). Паттерн #14 (в котором эта команда)
на самом деле используется дважды (второй раз 3xxx имеет смысл),
но в оригинале глисс никогда не звучит, т.к. PT35x занёс в саму
команду, что двигаться не надо. В PT36x аналогичное достигается
только полным убиванием 3xxx. Но для этого PT должен знать,
какая нота была предыдущей. В модуле паттерны не отсортированы,
и старые PT36x, пользуясь последней нотой в предыдущем ПО НОМЕРУ
паттерне, портили звук не только в этом месте, но и на первых
секундах. Сейчас трек без всякой сортировки выгрузится правильно
(но нельзя играть плейером от PT36x старый вариант модуля!
Плейер PT36x не играет 3xxx на ту же ноту!)
p.s. тот упомянутый трек
http://zxart.ee/eng/authors/m/miguel/adventurer13-01/, pt3.5 в трекере играет вторую команду, в плеере игнорирует обе упомянутые команды, 3.7 в трекере - аналогично 3.5
Теперь по переполнениям в орнаментах. PT 3.5 и ниже в случае выхода итоговой ноты за пределы C-1..B-8 пожимают плечами и сваливаются в undefined behavior (у меня в 3.5 при выходе за C-1 звук просто отключался, а за B-8 читались левые данные из тоновой таблички, соответственно нота играла как попало). PT 3.6 и выше при переходе ниже C-1 подставляют C-1, если уйти выше C-8, то опять-таки поведение не определено. Vortex Tracker и его плеер просто режут ноту по границе C-1..B-8 и дальше не парятся. Пример - portalim.pt3
tl;dr: в pt3.6+ и вортексе орнаментом L-96 можно заставить любую ноту звучать как C-1 и, к примеру, сделать в инструменте типа независимые смещения тона
вроде на сегодня всё
![happy XD](./images/smilies/happy.gif)
p.s. напоследок - примеры в пт3 (пока что, pt3md 0.3 еще не готов)