Хабрахабр

Опыт алгоритмической композиции на языке ChucK


Прямо сейчас в арт-галерее «Дар» (Псков) работает выставка, озвученная при помощи программы на языке Chuck. Я попытаюсь рассказать, почему и как все это получилось.

Небольшая необходимая преамбула

Бывает так, что фейсбучная активность перерастает в нечто большее; так образовался своеобразный проект «Пост-исторический город П.» — онлайн-сообщество, иногда, впрочем, выходящее и на оффлайновые акции. По материалам сообщества в сентябре 2017 года вышла книга «Пост-исторический город П. Антипутеводитель», одним из авторов (и издателей) которой оказался я. Подробнее о книге можно почитать по ссылкам ниже, пока же достаточно сказать, что это сборник фотографий и текстов, нечто вроде каталога, который мифологизирует скучную бетонную реальность современного города.

Где-то осенью же зародилась идея выставки, крупноформатного собрания «greatest hits» по мотивам книги, а также кое-чего, в книгу не вошедшего. Тогда же появилась мысль озвучить пространство, в котором будут расположены изображения и тексты, звуками города. Не откладывая дело в долгий ящик, Дмитрий, мой соавтор, вооружившись соответствующим устройством, отправился бродить по городу П., записывая шумы, разговоры, скрипы и шорохи. В итоге получилось что-то около полутора часов сырого звука из разных мест города.

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

Реализация

Изначально мне хотелось сделать что-то незафиксированное, непредсказуемое – не просто нарезать и склеить готовых звуков, а чтобы они накладывались друг на друга и жили как бы своей жизнью. Про ChucK я на тот момент не знал практически ничего, но по первом рассмотрении он показался подходящим инструментом – знакомые языковые конструкции, классы с наследованием, многопоточность задаром, возможность работать с аудио на достаточно низком уровне. Прослушав в быстром темпе за несколько вечеров курс с лекций Kadenze, в выходные я засел за реализацию проекта.
Структура в итоге сложилась следующая:

  • перетекающие друг в друга в случайном порядке звуковые ландшафты – среда, фон, на котором все происходит
  • события – отдельные реплики или звуки, которые возникают тоже случайно с применением набора несложных эффектов (обратное воспроизведение, эхо, «робот», ускорение/замедление)
  • «биты» — набор достаточно стандартных электро/хип-хоп паттернов, озвученных скрипами, всхлипами, репликами, вырезанными из оригинального звука
  • простенький гранулярный синтез на небольшом наборе отдельных звуков: из случайных мест оригинального файла проигрывается небольшой кусочек, каждый раз разный

Получившаяся в итоге композиция стала удачным дополнением к выставке: пока человек разглядывает фото и читает текст, из размещенных на потолке динамиков слышится, допустим, гулкий звук двора, отдаленные детские голоса, потом вдруг возникает какая-нибудь странная реплика, и крутится, отдаляясь и ускоряясь, или появляется нервный икающий бит, на фоне которого шуршит обрывками чужого голоса синтезатор. Все это, разумеется, происходит непредсказуемым образом, и никогда не знаешь, что прозвучит в следующий момент.
В качестве музыки это достаточно жестокая по отношению к слушателю вещь, но в качестве фона, сопровождения – результат оказался вполне удовлетворителен. Не менее регулярная и не более шизофреническая, чем окружающая панельная повседневность, эта звуковая среда создает именно тот эффект, который и был нам нужен: не погрузиться в реальность города П., а выйти из нее, взглянуть со стороны, удивиться и задуматься.
Я не буду разбирать здесь исходный код – кто хочет, может прочитать его на GitHub, ничего сложного там нет. Чтобы запустить и послушать, достаточно скачать и установить ChucK и запустить run.cmd из корневой папки. Все – разработка и воспроизведение – делалось под Windows.

Плюшки и очарования

Одна из самых изящных вещей в ChucK – это одноименный перегруженный оператор, который выглядит как «=>». Да, присваивания (и, соответственно, инициализация с объявлением переменных) выглядят несколько непривычно:

0 => int i; "test" => string message;

поначалу машинально путаешь правую и левую стороны. Но зато как красиво соединяются объекты. Допустим, мы хотим взять звуковой файл, добавить реверберации, отрегулировать громкость и вывести получившийся результат в отдельный канал. В этом случае строится простая интуитивно понятная цепочка:

SndBuf sound => JCRev reverb => Gain master => Pan2 pan => dac;

Дальше можно настроить необходимые параметры – поскольку мы никак еще не работаем со временем, все это пока не звучит.

Обращение со временем – еще одна изящно сделанная часть ChucK. Выражения, исчисляющие время, выглядят как «число:: единица времени». Например:


1::second
1000::samp
2::day
(x + y)::minute

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

1::second => now;

