Pull to refresh

Comments 7

Интересно, зачем для множителя выбирается число (1+ln(x)/n), которое в степени n лишь приближённо равно нужному значению x по формуле et = lim (1+t/n)n?

Это имеет смысл, если мы будем писать как в статье, на которую ссылка:
multiplier = (log(endLevel) - log(startLevel)) / (lengthInSamples);
currentLevel += currentLevel * multiplier;

(я убрал 1 из multiplier).

А именно, этот смысл заключается в том, что вместо числа 1+ε хранится и вычисляется ε, что при маленьком ε может обеспечить гораздо большую точность.

На практике же для разумных n гораздо более точным оказывается вычисление множителя «в лоб»:
multiplier = pow(endLevel / startLevel, 1. / lengthInSamples );

А вот что действительно непонятно, так это взятое «с потолка» значение 0.001 для нуля. Дело в том, что при экспоненциальном характере огибающей порядок этого значения прямо влияет на скорость затухания/атаки. Иными словами, если вместо 0.001 использовать 0.0001, то скорость затухания будет значительно более большой.
Вы подходите к вопросу с точки зрения прикладной математики, но тут рулят психоакустика и эффективность вычислений :) Надо выбирать настолько оптимальный алгоритм, насколько возможно без потери качества. Слепым тестом никто не отличит грубое приближенное экспоненциальное изменение амплитуды от более точного.

По поводу 0.001 — не понимаю, что вас смущает.

По поводу 0.001 меня смущает в первую очередь то, что на слух это ужасно. Если, например, период release установлен в 0.2 сек, то экспоненциальное спадание от 1 до 0.001 будет означать затухание в 31 раз (~= корень из 1000) за первые 0.1 сек. Я поэксперементировал с этим параметром и нашёл, что гораздо более комфортно воспринимается значение 0.05 вместо 0.001.

Теперь по поводу алгоритма. Резон неточных вычислений, описанных в статье www.musicdsp.org/showone.php?id=189 понятно какой, и это не эффективность вычислений, которая у вычисления двух логарифмов будет никак не меньше, чем у вычисления одной экспоненты, а именно точность: вместо числа 1+ε хранится и вычисляется ε. Но в статье, которую вы переводили к этому эпсилон прибавляется 1, и все преимущества сразу теряются. На самом деле, их и не было, поскольку в вышеупомянутом пределе скорость сходимости не такая, чтобы для разумных количеств отсчётов математическая погрешность, возникающая в алгоритме статьи оказывалась бы меньше погрешности double, которая возникает тупом при вычислении в лоб. Поэтому вывод: по ссылке www.musicdsp.org/showone.php?id=189 описан алгоритм обоснованный, но на практике неправильный. В статье этот алгоритм неправильно используется, так что получается необоснованно и неправильно.
Я поэксперементировал с этим параметром и нашёл, что гораздо более комфортно воспринимается значение 0.05 вместо 0.001.

Интересно, надо попробовать, неужели действительно слышно. Если так звучит лучше, значит стоит этого придерживаться.

По поводу сложности вычислений согласен, да.
А какие преимущества могли быть и почему они исчезли при прибавлении единицы?
Преимущества в точности. Хорошо, объясню подробно. Числа с плавающей точкой устроены так, что чем ближе число к нулю тем выше точность (тем ближе расположены соседние числа). Для double погрешность хранения числа, близкого к 1, составляет 2-53 (см. en.wikipedia.org/wiki/Machine_epsilon), для чисел, близких к нулю, она будет на порядки меньше. А в данном случае — погрешность очень важный параметр, поскольку в конечном итоге множитель возводится в очень большую степень порядка 100 000. Собственно, резон алгоритма, описанного по ссылке www.musicdsp.org/showone.php?id=189 в этом и состоит: для величины m, близкой к 1 вычисляется и используется параметр m-1. Я думаю, что больше нет ни одной причины не использовать формулу

multiplier = pow(endLevel / startLevel, 1. / lengthInSamples );
Sign up to leave a comment.

Articles