Создание полноценных приложений на Max 7. Часть 1 — Постановка задачи, визуальное программирование

  • Tutorial
При решении задач визуализации информации, очевидно, возникает вопрос о практической реализации задуманного. Данный цикл статей посвящен процессу проектирования приложений с помощью визуального программирования в Max 7 от компании Cycling '74. Начнем изучение вопроса, от простого к сложному. Пройдем путь от любительской заготовки до полноценного «однофайлового» приложения (standalone .exe).

Уровень: легкий



Конечный результат


Наверняка кто-нибудь использует какую-либо программу и не догадывается, что она сделана с помощью Max. Такой программой, например, является DAW Ableton Live. Догадаться можно по интерфейсу объектов, а так же из-за Max for Live. Конечно, в таких серьезных проектах используется не только Max, но и дополнительные библиотеки, файлы, скрипты и т.д. Так же и некоторые современные программы на iPad для работы со звуком. В данном цикле статей мы попытаемся разобраться в процессе проектирования подобных сложных приложений, начиная с самых простых примеров.

Оглавление


1. Визуальное программирование
→ 1.1. Понятия
2. Интерфейс Max 7
3. Принцип построения программ в Max
→ 3.1. Модульные объекты со входами и выходами
→ 3.2. Инкапсуляция [p patchname]
→ 3.3. Самостоятельный патч
→ 3.4. [bpatcher]
4. Структура программы
→ 4.1. Проектное пространство
→ 4.2. Первые шаги
→ 4.3. Bang, Metro, Counter, Number
→ 4.4. Избавляемся от лишнего
→ 4.5. Другие объекты
→ 4.6. Логические операторы, регулярные выражения
→ 4.7. Логические выражения
5. Полезные модули
Прилагаемые файлы
Полезные ссылки


§ 1. Визуальное программирование


Визуальное программирование — способ создания программы для ЭВМ путём манипулирования графическими объектами вместо написания её текста. [1]


Данный способ программирования позволит читателю отойти от написания строк кода на языках типа C/C++, всё представляется в виде модулей и связями между ними. Процесс разработки становится более наглядным и быстрым, при этом программа выполняется в реальном времени, пока вы ее делаете, т.е. для любых изменений в структуре результат отображается сразу же, без компиляции. По сути, вы строите логическую блок-схему работы программы.

Для решения задач визуализации будем использовать визуальный язык программирования — Max (MSP). В основном, Max предназначен для создания интерактивных объектов искусства, но так же может быть применим при решении огромного пласта задач. Во многих областях можно найти что-то, что можно визуализировать красиво. Вспомните эти шпионские фильмы, в которых на компьютерах героев изображены различные красивые интерфейсы неведомых программ. Да и в реальности — например, визуализация информации, поступающей с датчиков. К тому же он позволяет вести разработку как на машинах с ОС Windows, так и на компьютерах с Mac OS.

§ 1.1. Понятия


Для описания процесса осуществления задуманного, введем следующие понятия:

  • Объект — элемент программы, выполняющий какие либо операции, либо отображающие информацию. Может иметь или не иметь входные и выходные значения.
  • Модуль — группа объектов, объединенных в субпатч с целью выполнения заданной работы.
  • Патч, субпатч — в Max 7 исходные файлы проектируемой программы сохраняются в формате .maxpatch, .maxhelp или .json и называются патчами. Субпатч в свою очередь — это дочерний элемент патча, может хранится как в отдельном файле, так и внутри патча.
  • Инлет [inlet] — объект, создающий коммутацию модулей друг с другом. Является входным параметром модуля.
  • Аутлет [outlet] — объект, создающий коммутацию модулей друг с другом. Является выходным значением модуля.
  • Вход модуля — место соединения внешних объектов с модулем, входные параметры.
  • Выход модуля — место соединения внешних объектов с модулем, посылает на выход результат работы модуля.


В терминах телекоммуникаций модуль выступает в роли коммутатора, который в свою очередь выполняет заданные функции и отправляет результат в выходные порты.

§ 2. Интерфейс Max 7


Примечание. В данной статье я постараюсь не углубляться в очевидные вещи. Очень много дополнительной информации о работе объектов и модулей доступно в справке — правой кнопкой мыши по объетку, затем «Open имя_объекта help». Поэтому при описании элементов программы предпочтение будет отдаваться в основном их предназначению, а не синтаксису или структуре.

