Введение
Немного общей информации
PureData — визуальный язык программирования для создания интерактивных программ (в данном случае их чаще называют «патчи»), используемых для исполнения и записи компьютерной музыки, звукового дизайна и визуализаций. Люди, знакомые, например, с Max/MSP, узнают привычный для них графический код, так как PureData — один из языков семейства MAX-подобных.
Выражаясь проще и слегка утрировано — это язык, заточенный под программирование синтезаторов и эффектов.
В этой статье я опишу некоторые элементы языка, а так же основные принципы, на которых базируется работа со звуком в PureData.
PureData — кроссплатформенный, есть сборки для Windows, MacOS, Linux и FreeBSD; работает как со стандартными драйверами (ALSA, MMIO), так и с jack, ASIO, так же поддерживается трансфер midi. Все версии доступны для скачивания с официального сайта. Рекомендую качать extended-версию, так как в ней из коробки содержится большой набор внешних библиотек, крайне необходимых в большинстве случаев.
Представление цифрового звука
А вот тут можно вспомнить патефон и пластинку. Каков принцип записи звука на винил? Резак, царапающий виниловый диск, вынужденно колеблется под действием некоего источника (сигнал с микрофона, например), из-за чего на поверхности диска срез становится извилистым, и этот след идеально повторяет колебания резака. Впоследствии, когда игла движется по этой извилистой дорожке, она колеблется, точно повторяя колебания источника. Т.е. игла зазвучит. Так вот, если эту дорожку представить в виде графика, и записать с маленьким шагом координаты точек графика — мы получим звуковой файл. Таким образом WAV — не что иное, как массив чисел, которые являются точками некоей кривой. Данный процесс — разбиения волны на точки, — называется дискретизацией, а частота, с которой берутся точки для записи в файл — частота дискретизации.
Из этого как раз и рождается первый аспект программного синтеза: описывать математически звук как некую линию, которая является графическим представлением нужных нам колебаний. Этот подход универсален и реализуем на любом языке, имеющим библиотеки взаимодействия со звуковыми устройствами. Хотя на самом деле, это не обязательно, так как массив значений можно просто сложить в файл, повесив расширение WAV.
Такое представление логично и универсально, но не всегда удобно. Контролировать работу программного синтезатора гораздо проще и удобней, если взаимодействие элементов интерфейсно напоминает модульный синтезатор. Для тех кто не в курсе: модульный синтезатор — это устройство, состоящее из различных самостоятельных компонентов (т.н модулей: генераторы, фильтры, преобразователи и т.д.), соединенных между собой проводами. В этом случае исполнителю известно, какой модуль за что отвечает, в каком порядке они следуют друг за другом, и, немаловажно, конфигурацию можно изменять «на горячую».
Именно такой подход, с точки зрения построения кода, реализован в MAX-подобных языках:
Итак, Второй аспект программного синтеза на PD: взаимодействие элементов языка строится по аналогии с модульным синтезатором.
На практике эти два подхода находятся в симбиозе, взаимодополняя друг друга.
Итак, узнав, с чем мы будем иметь дело, приступим непосредственно к PureData.
Элементы языка PureData
a+b=?
В общем и целом, программирование нa PureData сводится к трем вещам: передача «импульсов», чисел и сигналов. Основных элементов языка тоже немного, четыре: объекты, численные блоки (number box), блоки сообщений (message box) и соединения, похожие на провода. Напишем простейшую программу, заставим PD сложить два числа.
Итак, в окне с новым патчем создадим объект (Сtrl-1), разместим где-нибудь этот прямоугольник и впишем туда [bng] (он же bang). Без этого объекта не обходится практически не один патч. Его задача создать и послать импульс. Сейчас разберемся куда и зачем. Теперь создадим два блока с сообщениями (Сtrl-2) и впишем туда два произвольных числа, соединив bang с каждым из блоков. Итак, теперь эти числа нужно сложить. Для этого снова создаем объект, и вписываем в него "+". Ожидаемо, правда? Соединим численные блоки с объектом "+". Теперь осталось только вывести результат. Это можно сделать либо в консоль, с помощью объекта print, либо оставить внутри патча, отправив его в number box (Ctrl-3).
Чтобы проверить патч в действии, его нужно заблокировать (Ctrl-E) и нажать на объект bang. Итак, в консоли или в numbreBox'e, мы видим результат. Если он неверен — не пугайтесь, строкой ниже все разберем. Что произошло, нажав на bang, мы создали импульс, который по соединениям пришел к блокам сообщений и передал их дальше объекту сложения и т.д.
А теперь попытаемся понять, почему у некоторых из нас результат сложения неверен. Просто нажмите bang еще раз. Теперь верно? Дело в том, что на правильность выполнения арифметических операций влияет порядок соединения элементов. При построении патча, схожим с нашим, правильность гарантируется, если объекты были соединены справа-налево. Это чертовски неудобно, невозможно отладить и найти ошибку. Но этого всего можно избежать, если применить другой объект, задача которого разбивать вход на несколько потоков и слать импульсы одновременно.
Это объект trigger.
Создадим объект с этим именем. Теперь рядом запишем, что нужно передать (bang — импульс, float — числовое значение, anything — любой). Так как мы разбиваем импульс на два, содержимое объекта у нас приобретает вид trigger bang bang, сокращенно t b b. Осталось соединить выходы с числами. Вот теперь результат будет верным независимо от порядка соединения.
Это, конечно, все замечательно, но как поступить, если мы хотим рассчитать длинное выражение, или воспользоваться математическими функциями? Ведь написанная вышеизложенным методом простейшая программа, вроде поиска корней квадратных уравнений, будет слишком сложной и запутанной. Для таких случаев в PD существует объект expression или expr. С помощью этого объекта можно описывать математические и логические выражения, а так же их комбинации. Рассмотрим тот же пример со сложением. $f1 и $f2, как нетрудно догадаться — переменные, и считаются они слева-направо. Крайний левый вход — $f1, и далее по порядку. Количество входов объекта expr равно числу переменных, используемых в выражении.
Послесловие и F1
Сегодня мы рассмотрели самый возможный минимум и разобрались в разности представлений, в следующей статье я опишу работу условной логики и простейшие объекты, связанные с работой над сигналами. Осталось только рассказать про систему справки. Справкой приходится пользоваться постоянно, и чтобы увидеть информацию по объекту, достаточно кликнуть по нему правой кнопкой мыши и выбрать пункт «help». Там будет содержаться описание и, в большинстве случаев, примеры использования. Полный список объектов и библиотек доступен в пункте Pd help browser или по хоткею Ctrl-b.
Следующие статьи и уроки, посвященные PureData я постараюсь выпускать не реже раза в неделю. Всех благ.
Автор: RoSenMann