В новый год всегда хочется чего-то нового. А даже если не хочется, то сознание, ещё не остывшее от работы, всё равно само возьмёт и подкинет какую-нибудь офигительную идею. И если в прошлом году накануне праздников я генерил нейросетью панельные дома, то в этом году меня занесло в совершенно неожиданную комбинацию технологий — NFT, модульные синтезаторы и javascript. Казалось бы, какая между ними связь? Обо всём понемногу читайте под катом. Дисклеймер: я рассматриваю NFT не как способ заработка, а как способ обмена некоторыми приколюхами за некоторые ништяки, причём и те и другие существуют и имеют ценность только внутри отдельно взятой криптоплатформы. Все пересчёты на фиатные деньги нерепрезентативны и не несут смысла :) Про генеративный арт Если вкратце, то генарт — это когда художник не рисует картину, а пишет генератор картин. Причём (судя по общению с генеративщиками) философские корни этой движухи уходят куда-то в сторону демосцены и написания шейдеров, а не в модные нейросетки-стайлганы, как вы могли подумать — сетки как раз у них не в почёте. Генеративщики существуют давно, активно и красиво себя публикуют и туториалов по генарту в интернете очень много. А ещё есть вот такое русскоязычное сообщество, в котором очень легко нахвататься разных прикольных идей и которое подтолкнуло меня вот этим всем заняться. Про NFT Вцелом, что-то про нфт слышали все, а всего про нфт не знает никто. Важным мне кажется понимание того что разные блокчейны (как и разные площадки) имеют разные возможности и ограничения и нацелены на разную аудиторию. Так например на "эфирных" площадках из-за высокой цены газа придётся заплатить огромную комиссию при создании NFT-токена, но и количество людей использующих эфир немаленькое. Поэтому направление генарта на эфире развивается слабо — люди просто выкладывают в блокчейн картинки и видосики (пусть даже иногда и генеративные). Скажу сразу что ответить на вопрос зачем люди покупают за огромные деньги макак или камни я не могу — до такого понимания я ещё не преисполнился.  У других блокчейнов другие возможности. Тезос обеспечивает гораздо меньшие комиссии за исполнение и хранение кода, поэтому больше подходит для создания инфраструктуры для генарта. На блокчейне тезоса построены такие площадки как hic et nunc и набирающий обороты fxhash.xyz. На последней площадке я и остановил свой выбор, т.к она позволяет писать интерактивные NFT на javascript.  Про модульные синтезаторы Модульные синтезаторы это что-то среднее между музыкальной школой и курсом цифрового сигнального процессинга. На хабре есть про них хорошая большая статья. Как явление они появились с развитием электроники в 50х-60х годах прошлого века, позже были заброшены по причине появления компьютеров и своей непригодности для массового рынка, а сейчас снова испытывают расцвет, потому что компьютеры стали мощными настолько, чтобы эмулировать модули даже в браузере на js. Модульные синтезаторы, особенно их современные компьютерные варианты, очень располагают к созданию генеративной музыки, так как позволяют абстрагироваться от музыкальной теории и оперировать звуком и логикой на самом низком уровне. Несложно догадаться, что сообщества генеративщиков и фанатов модульных синтезаторов довольно сильно пересекаются. Осознав всё вышенаписанное (и будучи фанатом модульных синтов) я загорелся идеей сделать генеративный модульный синтезатор в формате NFT. Погуглив и не найдя ничего готового+красивого+на javascript, я понял что дело принимает радикальный оборот и придётся писать модуляр на js с нуля. Впереди как раз были все новогодние праздники. Fxhash построен вокруг простой идеи — при покупке экземпляра арта у генератора артов, формируется уникальный хеш транзакции, который инициализирует детерминированный генератор псевдослучайных чисел. Использование этих случайных чисел при создании арта позволяет получать для каждой покупки свою уникальную картинку. Причём покупатель не может узнать, какой она будет, до самого момента подписания транзакции. Для быстрого старта на платформе, создатели fxhash сделали шаблонный проект, в котором уже написан генератор случайных чисел fxrand(), инициализируемый хешем транзакции. Простейший пример генеративного токена также реализован в index.js — в ответ на некоторый хеш он просто выводит на экран последовательность случайных чисел, неизменную для этого хеша. Но мы пойдём чуть дальше чем просто вывод чисел на экран и подключим библиотеку p5js, чтобы нарисовать какую-нибудь абстрактную картинку, основанную на псевдорандомных числах. Для этого надо написать 2 глобальных функции: setup() и draw(). В setup() происходит инициализация канваса, а в draw() отрисовывается случайная линия, основанная на хеше транзакции. Что касается графических примитивов, у p5js очень хорошая документация, можно быстро разобраться что к чему. Всё, можно паковать код в zip архив, загружать в песочницу и смотреть на нфт-случайную линию! Теперь пора заняться вещами посерьёзнее чем рисование случайных линий. Начнём строить модульную абстракцию с класса порта. Порт — это просто именованное хранилище числа с геттером и сеттером, имеющее своё визуальное представление (например в виде кружочка с подписанным названием). Задача порта — хранить число, переданное ему кабелем в момент вызова метода process() (подробнее о том что это за метод — чуть ниже) и отдавать это число владеющему портом модулю в момент востребования. Ещё порт должен уметь отдавать свои экранные координаты, чтобы движок мог правильно нарисовать кабель из одного порта в другой Дальше нам понадобятся кабели, чтобы передавать значения между портами. Кабель должен хранить в себе ссылки на порты, которые он соединяет, уметь отрисовывать себя и иметь метод process(), в котором он будет перекладывать значение входного порта в выходной. Добавим также параметры scale и offset, задающие масштабирование и сдвиг сигнала при передаче по кабелю. Теперь напишем базовый класс модуля, реализующий в себе всё те же методы process() и draw(), вызываемые на каждый семпл и каждый кадр соответственно. Так как у каждого модуля наверняка будут какие-то входные и выходные порты, сразу создадим под них переменные и методы добавления. Получится примерно так:  Наконец, движок. Движок модульного синтезатора должен уметь делать три главных вещи: С учётом этих требований, он будет выглядеть как-то так:  Осталось только прикрутить движок к аудиопроцессору webaudio и p5js. И если с p5js всё более-менее понятно (нужно просто вызвать из глобальной функции draw() метод draw() движка), то с аудио есть один нюанс. API onaudioprocess, которое я использовал в своём проекте, уже давно маркируется как deprecated, но так как оно показалось мне удобнее чем audioworklet, я использовал его. В теории этот способ может не работать в каких-то браузерах. Для коммуникации модулей друг с другом в реальных системах как правило используется интерфейс CV/GATE. CV это control voltage, управляющее напряжение от -10 до 10 вольт, а GATE — прямоугольный импульс +10В, триггер.  VCO Напишем в качестве примера один, но самый главный модуль, без которого не обходится ни один патч — VCO. VCO расшифровывается как Voltage Controlled Oscillator — это модуль, осциллирующий на высоте тона, пропорциональной напряжениям на входах CV (control voltage) и FM (frequency modulation). Здесь есть важная деталь — высота тона осциллятора пропорциональна напряжениям на входах, если измерять её в октавах а не в герцах. Эта конвенция называется 1V/OCT, что значит что прирост напряжения на 1 вольт даёт прирост частоты на октаву, то есть в 2 раза. Зная это, напишем модуль VCO с двумя управляющими частотой входами CV и FM. Как работают другие типы модулей и как их написать можно подсмотреть например в исходниках VCV Rack. Вместо разбора их реализации расскажу, что делает и зачем нужен каждый из них. В итоге праздники закончились и как получилось так получилось я проковырялся с этим проектом около недели, написал ревербератор, квантайзер и резонансный фильтр, допилил визуалы до вменяемого состояния, нарисовал генеративные горы :) Каждый, кто создаст экземпляр этого синтезатора на NFT платформе получит уникальную итерацию значений параметров, тональности, базового сиквенса, визуального оформления. И возможно, получит некоторое удовольствие от залипания в него. https://genclub.club/ — русское сообщество любителей генарта fxhash.xyz — платформа генеративного арта на js twitter.com/ferluht — твиттер, где пишу апдейты по синту пишу код и музыку