Тьфу, конечно же min/minps выше, не max. Совсем старый стал.
gammaker
> Но ведь для этого нужно синус или косинус пересчитать? А если приращение фазы
> непрерывно меняется, то придётся каждый семпл косинус считать и никакого толку
> от оптимизации тогда не будет?
Не надо считать синус, косинус, зачем?
Приращение фазы - вот что меняется, зачем заново считать синус/косинус. Я что-то не понимаю.
> Ну я считаю наоборот, что я делаю хост, а не плагины и юзаю уже тысячи готовых
> плагинов.
Хост как раз загружает в себя плагины и с их помощью производит звук. В заголовке вроде про синтезатор написано. Ну в общем не суть.
> И переводить float индексы в int, что наверное даже дольше вычисления синуса
ну приехали, cvtips и иже с ними - 1/2 такта, синус/косинус около сотни.
Dmitry_Milk
> Ну а при очередном питчбенд-событии снова расчитать синус/косинус приращения
> по-честному.
да если учесть, что разницы в один цент достаточно (а ее достаточно), то всего-то надо хранить табличку из 12800 значений, в компах давно уже не 640Кб, так что еще ~64 ни чего не изменят
Dmitry_Milk
> Но вообще метод (пусть слегка жульнический) борьбы с экспоненциальным возрастанием я уже выше давал - постоянный контроль/коррекция значений, чтоб не вылезали за единицу (max/maxps значения с единицей(ами), чтоб без сравнений и условных переходов).
Есть нормальный способ — периодически умножать на (1.5 - 0.5 * norm), где norm = c * c + s * s.
Способ имеет квадратичную сходимость, поэтому крайне эффективен при небольших отклонениях нормы от 1.
Подходит не только для sin/cos, но и для кватернионов и восстановления ортогональности матриц.
FordPerfect
> Если это в лоб сделать, то второе приращение получится (типично) крохотным, и вся эта радость может разъехаться на float (экспоненциальное возрастание амплитуды). Если знаешь как сделать нормально - так делись, что-ли...
Для маленьких поворотов можно использовать линейную интерполяцию с последующей нормализацией вышеописанным алгоритмом (возможно, потребуется несколько итераций).
Особенно удобно, что вместо линейной можно использовать интерполяции высших порядков и сплайны.
}:+()___ [Smile]
Работает, вроде:
http://ideone.com/EysHI5 - влобный
http://ideone.com/wlp2xf - фикс раз в 64 итерации (дальше - diminishing returns).
В реальности там не if, наверное, но суть и так вроде видна.
В идеале - хотелось бы чего-то единообразного, но это уже эстетство.
Да откуда там маленькие повороты-то? или кто-то меньше 20гЦ синтезирует на сэмплрейте больше 192кГц?
d.m.k
Речь о переменной частоте:
\(f(n)=\cos(\phi+\omega n +\frac{1}{2} \kappa n^2)\)
Т. е. частота \(\omega+\kappa n\).
Тогда для достаточно реалистичного сценария "f=200 Гц → 400 Гц за 1 с, на частоте дискретизации 44100 Гц":
\(\kappa \approx 6.46 \cdot 10^{-7}\).
P. S. 44100=22325272 (c).
> [cht]\kappa \approx 6.46 \cdot 10^{-7}[/cht]
Мне кажется, что я вижу обходной путь. Проблема ведь не в самой малости величины (ведь порядок в флоате нам позволяет представить и на много порядков меньшую величину с сохранением количества значащих цифр). И даже при умножении на такую величину тоже ничего страшного не происходит, просто складываются порядки, а мантиссы умножаются практически без потери значащих цифр.
Проблема возникает при сложении такого числа (или результата умножения на такое число) с числом, отличающимся на несколько порядков - вот тогда-то у маленького числа много или все значимые цифры теряются.
У нас ситуация такая, что маленький угол дает очень близкий к нулю синус и очень близкий к единице косинус. И проблема возникает, когда A*sin(k)+B*cos(k).
А что, если косинус маленького угла представить как "единица минус маленькое число (назовем его cos_diff)"? Тогда имеем:
A[j+1] = B[j] * sin(k) - A[j] * cos_diff + A[j]
B[j+1] = B[j] - B[j] * cos_diff - A[j] * sin(k)
Величины B[j] * sin(k) и A[j] * cos_diff уже будут более близки по своим порядкам друг к другу. А величины A[j] и B[j] представлять из двух компонент - тех, что получены умножением на маленькие величины, и тех, что на большие, никогда не складывая их между собой.
Ну как-то так, дальше надо формулы еще раскладывать, лень :)
P.S. Блин, гадский индекс i :) Пришлось менять на j
>B[j] * sin(k) и A[j] * cos_diff
Dmitry_Milk
Порядки-то всё-таки разные:
\(\sin x \approx x\),
\(\cos x \approx 1 - \frac{1}{2} x^2\).
Вероятно, можно использовать что-то в духе https://en.wikipedia.org/wiki/Kahan_summation_algorithm , но тогда уже можно сразу к double перейти, там тоже без проблем в этом диапазоне.
Нда, все сложнее и сложнее.
Я уже слышу, как сторонники табличного синтеза синусоиды молча ржут над сторонниками чистой математики, как те создают себе все новые и новые проблемы, а потом героически их решают.
Dmitry_Milk
Я уже слышу, как сторонники табличного синтеза синусоиды молча ржут над сторонниками чистой математики, как те создают себе все новые и новые проблемы, а потом героически их решают.
Ага :)
Алгоритм Герцеля для синусоиды предлагали уже?
FordPerfect
> Тогда для достаточно реалистичного сценария "f=200 Гц → 400 Гц за 1 с, на
> частоте дискретизации 44100 Гц"
Как я выше уже сказал, шаг по частоте меньше цента - смысла делать вообще нет никакого. К тому же, смысла делать шаг по частоте чаще чем раз в период - еще меньше.
То есть, периодическое обращение к таблице преобразования высоты ноты (в центах) в пары синус/косинус соответствующих углов приращения? Ну, теоретически можно, поскольку эти обращения будут уже не на каждом отсчете. Заодно в виде плюшки - сразу учтена экспоненциальная зависимость.
Но все равно SIMD уже разъезжается... У каждой из компонент необходимость получения нового значения синкос угла поворота будет возникать в разные моменты времени, значит условные переходы, пусть даже по условию "у кого-то из четырех SIMD-компонент возникла необходимость получить новый угол приращения"...
Если б я ещё хоть немного понимал о чём вы))
Epsilon
> Если б я ещё хоть немного понимал о чём вы))
У тебя цель-то какая?
Я могу тебе рассказать вообще все про синтез звука (не укатываясь уж совсем в экзотику), последовательно. Что, куда, откуда, как и зачем. Но это надолго. Если решил сделать что-то более менее полезное - надо начинать с простого и постепенно добавлять фишечки.
Тема в архиве.