Такое выражение называется «advance time» — мне почему-то нравится переводить это как «занять времени». Таким образом, чтобы издать первый звук на ChucK, нужно сделать следующее:


SinOsc sin => dac; // это уже полностью инициализированный объект-осциллятор, соединенный с устройством воспроизведения, но он пока молчит
// чтобы заставить его издать звук, нужно задать частоту (хотя по умолчанию она тоже не нулевая)
440 => sin.freq; // 440 Hz
// и «занять времени»
1::second => now;
// вуаля – ровно одну секунду мы слышим звук указанной частоты

ChucK вообще довольно дружелюбная штука, и многие вещи делаются совсем просто. Например, проиграем звук из файла:


SndBuf snd => dac; // инициализируем объект и направляем вывод "c:/music/test.wav" => snd.read; // читаем файл
snd.samples()::samp => now; // проигрываем до конца

Еще одна красиво реализованная вещь – создание потоков (в терминологии ChucK – shred). Для того, чтобы создать новый «шред» используется ключевое слово «spork» и специальный оператор «~». Вот как это выглядит:


// играем случайные звуки в заданный канал
fun void play(int channel)
{ SinOsc sin => dac.chan(channel); // создаем осциллятор while(true) { Math.random2f(100, 500) => sin.freq; // задаем частоту .1::second => now; // занимаем 100 мс }
}
// основная программа
spork ~ play(0); // играем в левый канал
spork ~ play(1); // играем в правый канал
// висим бесконечно, чтобы порожденные потоки не уничтожились
while(true) 1::second => now;

В общем я не намерен, конечно, писать тут «ChucK для начинающих»; приведенных примеров, думаю, достаточно, чтобы заинтересовать тех, кто может заинтересоваться.

Глюки и разочарования

При всей простоте, дружелюбности и интуитивной понятности, в ChucK (по крайней мере, под Windows – может, с другими платформами дела обстоят получше) встречаются и проблемы.

Среда разработки – miniAudicle – конечно, мало пригодна для таковой. Да, есть подсветка синтаксиса, обзор устройств, контроль виртуальной машины, консоль. Но – нет даже элементарного поиска/замены. К тому же периодически она грохается с ошибкой – например, если забыть поставить @ в операторе присваивания по ссылке «@=>» — и если в этот момент окно консоли не видно, то нет никакой возможности понять, в чем проблема.

В ChucK есть классы с наследованием, и это очень круто – но в них нет конструкторов, что несколько расстраивает. Вообще, когда я начал собственно писать код, возник какой-то когнитивный диссонанс – если достаточно сложные вещи делаются в ChucK просто, то что касается простых вещей – вроде работы со строками – в документации ни слова. Оказалось, что есть еще одна документация, где присутствует некоторое количество информации о стандартных библиотеках.

Поначалу я делал по потоку на каждый тип звука, и старался повторно использовать объекты SndBuf – но обнаружилось, что по прошествии некоторого времени, во-первых, начинает появляться какое-то потрескивание при воспроизведении, во-вторых, некоторые эффекты не отключаются, а аккумулируются, несмотря на все мои усилия их обнулить.

В результате я пришел к конструкции, когда каждое событие создает отдельный shred, где все объекты создаются заново и потом удаляются. Однако, выяснилось, что они не удаляются – заявленная сборка мусора, видимо, далека от совершенства, и при воспроизведении процесс постепенно съедает всю доступную память. Победить эту проблему в отведенный срок я так и не смог, поэтому просто попросил работников галереи время от времени перезапускать исполняемый файл.

В целом – ChucK производит очень приятное впечатление, для быстрого наброска, небольшого проекта, демонстрации – самое то. Но если вы задумали более серьезный проект – стоит основательно взвесить все «за» и «против», местами ChucK еще сыроват.

Дополнительные материалы

ChucK – основные ресурсы

  • Дистрибутив
  • Документация. Это далеко не полная документация. Удивительно, но здесь ни слова нет о базовых вещах, которые наверняка потребуются, вроде работы со строками или файлового ввода/вывода.
  • Другая документация. Этот материал частично пересекается с предыдущим, но также – что очень ценно – заполняет пробелы относительно стандартных библиотек.
  • Курс на Kadenze. Для прослушивания лекций требуется регистрация, для выполнения заданий и получения сертификата нужно платить. Этот курс рассчитан на людей, не имеющих опыта программирования, так что имеющим таковой местами будет скучновато. Но зато вы получите множество ценных сведений о ChucK практически из первых рук.
  • Книга «Programming for Musiciands and Digital Artists». Книга содержит примерно ту же информацию, что и видеокурс. Пришедшим с Kadenze дают скидку; но в то же время полный вариант книжки достаточно легко нагуглить в pdf

Проект «Звуки П.»

Книга «Пост-исторический город П.»

Инсталляция «Объятие Родины»

Теги
Показать больше

Похожие статьи

Кнопка «Наверх»
Закрыть