В основном мы будем пользоваться режимами: конструктора и презентации, а так же заглядывать в окна консоли (Max console), инспектора объектов (Inspector, CTRL+I) и инспектора патча (Inspector Window, CTRL+SHIFT+I).



  1. Главное меню программы
  2. [inlet]-объекты. Входы модуля.
  3. Компоненты (объекты) модуля, исполняемая часть.
  4. [outlet]-объекты. Выходы модуля.
  5. Inspector. Параметры выделенного объекта.
  6. Заблокировать/разблокировать редактирование патча.
  7. Переключатель между режимами конструктора и презентации.
  8. Вкл/выкл сетку.
  9. Область программы.


§ 3. Принцип построения программ в Max


§ 3.1. Модульные объекты со входами и выходами


Процесс создания программ сводится к построению блок-схемы из модулей и связей между ними. Можно использовать встроенные в Max модули, но интересней всего писать их самому. Это очень удобно как при вызове их изнутри программы, так и при использовании в процессе программирования в целом. В обычном программировании данная модель представлена в виде ООП, ну или можно представить один модуль как одну функцию, параметры которой — входы [inlets] модуля, а return — выход, причем выходов может быть много [outlets].

Примечание: Для добавления объекта в патч кликните 2 раза мышкой по пустому месту, либо нажмите клавишу N, вводите название, нажимаете Enter и дальше можно уже соединять его с другими.

Есть несколько способов добавления самописных модулей:

— инкапсуляция [p patchname],
— самостоятельный патч,
— [bpatcher].

§ 3.2. Инкапсуляция [p patchname]


Данное понятие аналогично понятию инкапсуляции в обычных языках программирования. В данном случае всё элементарно — выделяем объекты, которые хотим объединить в группу/модуль/файл и нажимаем CTRL+E (Edit — Encapsulation). При завершении инкапсуляции таким образом на выходе получаем модуль — [p patchname], где patchname — любая фраза на английском. Так же доступны и цифровые символы.

Объединяемые объекты после завершения данного процесса исчезают из окна патча Max. На самом деле Max внутри оригинально патча создает субпатч, куда и переносит все выделенные объекты и их связи. В зависимости от наличия внешних связей, инкапсулятор может автоматически вставить объекты входы [inlet] и выходы [outlet], а так же соединить их с внешними объектами. Это очень удобно, когда разрабатываешь программу не задумываясь о нагромождении объектов, ведь при достижении определенного количества, структура программы перестанет быть читаемой и вы сами в ней запутаетесь. Для решения проблем организации структуры программы и предназначена инкапсуляция в Max.

Особенности: это инструмент группировки/разграничения объектов по различным признакам. Данный способ создания модулей предполагает уникальность каждого модуля. Т.е. если вы создадите один модуль таким образом и продублируете его — это будут уже два разных модуля. Внесение изменений в один из них не повлечет за собой изменение остальных дубликатов.

Применение: уникальные группы объектов, простые или сложные вычисления, которые используются в программе только в одном месте.

§ 3.3. Самостоятельный патч


Для создания модулей можно воспользоваться и другим способом. Достаточно создать новый файл, добавить и соединить нужные блоки, расположить объекты, отвечающие за принятие входа [inlet], и за отправку на выход — [outlet] и сохранить файл в любой папке (например создать отдельную папку «tools» и кидать туда патчи со своим префиксом). Далее уже в рабочем патче добавляем объект с именем [название_файла] (без разрешения файла .maxpat) и всё готово.

Данный способ можно использовать в комбинации с инкапсуляцией, описанной выше. Это даже еще удобнее. Можно инкапсулировать нужные объекты, открыть получившийся модуль (в заблокированном режиме два раза левой кнопкой мыши по блоку) и сохранить его как самостоятельный патч.

Особенности: удобная вещь для создания модулей по типу «черный ящик» — один раз написав модуль, мы уже не возвращаемся без надобности к его структуре и т.д. Мы видим только 3 вида информации: входы, название модуля и выходы. Важно, что при дублировании таких модулей, их содержание не становится уникальными, т.е. изменения в одном из дубликатов повлечет за собой изменения во всех них. Если точнее, то в таком случае редактируется не дубликаты модулей, а сам оригинальный файл модуля.

Применение: удобно применять этот способ при создании модулей для каких либо отдельных вычислений. Особенности позволяют многократно дублировать модули.

Наглядный пример — модуль перевода сообщения из десятичной системы исчисления в двоичную. Простой копипаст объектов абстракции переводчика внутри главного патча в этом случае будет признаком плохого тона, т.к. может оказаться, что модуль требует изменений. Легче изменить 1 файл, чем весь этот копипаст перебирать.

§ 3.4. [bpatcher]


Если в предыдущих способах мы создавали «черные ящики», то бывают случаи, когда нужно отобразить какую-либо часть модуля в открытом виде без редактирования структуры. Это могут быть различные числовые визуализации, отображения служебных сообщений и т.д. Еще более интересным является процесс добавления презентационной части модуля.

Данный способ расширяет границы применения самостоятельных патчей. Для того, чтобы добавить модуль в рабочий патч, просто создаем объект [bpatcher], а в инспекторе его свойств указываем путь к файлу модуля.

Особенности: можем видеть структуру и связи модуля, а так же презентационную часть.

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

§ 4. Структура программы


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

Лично для меня данный способ проектирования программ является более наглядным. К тому же не нужно дублировать кучу символьного кода, а в некоторых случаях это очень утомляет.

Наглядные примеры модулей, созданных перечисленными способами, представлены в файле tut01_subpatches.maxpat

§ 4.1. Проектное пространство


Для создания сложных программ с большим количеством библиотек в Max 7 предусмотрена возможность создания проектов. Данная функция представлена в виде списка патчей и других файлов, использующихся в проекте. Справа в миниатюре показано содержание уже готового крупного проекта по визуализации цифровой обработки сигналов. Как можно наблюдать, в списке видим не только сами файлы патчей .maxpat, но и файлы других типов.

В дальнейшем можно будет использовать такой список «для себя», просто чтобы знать где что лежит и какие модули использованы в данном проекте. Хотя, компилировать программу можно хоть из главного патча, хоть из меню с проектом. Отличие в том, что при открытии проекта можно задать открываемый патч по-умолчанию — открываешь проект и вместе со списком файлов открывается и назначенный патч.

§ 4.2. Первые шаги


Начнем наш тернистый путь познания о программировании в среде Max 7 созданием нового проекта. File → New Project. Рекомендуется сохранять все проекты в отдельную папку, например — C:\Max Projects\… Расположение папки с проектами в корне диска крайне удобно, особенно когда меняешь версию программы или ОС.

После сохранения проекта откроется окно со списком патчей проекта, но пока он пуст. Добавим новый файл в проект:
+ → Add New File… Сохраняем файл в каталог, где лежит файл проекта, а дальше Max сам создаст там папку patchers, в которую на самом деле и сохраняется файл патча.

§ 4.3. Bang, Metro, Counter, Number


Начнем с чего-нибудь простого, например, счетчик с тактовым генератором. Счетчик будет прибавлять значение на единицу только тогда, когда на вход счетчика приходит bang-сообщение от тактового генератора (метроном).

Bang — это специальное сообщение, запускающее работу модуля/объекта. Завершение любой операции в модуле на выходе дает какое-то значение, при этом сам факт отправки данных из модуля на его выход сопровождается bang-сообщением. Bang используем когда нужно отправить какое-либо сообщение куда-либо. Он как бы «толкает» сообщение дальше по тракту от объекта к объекту.

Добавим в наш патч объекты и связи как на изображении справа.

Примечание. Max хорош еще и тем, что патчами можно спокойно обмениваться в текстовом формате. Происходит это следующим образом — вы выделяете все элементы и связи в патче нажатием клавиш CTRL+A, копируете CTRL+C, а затем открываете любой текстовый редактор или форму на сайте и вставляете текст из буфера. По сути, описание состояния программы (структуру, данные) представляется в виде JSON-текста, который вы только что скопировали. Чтение такой информации происходит не намного сложнее: в главном меню Max 7 Files → New From Clipboard… А вообще, не обязательно даже создавать новый файл, можно вставить скопированное прямо в уже открытый патч. Таким образом, Max считывает текст из буфера обмена и интерпретирует его в модули и связи между ними.

Попробуйте скопировать приведенный ниже код программы и вставить в Max.
Код модуля tut_lesson01
{
	"patcher" : 	{
		"fileversion" : 1,
		"appversion" : 		{
			"major" : 7,
			"minor" : 0,
			"revision" : 2,
			"architecture" : "x64",
			"modernui" : 1
		}
,
		"rect" : [ 458.0, 167.0, 574.0, 390.0 ],
		"bglocked" : 0,
		"openinpresentation" : 0,
		"default_fontsize" : 12.0,
		"default_fontface" : 0,
		"default_fontname" : "Arial",
		"gridonopen" : 1,
		"gridsize" : [ 15.0, 15.0 ],
		"gridsnaponopen" : 1,
		"objectsnaponopen" : 1,
		"statusbarvisible" : 2,
		"toolbarvisible" : 1,
		"lefttoolbarpinned" : 0,
		"toptoolbarpinned" : 0,
		"righttoolbarpinned" : 0,
		"bottomtoolbarpinned" : 0,
		"toolbars_unpinned_last_save" : 0,
		"tallnewobj" : 0,
		"boxanimatetime" : 200,
		"enablehscroll" : 1,
		"enablevscroll" : 1,
		"devicewidth" : 0.0,
		"description" : "",
		"digest" : "",
		"tags" : "",
		"style" : "",
		"subpatcher_template" : "",
		"boxes" : [ 			{
				"box" : 				{
					"id" : "obj-21",
					"maxclass" : "comment",
					"numinlets" : 1,
					"numoutlets" : 0,
					"patching_rect" : [ 265.0, 165.0, 30.0, 20.0 ],
					"style" : "",
					"text" : "в)"
				}

			}
, 			{
				"box" : 				{
					"id" : "obj-20",
					"maxclass" : "comment",
					"numinlets" : 1,
					"numoutlets" : 0,
					"patching_rect" : [ 145.0, 165.0, 30.0, 20.0 ],
					"style" : "",
					"text" : "б)"
				}

			}
, 			{
				"box" : 				{
					"id" : "obj-19",
					"maxclass" : "comment",
					"numinlets" : 1,
					"numoutlets" : 0,
					"patching_rect" : [ 25.0, 165.0, 30.0, 20.0 ],
					"style" : "",
					"text" : "a)"
				}

			}
, 			{
				"box" : 				{
					"id" : "obj-13",
					"maxclass" : "number",
					"numinlets" : 1,
					"numoutlets" : 2,
					"outlettype" : [ "", "bang" ],
					"parameter_enable" : 0,
					"patching_rect" : [ 255.0, 135.0, 50.0, 22.0 ],
					"style" : ""
				}

			}
, 			{
				"box" : 				{
					"id" : "obj-14",
					"maxclass" : "newobj",
					"numinlets" : 5,
					"numoutlets" : 4,
					"outlettype" : [ "int", "", "", "int" ],
					"patching_rect" : [ 255.0, 90.0, 81.0, 22.0 ],
					"style" : "",
					"text" : "counter 2 0 3"
				}

			}
, 			{
				"box" : 				{
					"id" : "obj-15",
					"maxclass" : "number",
					"numinlets" : 1,
					"numoutlets" : 2,
					"outlettype" : [ "", "bang" ],
					"parameter_enable" : 0,
					"patching_rect" : [ 300.0, 15.0, 50.0, 22.0 ],
					"style" : ""
				}

			}
, 			{
				"box" : 				{
					"id" : "obj-16",
					"maxclass" : "newobj",
					"numinlets" : 2,
					"numoutlets" : 1,
					"outlettype" : [ "bang" ],
					"patching_rect" : [ 255.0, 60.0, 65.0, 22.0 ],
					"style" : "",
					"text" : "metro 500"
				}

			}
, 			{
				"box" : 				{
					"id" : "obj-17",
					"maxclass" : "toggle",
					"numinlets" : 1,
					"numoutlets" : 1,
					"outlettype" : [ "int" ],
					"parameter_enable" : 0,
					"patching_rect" : [ 255.0, 15.0, 24.0, 24.0 ],
					"style" : ""
				}

			}
, 			{
				"box" : 				{
					"id" : "obj-8",
					"maxclass" : "number",
					"numinlets" : 1,
					"numoutlets" : 2,
					"outlettype" : [ "", "bang" ],
					"parameter_enable" : 0,
					"patching_rect" : [ 135.0, 135.0, 50.0, 22.0 ],
					"style" : ""
				}

			}
, 			{
				"box" : 				{
					"id" : "obj-9",
					"maxclass" : "newobj",
					"numinlets" : 5,
					"numoutlets" : 4,
					"outlettype" : [ "int", "", "", "int" ],
					"patching_rect" : [ 135.0, 90.0, 81.0, 22.0 ],
					"style" : "",
					"text" : "counter 1 0 3"
				}

			}
, 			{
				"box" : 				{
					"id" : "obj-10",
					"maxclass" : "number",
					"numinlets" : 1,
					"numoutlets" : 2,
					"outlettype" : [ "", "bang" ],
					"parameter_enable" : 0,
					"patching_rect" : [ 180.0, 15.0, 50.0, 22.0 ],
					"style" : ""
				}

			}
, 			{
				"box" : 				{
					"id" : "obj-11",
					"maxclass" : "newobj",
					"numinlets" : 2,
					"numoutlets" : 1,
					"outlettype" : [ "bang" ],
					"patching_rect" : [ 135.0, 60.0, 65.0, 22.0 ],
					"style" : "",
					"text" : "metro 500"
				}

			}
, 			{
				"box" : 				{
					"id" : "obj-12",
					"maxclass" : "toggle",
					"numinlets" : 1,
					"numoutlets" : 1,
					"outlettype" : [ "int" ],
					"parameter_enable" : 0,
					"patching_rect" : [ 135.0, 15.0, 24.0, 24.0 ],
					"style" : ""
				}

			}
, 			{
				"box" : 				{
					"id" : "obj-7",
					"maxclass" : "number",
					"numinlets" : 1,
					"numoutlets" : 2,
					"outlettype" : [ "", "bang" ],
					"parameter_enable" : 0,
					"patching_rect" : [ 15.0, 135.0, 50.0, 22.0 ],
					"style" : ""
				}

			}
, 			{
				"box" : 				{
					"id" : "obj-6",
					"maxclass" : "newobj",
					"numinlets" : 5,
					"numoutlets" : 4,
					"outlettype" : [ "int", "", "", "int" ],
					"patching_rect" : [ 15.0, 90.0, 71.0, 22.0 ],
					"style" : "",
					"text" : "counter 0 3"
				}

			}
, 			{
				"box" : 				{
					"id" : "obj-5",
					"maxclass" : "number",
					"numinlets" : 1,
					"numoutlets" : 2,
					"outlettype" : [ "", "bang" ],
					"parameter_enable" : 0,
					"patching_rect" : [ 60.0, 15.0, 50.0, 22.0 ],
					"style" : ""
				}

			}
, 			{
				"box" : 				{
					"id" : "obj-4",
					"maxclass" : "newobj",
					"numinlets" : 2,
					"numoutlets" : 1,
					"outlettype" : [ "bang" ],
					"patching_rect" : [ 15.0, 60.0, 65.0, 22.0 ],
					"style" : "",
					"text" : "metro 500"
				}

			}
, 			{
				"box" : 				{
					"id" : "obj-3",
					"maxclass" : "toggle",
					"numinlets" : 1,
					"numoutlets" : 1,
					"outlettype" : [ "int" ],
					"parameter_enable" : 0,
					"patching_rect" : [ 15.0, 15.0, 24.0, 24.0 ],
					"style" : ""
				}

			}
 ],
		"lines" : [ 			{
				"patchline" : 				{
					"destination" : [ "obj-11", 1 ],
					"disabled" : 0,
					"hidden" : 0,
					"midpoints" : [ 189.5, 58.0 ],
					"source" : [ "obj-10", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-9", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-11", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-11", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-12", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-13", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"midpoints" : [ 264.5, 134.0 ],
					"source" : [ "obj-14", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-16", 1 ],
					"disabled" : 0,
					"hidden" : 0,
					"midpoints" : [ 309.5, 58.0 ],
					"source" : [ "obj-15", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-14", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-16", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-16", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-17", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-4", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-3", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-6", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-4", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-4", 1 ],
					"disabled" : 0,
					"hidden" : 0,
					"midpoints" : [ 69.5, 58.0 ],
					"source" : [ "obj-5", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-7", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"midpoints" : [ 24.5, 134.0 ],
					"source" : [ "obj-6", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-8", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"midpoints" : [ 144.5, 134.0 ],
					"source" : [ "obj-9", 0 ]
				}

			}
 ],
		"dependency_cache" : [  ],
		"embedsnapshot" : 0
	}

}



Разберем всё по порядку. Основными объектами в данном патче являются:
3 тактовых генератора ([toggle] + [metro]) и 3 счетчика [counter].

[toggle]
Переключатель. Имеет два режима работы: кнопка (Button) и переключатель (Toggle). При нажатии на [toggle], объект посылает на выход значение своего состояния [0, 1]. При нажатии на «кнопку», он посылает на выход короткую единицу. Переключатель отличается тем, что запоминает свое предыдущее состояние. Нажал один раз, на выходе 0, еще раз — 1, еще раз — 0 и т.д.

[metro 500]
Данный объект представляет из себя метроном, отправляющий на свой выход каждые N-миллисекунд bang-сообщение. В данном случае bang будет генерироваться каждые 500 мс.

[counter направление мин.значение макс.значение]
Счетчик, прибавляющий свое значение на одну единицу при каждом поступающем на вход bang-сообщении. По направлению отсчета счетчики разделяются на восходящий (а), нисходящий (б) и туда-обратно (в).

Таким образом, название объекта [counter 1 0 3] говорит нам о нисходящем счетчике с границами от 0 до 3. При достижении максимального значения счетчик сбрасывается и отсчет начинается с мин. значения. У объекта есть два инлета, позволяющие сбросить счетчик. Один из них сбрасывает значение мгновенно, а другой — сбросить, начиная со следующего отсчета.

[number]
Объект ввода данных, позволяющих хранить введенную информацию. Используется только для целых чисел, для чисел с плавающей точкой есть объект [flonum].

§ 4.4. Избавляемся от лишнего


Немаловажным умением при создании программ является умение избавляться от лишних деталей. Любознательный читатель заметил бы, что в вышепреведенном патче мы используем 3 тактовых генератора и 3 выключателя, хотя можно использовать всего по одному экземпляру. Забегая вперед скажу, что чем больше объектов типа [metro] вы будете добавлять, тем медленнее может стать обработка остальной информации программой. Чтобы получить программу с хорошим быстродействием, следует задумываться об этом еще на начальной стадии.

Избавимся от лишнего, удалим избыточные вычисления из программы:

Заменяем три тактовых генератора одним, входы счетчиков соединяем с выходом объекта [metro 500]. Так-то лучше. Вы можете сказать, что так надо было поступать с самого начала, но на практике координаты блоков генератора и других объектов могут сильно отличатся, не задумываясь добавляешь еще один метроном, а потом еще и еще. В итоге связи объектов превращаются в запутанную паутину, в которой довольно сложно ориентироваться. При правильном подходе данных проблем можно избежать множественными инкапсуляциями объектов в модули, группируя их по назначению. Этого мы и будем добиваться на протяжении всего цикла статей.

§ 4.5. Другие объекты


[print]
Если по каким-то причинам вы хотите выводить информацию в консоли, то для этого используется объект [print имя_строки]. Название объекта [print b] говорит нам о том, что при поступлении сообщения на вход [print], в консоли отобразится сообщение вида b: текст.

§ 4.6. Логические операторы, регулярные выражения


Элементарные операции

[+ i/f] — сложение двух значений входных параметров объекта с возвратом результата в аутлет.
Прим.: [+ 1], [+ 1.06]. i -int — целые числа, f — float — числа с плавающей точкой.

[* i/f] — умножение
[/ i/f] — деление

[+~ 1.] — сложение двух сигналов
[*~ 1.] — умножение двух сигналов

[if условие then 1 else 0] — при выполнении условия послать на выход единицу, в ином случае — ноль.
[if условие then 1 else out2 0] — при выполнении условия послать на первый выход единицу, в ином случае — во второй выход послать ноль.

[regexp] — работа с регулярными выражениями
[expr $i1 + $i2*$i3] — выполнить выражение между значениями, поступающими на вход модуль.

Остальные операции доступны в документации, всё аналогично обычному программированию.

Сохраняем приведенный код как два разных файла с именами tobit.maxpat и frombit.maxpat в папке патчей проекта. В дальнейшем, для осуществления операций кодирования/декодирования чисел мы будем пользоваться именно этими модулями.

§ 4.7. Логические выражения


С помощью объекта [vexpr] можно задавать различные логические операции.

tut_bitlogic.maxpat — в данном примере рассматриваются побитовые логические операции многоразрядных сообщений.

§ 5. Полезные модули


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

[toBit]
Данный модуль переводит переводит числа от 0 до 255 в восьмиразрядный битовый код.

[fromBit]
Принимает на вход восьмиразрядный битовый код, а на выходе выдает числа от 0 до 255.

[tut_dynamicInlets N]
Пример организации входов и выходов с заданным количеством N.

Прилагаемые файлы


image tut_lesson01.maxpat
image tut_bitlogic.maxpat
image tut_encapsulation.maxpat
image tut_dynamicInlets.maxpat

image toBit.maxpat
image fromBit.maxpat

image Все сразу (.zip) + каталог tutorial_all.maxpat

Полезные ссылки


Обзорная статья на хабре про Max MSP

Cycling '74 — сайт производителя/страница Max 7.
Max Objects Database — хранилище разнообразных объектов. Зачем изобретать велосипед, когда он уже есть.
Cycling '74 — Projects — проекты других разработчиков.
Cycling '74 — Forums — форум, где можно найти решения для многих задач, достаточно лишь правильно спросить.
Pattr.ru — здесь можно найти полезные плюшки и статьи для Max MSP.
maxmsp vk — группа русскоязычных пользователей.

В следующем номере


Список может изменится, примерный вариант:
  • § Формы и способы ввода информации
  • § Графики, GUI
  • § Открытие HTML-страниц
  • § Создание внешних ссылок
  • § Пути. PATH=?
  • § Вызов внешнего модуля (окна) с помощью кнопки



Автор: Валерий Зимнев
  • +9
  • 24.8k
  • 9
Share post

Similar posts

Comments 9

    +2
    Наверняка кто-нибудь использует какую-либо программу и не догадывается, что она сделана с помощью Max. Такой программой, например, является DAW Ableton Live.


    Создатель Ableton Live с вами не согласен

    Starting de- mystification process…

    Live was not prototyped in MAX. But almost all audio devices were. Parts of the concept were adapted from MAX patches Gerhard and me used for making music.
    Other parts are derived from experiences we made when Gerhard wrote the sampling modules for Reaktor. Gerhard has a long history of creating granular based software, starting at a Sicicon Graphics workstation at Techincal University Berlin…

    Most parts of Live were prototyped — on paper. Tons of sketches, month of discussions before the first line of C++ has been written.

    So, the missing link is not there…

    Best, Robert
    .

      0
      «But almost all audio devices were.»
      «Parts of the concept were adapted from MAX patches»

      Вот эти фразы полностью объясняют то, о чем я и говорю «сделана с помощью Max», а не «полностью на Max». Но аблетон слишком сложный, чтобы оставлять его только на максе.

      Кстати спс, я все думал на чем же еще они аблетон дописывают, кроме макса и си++
        0
        Ну DAW и девайсы — это несколько разные вещи. Вы же писали про DAW. Разобрались и отлично :)
          –2
          под DAW понимаю любые крупные программы, работающие со звуком. Ну или синтезаторы. На Max MSP много статей в основном в направлении создания музыки и аудиовизуальных-эффектов, проводятся различные воркшопы и мастер-классы, но уклон в них в основном на аудио. На максе как раз можно сделать свою более/менее рабочую DAW без больших усилий, т.к. информации доступной полно в интернете, как и примеров уже готовых синтезаторов, обработчиков звуковых файлов, семплеров, усилителей, фильтров и т.д. Короче, для работы с сигналами.

          Просто я подумал, что новая версия Max 7 уже почти созрела для проектирования чего-то другого, для решения других задач в виде графических интерфейсов управления микроконтроллерами, что-то на подобии SCADA наверное, для расчета различных сложных вещей. Я слышал, можно даже веб-сервер поднять свой с помощью Max 7, где-то в будущем я об этом хочу написать. Нашел человека, который этим занимается.
            0
            можно даже веб-сервер поднять свой с помощью Max 7

            Месье знает толк в извращениях )
              0
              Слишком громко сказал, наверное. Имел в виду отправку данных с микроконтроллера в сеть или интернет, например. ;)
      0
      Ожидал увидеть что-то похожее на Simulink.

      Есть стандарты визуального программирования, которые кроме всего прочего диктуют еще и «читаемость» алгоритма. Это важный плюс визуального подхода, и он теряется при создании спагетти-диаграмм.

      Как в случае сплайнов в Макс можно стандартизировать внешний вид?
        0
        § 3. Принцип построения программ в Max

        в этом разделе все расписал
        0
        Очень интересно видеть больше статей по MSP и Jitter

        Only users with full accounts can post comments. Log in, please.