Найти в Дзене
ZDG

Музыка сфер (точнее, окружностей)

По мотивам этой статьи: Я вспомнил про видео из уже полузабытого ютуба, где полиритмы были визуально представлены как бегающие по окружностям шарики. Наблюдая за их относительными скоростями, можно было видеть (и слышать), как хаос постепенно переходит в гармонию и наоборот. Один ритм это "тук... тук... тук..." через равные интервалы. Добавив к этому ритму другой ритм, с другими интервалами, мы получим полиритм. В полиритм можно добавить сколько угодно дополнительных ритмов. Но их секрет в том, что имея разные интервалы, они тем не менее в определённый момент совпадают. Так, если у первого ритма принять интервал по умолчанию равный 1, а у второго сделать интервал 2, то эти ритмы будут совпадать на каждый второй такт. Если сделать интервал 3, то они будут совпадать на каждый третий такт, и т.д. Моменты совпадения полиритма воспринимаются нашим мозгом как гармония, а если это визуализировать, то становится ещё интереснее. Я возьму 7 ритмов, соответствующих 7 нотам. Каждый ритм будет изоб
Оглавление

По мотивам этой статьи:

Я вспомнил про видео из уже полузабытого ютуба, где полиритмы были визуально представлены как бегающие по окружностям шарики. Наблюдая за их относительными скоростями, можно было видеть (и слышать), как хаос постепенно переходит в гармонию и наоборот.

Что такое полиритмы

Один ритм это "тук... тук... тук..." через равные интервалы. Добавив к этому ритму другой ритм, с другими интервалами, мы получим полиритм. В полиритм можно добавить сколько угодно дополнительных ритмов.

Но их секрет в том, что имея разные интервалы, они тем не менее в определённый момент совпадают. Так, если у первого ритма принять интервал по умолчанию равный 1, а у второго сделать интервал 2, то эти ритмы будут совпадать на каждый второй такт. Если сделать интервал 3, то они будут совпадать на каждый третий такт, и т.д.

Моменты совпадения полиритма воспринимаются нашим мозгом как гармония, а если это визуализировать, то становится ещё интереснее.

Математика

Я возьму 7 ритмов, соответствующих 7 нотам. Каждый ритм будет изображен как окружность, по которой движется шарик. Один оборот по окружности это один такт ритма.

Нужно задать скорости шариков таким образом, чтобы пока первый шарик делает один оборот, второй делал бы 2, третий делал бы 3, и т.д.

Совершая оборот, шарик поворачивается на угол от 0 до 2*пи. Чтобы этот оборот занимал какое-то удобное для наблюдения время, не короткое и не длинное, угол надо наращивать небольшими порциями, например по 2*пи/100. Обозначим это приращение как step.

Если мы сделаем начальный угол, равный 0, и будем в каждом кадре прибавлять к нему step, шарик будет вращаться,

Но есть нюанс

Из-за потерь в арифметике с плавающей точкой приращение угла поворота, хотя и не скоро, но приведёт к накоплению ошибки.

Чтобы этого не произошло, нужно отталкиваться от какой-то целочисленной базы. Она у нас есть: шарик должен завершить оборот за 100 шагов.

Значит, базой является номер шага от 0 до 99. Зная его, мы через пропорцию можем вычислить угол, соответствующий этому шагу:

angle = step * Math.PI * 2 / 100

Теперь мы не будем увеличивать угол, а будем увеличивать только целочисленный шаг, угол же будет вычисляться каждый раз с максимальной точностью.

Сделаем класс для объекта с параметрами орбиты (на JavaScript):

Здесь будут храниться текущий шаг (step), радиус (r) и максимальное количество шагов (maxStep).

Зададим два радиуса: минимальный и максимальный. Радиусы орбит полиритмов должны располагаться в промежутке между ними:

-2

Рассчитаем, опять же методом пропорции, радиусы для 7 орбит:

-3

и сразу создадим массив объектов Orbit с этими радиусами и соответствующим количеством шагов:

-4

100 шагов задают первый ритм. Второй ритм будет содержать 200 шагов, то есть будет в два раза медленнее. Третий будет содержать 300 шагов, и т.д.

Можно экспериментировать с различным количеством шагов, например сделать не 200, а 150, и т.д. Я пока сделал i * 100 для простоты и наглядности.

Кручу-верчу, полиритм хочу

Сделаем функцию обновления состояния:

-5

Здесь всего лишь для каждой орбиты увеличиваем шаг, и если он достиг максимума, то обнуляем. Затем перерисовываем всё целиком в методе drawView(), привожу только его актуальную часть:

-6

Здесь перерисовываем каждую окружность заново (так как экран каждый раз стирается полностью). Затем для каждой орбиты высчитываем её текущий угол поворота по вышеописанной формуле. И наконец, осуществляем поворот декартовых координат.

Поворот всегда делается из 0 градусов, то есть это радиус, положенный набок из координат (0, 0) вдоль оси x. Точка, которую надо повернуть, будет иметь координаты (r, 0). Полные формулы поворота это:

x_new = x * cos(a) + y * sin(a)
y_new = y * cos(a) - x * sin(a)

Но так как в начальном положении y = 0, то мы можем сократить эти формулы до:

x_new = x * cos(a)
y_new = -x * sin(a)

Также отмечу, что в математическом пространстве ось координат y направлена вверх, а в экранном вниз, но дополнительных преобразований я не делаю, так как по большому счёту без разницы, как отображаются шарики, всё равно всё симметрично.

Итак, вычислив повёрнутые координаты (x, y), мы рисуем на этом месте шарик.

И собственно всё, нужно только стартовать цикл:

window.requestAnimationFrame(update);

И наблюдать вращение шариков:

-7

Вы можете наблюдать его онлайн, а также смотреть исходный код по ссылке:

Вот ссылка

Дальше я сделаю так, чтобы шарики звучали разными нотами: