39
 MaxJava API Назначение  и применение  

MaxJava API

  • Upload
    oscii

  • View
    217

  • Download
    0

Embed Size (px)

Citation preview

Page 1: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 1/39

MaxJava API

Назначение и применение

Page 2: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 2/39

1. Начало .....................................................................................................................................3

Вступление .................................................................................................................................3Преимущества Java-external’ ов ................................................................................................3Как работают Java-external’ ы в Max? ......................................................................................3Приступая к работе ....................................................................................................................4Пути поиска объекта mxj (CLASSPATH) ...............................................................................5mxj quickie – Java IDE от Cycling’74........................................................................................5

2. Программирование Java-external’ ов ........................................................................9Конструкторы ............................................................................................................................9Конструкторы и приведение аргументов ..............................................................................11Объявление входов (inlets) и выходов (outlets) ....................................................................11Info- выход (Info Outlet) ...........................................................................................................12Создание Java-external’ ов без входов и выходов ..................................................................12Добавление подсказок для входов и выходов ......................................................................13

Сокращенная форма объявления входов и выходов ............................................................13Обработка числовых сообщений ...........................................................................................14Использование getInlet() для определения входа , в который поступило сообщение .......14Обработка сообщений типа int и float ...................................................................................14Работа со списками ..................................................................................................................15Обработка произвольных сообщений ...................................................................................16Произвольные сообщения и типы параметров .....................................................................18Тип сообщения anything ....................................................................................................20Сообщение viewsource .............................................................................................................21Перегрузка сообщений ............................................................................................................21

3. Взаимодействие с Max ...................................................................................................23

Метод outlet .........................................................................................................................23Отправка сообщений через info- выход .................................................................................25Использование атрибутов .......................................................................................................25Специальная обработка атрибутов ........................................................................................27

4. Многопоточное программирование . ......................................................................29Многопоточная модель Max...................................................................................................29Вывод информации в высоком приоритете ..........................................................................29Использование объектов MaxClock и Callback .............................................................30Выполнение “тяжелых ” функций в основном потоке .........................................................32Использование Java- потоков для выполнения “тяжелых ” функций ..................................33

5. Примеры программирования ....................................................................................35Игра “Пятнашки ”.....................................................................................................................35Объект pac ................................................................................................................................38

2

MaxJava API

Page 3: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 3/39

1. Начало Вступление

С появлением MaxMSP версии 4.5, у людей , которые хотят расширить инструментарий Max/MSP/Jitter, появилась возможность программировать external’ ы на языке Java.

External’ ы – это модули , обычно написанные на языке Си, которые загружаются в среду исполнения Max. С помощью external’ ов можно расширять функциональность программ ,написанных на Max, при помощи собственных алгоритмов .

Преимущества Java-external’ ов

Зачем нужно писать external’ ы на Java?

Главное преимущество Java-external’ ов – это кросс -платформенность .Вам нужно только написать программу и преобразовать ее в байт -код . Далее , этим байт -кодом можно пользоваться как в версиях Max под Windows, так и под MacOS X.

Java – это язык , который надежно работает с памятью .Java берет на себя управление памятью : отсутствуют указатели (которые могут стать

причиной некорректной работы external’ ов, написанных на языке Си), осуществляется автоматическая “сборка мусора ” для предотвращения “утечек памяти ” и т.д.

Java - это полноценный (в отличии от Си) объектно -ориентированный язык программирования (ООП ).Java позволяет использовать преимуществ s ООП : повторное использование кода ,инкапсуляцию , наследование , полиморфизм и пр . Стандартная библиотека Java содержит огромное количество готовых классов ( работа с сетью , базами данных , XML и пр.),которые отсутствуют в Си .

Cycling’74 предоставляет простую Java-IDE (integrated development environment) под

названием mxj quickie , которая позволяет разрабатывать несложные Java-external’ ы не выходя из Max. А для того , чтобы проверить измененную версию вашего кода - вам не понадобится даже перезапускать Max (external’ ы написанные на Си становятся частью среды исполнения и для проверки новой версии кода , вам необходимо перезапускать Max)

Как работают Java-external’ ы в Max?

Работа Java-external’ ов несколько отличается от работы external’ ов написанных на Си.Си-external’ ы загружаются напрямую в среду исполнения , а Java- классы (далее в тексте определения “класс ” и “external” будут использоваться наравне друг с другом , так как Java-external – это просто Java- класс или набор классов ) взаимодействуют с Max через специальный прокси -объект mxj .

3

MaxJava API

Page 4: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 4/39

Например , чтобы загрузить Java- класс под названием myextern , вам нужно впечатать аргумент -название вашего класса в объект mxj (через пробел ):[mxj myextern] , вместо впечатывания в object box просто названия , как это можно было бы сделать для Си-external’a.

mxj (и его MSP- версия mxj~ ) – написан на Си и предоставляет интерфейсы доступа к

экземпляру виртуальной Java- машины (JVM), созданной внутри Max. По ходу работы приложения Max ( до его закрытия ), создается только одна Java- машина и все объекты mxj делят ее между собой .

Схема работы Java- подсистемы в Max:

Приступая к работе

Для разработки несложных проектов , внутри Max существует простая IDE под названием mxj quickie , которая позволяет разрабатывать и тестировать классы не выходя из Max.Но вы также можете использовать любые другие Java IDE. Вот некоторые из них :

NetBeans – официальная IDE, рекомендованная компанией Sun. ( http://www.netbeans.org )

JBuilder Foundation – бесплатная IDE от компании Borland. ( http://www.borland.com )

Eclipse – бесплатная IDE от компании IBM ( http://www.eclipse.org )

Неважно , какой IDE вы будете пользоваться : главное , чтобы вы прописали пути к

библиотекам , которые вам понадобятся при разработке классов .

4

MaxJava API

Page 5: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 5/39

Самый простой способ указать местоположение библиотек - это положить файл max.jar ,который находится в папке Program Files\Common Files\Cycling’74\java\lib (Windows) или Library/Application Support/Cycling’74/java/lib (OSX), в папку lib\ext, в директорию в которой установлена Java.

Библиотека max.jar реализует так называемый API (application programming interface или

интерфейс программирования приложений ), который позволяет среде исполнения Max“общаться ” с вашими Java- классами , через прокси -объект mxj .В папке с установленным MaxMSP 4.5 и выше вы найдете html- документы , автоматически сгенерированные утилитой javadoc. В этих документах вы найдете исчерпывающее описание методов Java- библиотеки Max.

Пути поиска объекта mxj (CLASSPATH)

Чтобы прокси -объект mxj “нашел ” ваши классы , необходимо помещать скомпилированный байт -код в директорию , прописанную в путях поиска mxj .Пути поиска mxj (они отличаются от описанных выше настроек IDE) описывают папки , в которых нужно искать Java- классы . Обычно самый простой способ – поместить ваши классы в папку : Program Files\Common Files\Cycling’74\java\classes (Windows) или Library/Application/Support/ Cycling’74/ java/classes (OSX), которая по умолчанию прописана в путях поиска mxj . Чтобы изменить пути поиска mxj - нужно отредактировать файл max.java.config.txt ,который находится в папке Program Files\Common Files\Cycling’74\java (Windows) или Library/Application Support/Cycling’74/java (OSX). Например , чтобы mxj искал классы в папке d:/javaclass - надо прописать : max.system.class.dir d/javaclass

mxj quickie – Java IDE от Cycling’74

Самый простой способ написания Java-external’ ов – это использование mxj quickie IDE -среды разработки от Cycling’74. Для большинства несложных проектов , средств этой среды будет вполне достаточно . Главное преимущество mxj quickie заключается в том ,что она доступна внутри Max и позволяет создавать и загружать классы , не выходя из программы , что позволяет легко и быстро разрабатывать Java-external’ ы.

Также , при помощи mxj quickie можно получить доступ к коду любого Java-external’a,который находится в путях поиска mxj . Если вы находитесь в процессе разработки проекта , и вам понадобилось отредактировать исходный код нового или существующего MaxJava- класса : вы можете незамедлительно получить доступ к исходнику этого

external’a или откомпилировать новую версию , после внесения изменений в код .

Даже если вы не пользуетесь mxj quickie для разработки классов , вам все равно может пригодиться инструмент для быстрого редактирования , отладки или расширения функциональности существующих external’ ов. Кстати , mxj quickie тоже является Java-external’ ом и отлично демонстрирует возможности MaxJava API.

Чтобы продемонстрировать работу mxj quickie можно написать простой , но функциональный Java-external. Этот external будет выводить в консоль Max фразу “Hello,world!”, после того как будет получать сообщение bang в левый (и единственный ) вход .

Разъяснение кода будет приведено позже , а на данный момент будут описываться действия необходимые для компиляции external’a под названием “helloworld” в среде mxjquickie .

5

MaxJava API

Page 6: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 6/39

Запустите Max/MSP.

Создайте новый патч .

Создайте новый object box и впишите туда : mxj quickie helloworld

Дважды щелкните на только что созданном object box’ е mxj quickie helloworld .

После двойного щелчка должно открыться окно текстового редактора . В этом окне будет отображен текст шаблона для разработки Java external’ ов. Когда вы в первый раз будете открывать редактор - может пройти немного времени , т.к. JVM будет инициализировать графическую подсистему Swing. В течение этого времени object box объекта mxj quickiehelloworld будет мерцать различными цветами , показывая , что он находится в процессе работы .

Обратите внимание , что заголовок окна будет иметь название helloworld.java . Этот исходный Java- файл не будет сохранен до тех пор , пока вы не попытаетесь откомпилировать буфер редактора , или сохранить его , используя меню File->Save(сохраненный файл будет иметь расширения .java , такое же , как и стандартные Java-исходники ).Если вы случайно неправильно вписали название , например mxj quickie heloworld , вы можете закрыть окно редактора и вписать правильное название в object box. Никаких

дополнительных файлов , типа heloworld.java , на диск сохраняться не будет .

6

MaxJava API

Page 7: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 7/39

Шаблон кода в буфере будет содержать метод bang с пустым телом :

public void bang(){}

Внутри тела метода нужно вписать :

post(“Hello, World!”);

В итоге получится примерно так :

Public void bang(){

post(“Hello, World!”);}

Выберите из окна Java меню Open Compile Window… Возникнет диалог , который позволит скомпилировать буфер текстового редактора . Обратите внимание на поле Compiler Command: . В нем должен быть прописан путь к компилятору javac , при помощи которого вы можете скомпилировать исходник . Если в поле прописан неверный путь или оно пустое – щелкните на кнопке Browse… и укажите местоположения компилятора javac .

Полезно знать , что по умолчанию Windows не содержит ни Java- машины , ни компилятора . Чтобы установить компилятор и JVM, вам нужно скачать Java 2 Software Development Kit(J2SDK). Если вам не требуется компилятор , и вы просто хотите использовать уже существующие Java- классы - вам понадобится пакет Java 2 Runtime Environment (J2RE),который содержит только JVM. Все это и многое другое вы можете скачать с сайта компании Sun Microsystems ( http://www.java.sun.com ).В операционной системе Mac OSX компилятор и JVM встроены по умолчанию .В настоящий момент mxj поддерживает Java 2 версии 1.4. Для того чтобы использовать Java 2 версии 1.5 вам нужно прописать в файле max.java.config.txt следующее :max.java.jvm.version 1.5 Поле Compiler Command: запоминает внесенные в него изменения , соответственно вам нужно прописать путь к компилятору всего один раз. Если вы хотите изменить настройку

– снова щелкните на кнопке Browse… и изменения опять сохранятся .

И, наконец , щелкните на кнопке Compile , чтобы преобразовать исходник в байт -код и поместить файл с расширением .class в директорию по умолчанию . Окно компилятора будет отображать команды , которые используются для компиляции , а также сообщения ,возникающие в процессе .

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

сочетания клавиш Command-k (OSX) или Control-k (Windows).Также , можно переключиться на окно редактора из окна компиляции , используя сочетание Command-e (OSX) или Control-e (Windows).

7

MaxJava API

Page 8: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 8/39

Если вы успешно откомпилировали свой external, можете закрыть окно редактора . Чтобы посмотреть на работу Java-external’a, вы должны создать новый object box и вписать в него [mxj helloworld] . Создайте объект button . Подключите button к левому (единственному )входу external’ а. Щелкните на объекте button , и в консоли Max должна появиться надпись “Hello, World!”.

В любое время , когда вам нужно создать экземпляр этого external’a, вам нужно впечатать в object box [mxj helloworld] . Если вы захотите отредактировать ваш external, чтобы расширить его функциональность , вам нужно будет создать новый object box ( если его не существует ), вписать в него [mxj quickie helloworld] и щелкнуть по нему два раза .В редакторе откроется последний сохраненный исходный код для его дальнейшего редактирования (если исходного кода нет , то mxj quickie попытается декомпилировать байт -код ). Если вы удалите исходник (helloworld.java ) и байт -код (helloworld.class ) из директории , то после запуска редактора mxj quickie , вы увидите стандартный шаблон MaxJava класса .

Примечание : Если вы изменили код класса и откомпилировали его - необходимо перезагрузить этот класс в объекте mxj (если этого не сделать - mxj будет использовать старую версию кода , которая находится в оперативной памяти ). Поэтому вам нужно создать новый экземпляр объекта mxj и вписать в него [mxj helloworld] , или перезагрузить старый объект mxj , перепечатав в нем название вашего класса .Все оставшиеся экземпляры mxj , которые вы не перезагрузили , продолжат использовать старую версию кода .

8

MaxJava API

Page 9: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 9/39

2. Программирование Java-external’ ов В данном документе приводятся начальные сведения о библиотеке MaxJava API. Для детального описания – смотрите html- документацию , которая находится в папке с установленным Max.

Конструкторы

Чтобы Java-external успешно работал с объектом mxj – ваш Java- класс должен быть наследником класса com.cycling74.max.MaxObject . Если вы посмотрите документацию на класс MaxObject , вы найдете много методов , при помощи которых вы можете взаимодействовать со средой исполнения Max. Создавая наследника от класса MaxObject , вы получаете доступ к этим методам в вашем классе .

public class scale extends com.cycling74.max.MaxObject{

private float scale_factor; // переменная класса scale}

Или предпочтительный вариант :

/* импорт всех классов MaxJava API из библиотеки max.jar.В этом случае вам не нужно прописывая полный путь методов классов MaxJava API при обращении к ним */

import com.cycling74.max.*;

public class scale extends MaxObject{

private float scale_factor; // переменная класса scale}

Перегрузка методов очень полезна при программировании Java-external’ ов, а конструктор – это основное место , где рекомендовано ее реализовывать . Предположим , вы хотите ,чтобы пользователь передал значение переменной scale_factor через аргумент вашего Java-external’ а во время его инициализации . То есть , пользователь будет вписывать в object box что -то вроде [mxj scale 1.2] .Конструктор класса будет выглядеть так :

public scale(){bail("(mxj scale) you must provide a default”+” scale factor e.g. [mxj scale 0.5].");}public scale(float scale_arg){scale_factor = scale_arg;}

9

MaxJava API

Page 10: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 10/39

Если пользователь впишет в object box только mxj scale , то будет вызван пустой конструктор , так как не был получен аргумент для инициализации .В этом случае метод bail выведет в консоль Max сообщение об ошибке , которая объяснит пользователю , почему не произошла инициализация объекта .Объект mxj scale примет форму “нефункционального ” объекта без входов и выходов .Такое поведение объектов предпочтительно использовать , чтобы указывать пользователю

на отсутствие данных для инициализации объекта .

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

public class foo extends MaxObject{// глобальные переменные класса String name;float velocity;int factor;public foo(){bail("(mxj foo) must provide a name for”+” foo e.g. [mxj foo cheesecake]");}public foo(String thename){this(thename, 1.2, 40);}public foo(String thename, float thevelocity){this(thename,thevelocity,40);}public foo(String thename, float thevelocity,int thefactor){name = thename;velocity = thevelocity;factor = thefactor;}}

В этом случае следующие object box’ ы будут корректно инициализировать экземпляры вашего класса :

[mxj foo goober]

[mxj foo goober 0.7]

[mxj foo goober 0.7 42]

Вариант [mxj foo] будет вызывать ошибку инициализации и создание “нефункционального ” объекта без входов и выходов , так как аргумент thename является обязательным .

10

MaxJava API

Page 11: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 11/39

Конструкторы и приведение аргументов

Аргументы , которые получает объект из Max, будут приведены к типам данных , которые вы указали в конструкторе . Если вы объявили такой конструктор :

public foo (float x, float y, float z)

и пользователь впечатал [mxj foo 1 0 1] в object box - аргументы 1 0 и 1 будут автоматически приведены к типу float ( то есть 1.0 0.0 и 1.0), перед их передачей в конструктор .

В схеме приведения типов поддерживаются все основные типы данных Java, поэтому следующий список отображает правильные конструкторы :

public foo(int i, float f, String s)public foo(short s)public foo(boolean b1, boolean b2, byte b)public foo(int[] intarray)public foo(float[] floatarray)

и т.д.

Обратите внимание , что если конструктор содержит массив в качестве аргумента , этот массив должен быть единственным аргументом этого конструктора . Поэтому :

public foo(int[] ia1, int[] ia2)

и

public foo(float f, int[] ia)

являются неправильными конструкторами Java-external’ а.

Объявление входов (inlets) и выходов (outlets)

Следующей задачей написания конструктора – это указание прокси -объекту mxj количество входов и выходов для вашего класса . Это можно сделать при помощи методов declareInlets и declareOutlets класса MaxObject .

Методы declareInlets и declareOutlets требуют наличие аргументов в форме int- массивов , которые описывают типы входов и выходов в порядке слева - направо . Типы входов и выходов , которые вы можете создать , описываются переменными типа staticfinal (статичные , константные ) в классе com.cycling74.max.DataTypes.

Типы данных , с которыми вы обычно будете работать :

DataTypes.INT Входы /выходы поддерживают тип int

DataTypes.FLOAT Входы /выходы поддерживают тип float

DataTypes.ALL Входы /выходы поддерживают типы int, float и String

11

MaxJava API

Page 12: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 12/39

Соответственно , если вы хотите , чтобы external имел 2 входа и 2 выхода , нужно вызвать следующие методы в теле конструктора :

import com.cycling74.max.*;public class foo extends MaxObject{

/* глобальные переменные класса */private float _x;private float _y;private float _z;public foo(){bail(“(mxj foo) must provide x,y, and z arguments”);}public foo(float x, float y, float z){_x = x;

_y = y;_z = z;declareInlets(new int[]{ DataTypes.ALL, DataTypes.ALL});declareOutlets(new int[]{ DataTypes.ALL, DataTypes.ALL});}}

Info- выход (Info Outlet)

По умолчанию у всех Java-external’ ов есть специальный дополнительный выход , под названием info- выход (info-outlet). Он всегда является самым правым и предназначен для мониторинга значений атрибутов . Если в info- выходе нет необходимости , вы можете вызвать в конструкторе метод createInfoOutlet(false); . Например :

public foo(float x, float y, float z){_x = x;_y = y;_z = z;declareInlets(new int[]{ DataTypes.ALL, DataTypes.ALL});declareOutlets(new int[]{ DataTypes.ALL, DataTypes.ALL});createInfoOutlet(false);}

Создание Java-external’ ов без входов и выходов

По умолчанию , ваш Java-external всегда будет создаваться с одним входом , одним выходом и дополнительным info- выходом . Если вы хотите , чтобы ваш Java-externalвообще не имел входов и выходов , вам нужно использовать переменные типа NO_INLETS и NO_OUTLETS класса MaxObject .

declareInlets(NO_INLETS); // не создавать входов declareOutlets(NO_OUTLETS); // не создавать выходов

12

MaxJava API

Page 13: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 13/39

Примечание : в MSP версии объекта mxj~ невозможно создать Java-external без входов .Один вход всегда будет создаваться для получения сообщений из Max.

Добавление подсказок для входов и выходов

Вы можете добавить подсказки для каждого входа и выхода вашего external’ а. Эти

сообщения -подсказки будут появляться внизу окна Max в разблокированном окне Patcher.Вообще , стоит создавать подсказки для того , чтобы не забыть о том , как функционирует объект .

Самый простой способ создавать подсказки – пользоваться методами setInletAssist setOutletAssist класса MaxObject . В качестве аргументов эти методы требуют String- массивы , описывающие входы и выходы слева - направо .

public foo(float x, float y, float z){_x = x;_y = y;_z = z;declareInlets(new int[]{ DataTypes.ALL, DataTypes.ALL});declareOutlets(new int[]{ DataTypes.ALL, DataTypes.ALL});setInletAssist(new String[] { "bang to output","bang to reset"});setOutletAssist(new String[] { "calc result 1","calc result 2"});}

Сокращенная форма объявления входов и выходов Существуют сокращенные методы объявления входов и выходов Java-external’ ов:declareIO и declareTypedIO . Предположим , что вам нужен класс с 3 входами и 2выходами . В этом случае вы можете использовать метод declareIO в качестве альтернативы методам declareInlets и declareOutlets . Метод declareIO создает входы и выходы типа DataTypes.ALL .

public foo(float x, float y, float z){_x = x;_y = y;_z = z;declareIO(3,2);}

Метод declareTypedIO похож на declareIO , но он также позволяет указывать типы входов и выходов , которые вы хотите создать . Детальное описание метода declareTypedIO можно найти в html- документации на класс MaxObject .

13

MaxJava API

Page 14: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 14/39

Обработка числовых сообщений

Взаимодействие между объектами в среде Max осуществляется при помощи сообщений .Например , когда вы создали объект number box ( box1 ), который отсылает сообщения в форме int , а выход этого объекта вы подключили к входу другого объекта number box(box2 ), то box1 будет отсылать сообщение int с текущим числом в объект box2 .

Эта схема отображает путь сообщения типа int со значением 22 через ваш патч :

[box1]------- “int 22” ------- [box2]

В external’ ах, написанных на Си, вам придется создавать специальные функции (при помощи вызова методов addmess ), которые будут привязаны к определенным сообщениям .В MaxJava API, в классе MaxObject, для основных типов сообщений существуют пустые функции , которые вы можете переопределить , чтобы запрограммировать нужную реакцию на определенные сообщения Max. Например , если вы хотите , чтобы Java-external реагировал на сообщение bang , вам нужно переопределить метод bang в классе MaxObject .

public void bang(){post("I was just banged pretty well.");}

В этом случае , если ваш объект будет получать сообщение bang в любой из входов - в консоль Max будет выводиться сообщение "I was just banged pretty well.".

Использование getInlet() для определения входа , в который поступило сообщение

Если у вашего объекта есть несколько входов , и вы хотите узнать , в какой из них поступило последнее сообщение , вы можете воспользоваться методом getInlet .

public void bang(){int inlet_num = getInlet();post("I was just banged pretty well in inlet "+inlet_num);}

Метод getInlet возвращает номер входа , в который поступило последнее сообщение .Входы нумеруются с 0, начиная от самого левого . Поэтому , если вы получите bang в первый вход , объект выведет в консоль : "I was just banged pretty well on inlet 0", а если вы получите bang во второй вход , объект выведет в консоль : "I was just banged pretty well oninlet 1".

Обработка сообщений типа int и float

Обработка сообщений типа int или float очень похожа на обработку сообщений bang , за

исключением того , что вы будете получать еще и значения сообщения . Когда кто -то подключает к входу вашего Java-external’ а объект number box и изменяет его значение ,ваш объект будет получать сообщения типа int или float.

14

MaxJava API

Page 15: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 15/39

Чтобы обрабатывать эти числовые типы данных , вам необходимо переопределить методы inlet класса MaxObject . Существует один метод для типа int и один метод для типа

float .

public void inlet(int i){

int intlet_no;inlet_no = getInlet();post("I got an integer in inlet "+inlet_no);}public void inlet(float f){int intlet_no;inlet_no = getInlet();post("I got a floating point number in inlet "+inlet_no);}

Обратите внимание , что оба метода называются одинаково , но имеют разные типы данных аргумента . Это называется перегрузкой функций \ методов . В Java- методах значение имеет не только их название , но и сигнатура (т.е. аргументы метода ).

Примечание : Если вы переопределите только метод обработки чисел типа float (inlet (float f) ) - объект mxj будет автоматически приводить числа типа int к типу

float . Аналогично , если вы переопределите только метод inlet (int i) - объект mxj будет автоматически приводить числа типа float к типу int , а вся дробная часть чисел будет отбрасываться .

Работа со списками В Max, набор простых числовых типов и символов , начинающихся с числа , называется списком (list), а если первым элементом является символ – это называется сообщением (message).

Если вы создадите message box ( box1 ), впишите туда [1.2 4 killa 8.6 bass 3 88 mahler] и подключите его к входу другого message box’ а (box2 ), а затем щелкните на box1 – то сообщение , которое будет исходить из box1 , будет выглядеть так :

' щелчок мышью '-->[1.2 4 killa 8.6 bass 3 88 mahler ]-->

”list 1.2 4 killa 8.6 bass 3 88 mahler”-->[box2]

Поскольку список может содержать как целые , так и вещественные числа , а также символы необходимо представить новый тип данных , для обработки таких сообщений .Этот тип данных называется Atom . Atom может содержать вещественные , целые числа или строки и в этом он немного похож на объединения (union), используемые в языке Си.По правде говоря , на самом нижнем уровне среда Max и mxj работают с аргументами сообщений как с типом Atom . Как будет видно далее , при отправке сообщений через выходы вашего externel’a обратно в Max, вы будете пользоваться предпочтительно типом

Atom . Это потому , что среда исполнения Max сама “ничего не знает ” о типах данных Java.Внутри Max существует всего три типа данных : целые числа , вещественные числа и

символы , а прокси -объект mxj автоматически конвертирует символьные данные в тип String , который используется в Java.

15

MaxJava API

Page 16: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 16/39

Обработка списков во многом схожа с обработкой простых числовых данных , за исключением того , что вы имеете дело с массивами типа Atom , а не с единственными аргументами известного типа .

public void list(Atom[] args){

post("Received list message at inlet "+getInlet());// цикл по всем элементам массива типа AtomAtom a;for(int i = 0; i < args.length; i++){a = args[i];if(a.isFloat())post("List element "+i+" is a floating point atom witha value of "+a.getFloat());else if(a.isInt())post("List element "+i+" is an integer atom with a

value of "+a.getInt());else if(a.isString())post("List element "+i+" is a String atom with a valueof "+a.getString());}}

Показанный выше метод является примером простейшей обработки списков : цикл просматривает все элементы массива и выводит в консоль Max данные о типе и значении текущего элемента . Поэтому , если вы отошлете сообщение “1.2 killa 8.6 bass mahler ” в любой из входов объекта , то консоль выведет следующее :

List element 0 is a floating point atom with a value of 1.2

List element 1 is an integer atom with a value of 4

List element 2 is a String atom with a value of killa

List element 3 is a floating point atom with a value of 8.6

List element 4 is a String atom with a value of bass

List element 5 is an integer atom with a value of 3

List element 6 is an integer atom with a value of 88

List element 7 is a String atom with a value of mahler

Обработка произвольных сообщений

Когда вы пишите external’ ы на Си, вам необходимо явно “говорить ” среде Max какие сообщения понимает ваш объект при помощи вызова методов addmess . Когда вы

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

16

MaxJava API

Page 17: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 17/39

В Java-external’ ах нет подобного механизма регистрации сообщений , на которые будет реагировать ваш объект , поэтому в MaxJava API используется идея области видимости методов , для идентификации механизмов реакции на определенные сообщения .Подобный механизм отсутствует в Си, однако вы можете быть с ним знакомы , если вы программируете в Си++ , Smalltalk или в других языках ООП .

Области видимости Java- методов могут быть определены при помощи ключевых слов public , private и protected . Эта видимость определяет другие классы , которые могут обращаться к методам вашего класса . Когда метод объявлен как private , он может быть вызван только экземплярами класса , в котором определен этот метод .Наследники (подклассы ) этого класса уже не смогут получить доступ к этому методу .

Когда метод объявлен как protected , он может быть вызван как экземпляром класса , в котором определен этот метод , так и всеми подклассами (наследниками ) этого метода , а также другими классами определенных в одном пакете (package).Это похоже на определение “дружественных ” (friendly) методов в Си++, где вы говорите ,что класс A является “дружественным ” классу B и тем самым даете доступ к информации и методам класса B.

И, наконец , метод объявленный как public , дает право обращаться к нему из любого класса , загруженного в JVM в данный момент . Спецификатор public означает , что метод или переменная класса доступна всем без исключения .

Существует еще один спецификатор – спецификатор умолчания , когда вы не используете слова public , private или protected (то есть никак не помечаете метод или переменную ). В этом случае , метод или переменная будет доступна классам того же пакета (package), что и объявленный класс .

Чтобы определить сообщения , на которые будут реагировать ваши external’ ы, вам нужно создать функции с именами аналогичными сообщениям , на которые эти функции должны реагировать . Также к этим функциям необходимо применять спецификатор public , а возвращаемый тип данных должен быть void (без результата ). Например , если вы хотите ,чтобы объект реагировал на сообщение stop , вы должны объявить следующую функцию в вашем классе :

public void stop(){post("I received the stop message.");}

В этом случае , если кто -то впечатает stop в object box и подключит его к входу вашего Java-external’a, то при щелчке на этом message box’ е будет вызываться описанная выше функция .

Вы можете спросить , почему методы для реакции на сообщения типа int или float названы inlet , вместо int или float ? Причина в том , что слова int и float являются зарезервированными в языке Java и не могут служить именами функций .

17

MaxJava API

Page 18: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 18/39

Произвольные сообщения и типы параметров

Множество сообщений могут сопровождаться аргументами – например resize 100 .Обычный способ определить обработчик сообщения , который принимает неизвестное количество аргументов , это объявить метод с массивом Atom в качестве аргумента . Это будет называться сигнатурой списка .

Поэтому , мы можем написать реализацию метода resize следующим способом :

public void resize(Atom[] newsize){Atom a;if(newsize.length >= 1){a = newsize[0];if(a.isInt())_do_resize(a.getInt());else if(a.isFloat())_do_resize((int)a.getFloat());elsepost("resize message does not understand the stringargument "+a.getString());}}

Если вы считаете , что подобная реализация несколько сложна , вы можете воспользоваться более простым обработчиком сообщения resize :

public void resize(int newsize){_do_resize(newsize);}

В одном из прошлых разделов “Конструкторы ”, рассказывалось о том , как объект mxj автоматически приводит аргументы . Примерно так же функционирует обработка сообщений . Соответственно , если кто -то отсылает в Java-external сообщение resize cаргументом типа float , например resize 200.4 , то объект mxj автоматически приведет значение float 200.4 к значению int 200 , прежде чем передаст его в обработчик сообщения .

Примечание : Если кто -то отошлет в ваш Java-external сообщение resize с символьным аргументом (типа resize goforit ) - mxj выведет в консоль Max предупреждение о некорректном приведении типов и вызове метода resize с аргументом 0. Во всех случаях , при передаче символьных аргументов в метод , который ожидает числовой аргумент , в консоль Max будет выводиться предупреждение , а вместо символа будет передан 0.

В случае , когда вы хотите , чтобы ваш обработчик сообщений принимал больше чем один аргумент (но не хотите использовать массивы ) - просто добавьте больше параметров в сам обработчик .

18

MaxJava API

Page 19: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 19/39

public void doit(int i1, int i2, float f1, float f2){post("doit was called with "+i1+":"+i2+":"+f1+":"+f2);

}Следующие типы параметров поддерживают схему приведения , используемую объектом mxj , а также являются допустимыми параметрами при объявлении методов , которые обрабатывают сообщения .

boolean mxj будет приводить все ненулевые аргументы к true , а все нулевые к false .Все символы , кроме символа false будут приведены к нулю .

byte mxj будет приводить все числовые аргументы к типу данных byte (8 бит ) с диапазоном от -128 до 127. Символьные аргументы будут всегда приводится к 0.

char mxj будет приводить все числовые аргументы к их соответствующим значениям Unicode. Если символ имеет длину больше чем 1 – то mxj пропустит только его первую букву .

short mxj будет приводить все числовые аргументы к типу данных short (16 бит ) с диапазоном от -32768 до 32767. Символьные аргументы будут всегда приводится к 0.

int mxj будет приводить все числовые аргументы к типу данных int (32 бита ) с

диапазоном от -2147483648 до 2147483647. Символьные аргументы будут всегда приводится к 0.

long mxj будет приводить все числовые аргументы к типу данных long (64 бита ) Так как внутренняя разрядность Max равняется 32 битам , вы не сможете получить или отправить в Max числа находящиеся за диапазоном 32 бита . Однако вы можете использовать тип long для внутренних вычислений объекта . Символьные аргументы будут всегда приводится к 0.

float mxj будет приводить все числовые аргументы к типу данных float (32 бита ) с диапазоном от +/-1.4E-45 до +/-3.4028235E+38. Символьные аргументы будут всегда приводится к 0.

double mxj будет приводить все числовые аргументы к типу данных double (64 бита ) с диапазоном от +/-1.4E-45 до +/-3.4028235E+38. Так как внутренняя разрядность Max равняется 32 битам , вы не сможете получить или отправить в Maxвещественные числа находящиеся за диапазоном 32 бита . Однако вы можете использовать тип double для внутренних вычислений объекта . Символьные аргументы будут всегда приводится к 0.

String mxj будет приводить все числовые аргументы к их эквиваленту в представлении типа String и в этом случае в консоль Max будет выводится предупреждения .Символьные данные будут приведены к их эквиваленту типа String .

19

MaxJava API

Page 20: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 20/39

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

public foo(int[] ia1, int[] ia2)

и

public foo(float f, int[] ia)

являются неправильными обработчиками сообщений , тогда как :

public foo(boolean[] ba)

является правильным .

Следующие типы массивов поддерживаются правилом одного массива , а также

правилами приведения типов аргументов для каждого элемента массива .

boolean[]byte[]char[]short[]int[]long[]float[]double[]String[]

В случае , когда произвольное сообщение требует массива смешанного типа данных Atom[] : правила написания обработчика аналогичны примеру выше .

Тип сообщения anything

В MaxJava API существует еще один тип сообщений : сообщение anything . Если вы определите сообщение со следующей сигнатурой :

public void anything(String msg, Atom[] args)

и ваш external получит сообщение , которое не подходит по условиям ни к одному обработчику , то будет вызван метод anything в который будет передаваться параметр msg (типа String ), который будет представлять из себя имя сообщения и массив args (типа Atom), который будет содержать аргументы сообщения . Метод anything позволяет вам “отлавливать ” все сообщения , которые не подходят под условия ваших обработчиков .

20

MaxJava API

Page 21: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 21/39

Следующий пример будет выводить в консоль аргументы сообщения , если аргументов больше одного :

public void anything(String msg, Atom[] args){post("I received a " + msg + " message.");

if (args.length > 0){post("It has the following arguments:");for (int i=0;i<args.length;i++)post(args[i].toString());}}

Сообщение viewsource

В классе MaxObject , а соответственно и во всех остальных Java-external’ ах (т.к. они являются наследниками MaxObject ) по умолчанию существует реализация метода viewsource . После того как вы отошлете сообщение viewsource в ваш Java-external, он попытается найти исходный текст своего кода и вывести его на экран при помощи экземпляра класса - редактора MXJEditor . Если исходный код невозможно найти -обработчик попытается декомпилировать байт -код и вывести его на экран . Если вы не хотите , чтобы в вашем объекте была функция , которая бы позволяла увидеть его реализацию , вам нужно просто переопределить этот метод , оставив его тело пустым :

public void viewsource(){

}Хотя переопределение viewsource не сможет полностью скрыть реализацию вашего класса , т.к. его можно легко декомпилировать при помощи средств mxj quickie IDE.

Перегрузка сообщений

В то время как перегрузка конструкторов очень полезна в программировании Java-external’ ов – перегружать обработчики , которые будут реагировать на сообщения из Max,не рекомендуется . Все потому , что прокси -объект mxj использует схему приведения типов , а Max, в свою очередь , использует всего 3 основных типа данных (тогда как в Javaих 9).

Поддержка всех 9 основных типов данных Java во “внутренней работе ” mxj позволяет программировать Java-external’ ы как обычные Java- классы , поэтому портирование существующего Java- кода в Max не столь сложно . Однако в следующих примерах перегрузка методов не принесет ощутимых результатов :

public void doit(int i);public void doit(short s);public void doit(long l);

В среде исполнения Max существует всего один целочисленный тип данных , поэтому если вы отошлете в свой объект сообщение doit 24 , то mxj не сможет определить , какой из трех вышеперечисленных методов ему вызвать .

21

MaxJava API

Page 22: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 22/39

Хотя , следующая схема может оказаться полезной :

public void doit(int i);public void doit(float f);

Вообще , проще определить схему “на все случаи жизни ”:

public void doit(float f);

и позволить прокси -объекту mxj привести целые аргументы к вещественным .

Основываясь на том , что не рекомендуется делать , ниже приведены некоторые правила “хорошего тона ” в программировании Java-external’ ов:

1. Методы подбираются по самому “содержательному ” параметру :

public void doit(Atom[] args);

public void doit(int[] args);public void doit(int x);

Из этих трех методов будет всегда вызываться метод doit(Atom[] args) , независимо от количества аргументов во входящем сообщении .

public void doit(int[] args);public void doit(int x);

Из этих двух методов будет всегда вызываться метод doit(int[] args) , независимо от количества аргументов во входящем сообщении .

2. Методы подбираются по количеству аргументов :

public void doit(int x, int y);public void doit(int x);

Если вы отошлете сообщение doit с двумя или более аргументами – вызовется метод public void doit(int x, int y) . А если с одним или без аргументов - то public void doit(int x);

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

22

MaxJava API

Page 23: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 23/39

3. Взаимодействие с Max.Взаимодействие с Max в Java-external’ ах является двухсторонним . До этого момента рассказывалось о способах передачи данных из среды исполнения Max в ваш external.Этот раздел рассказывает о том , как вывести данные из вашего external’ а в Max.

Метод outlet

Если вы загляните в документацию по MaxObject , вы найдете множество методов , при помощи которых можно отсылать сообщения в среду исполнения Max. Для начала ,давайте напишем простой пример , в котором на каждое сообщение bang ваш объект отсылал 2 сообщения bang в свой первый выход :

public void bang(){outletBang(0);outletBang(0);}

Первым и единственным аргументом метода outletBang является номер выхода , через который вы хотите отослать сообщение bang . Выходы нумеруются слева - направо ,начиная с 0. Поэтому , если вы создали 3 выхода в конструкторе вашего объекта , типа :

declareOutlets(new int[]{ DataTypes.INT, DataTypes.FLOAT,DataTypes.ALL});

самый левый выход типа INT - будет проиндексирован как 0, выход типа FLOAT - будет проиндексирован как 1, а выход типа ALL – как 2. Поэтому , при описании методов вывода вам необходимо указывать номер выхода . Самым удобным способом вывести данные из вашего объекта , является метод outlet(int index, Atom[] args ), где index – это номер выхода . Atom API позволяет создавать объекты типа Atom из любых основных типов Java. Поэтому , если вы захотите вывести список из двух чисел типа int и числа типа

float , через второй выход , в ответ на сообщение bang – реализация может быть следующей :

public void bang(){

int a = 42;int b = 38;float c = 0.005F;outlet(1,new Atom[]{Atom.newAtom(a),Atom.newAtom(b),Atom.newAtom(c)});}

Чтобы немного упростить задачу вывода - в классе MaxObject существует множество перегруженных методов outlet . Эти методы применяются в простых случаях , когда вам необходимо вывести из своего объекта , например одно число типа int или строку типа String . Подобные методы существую для каждого основного типа данных Java.

23

MaxJava API

Page 24: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 24/39

Например , для того чтобы вывести одно число типа int, вам нужно объявить ваш метод так :

public void bang(){outlet(0,42);

}

как альтернативу методу :

public void bang(){outlet(0,new Atom[]{Atom.newAtom(42)});}

или

public void bang(){outlet(0,Atom.newAtom(42));}

Эти два метода синтаксически правильны , но избыточны . То же самое относится ко всем основным типам данных Java, поддерживаемых объектом mxj .

public void outlet(int index, boolean b);public void outlet(int index, char c);public void outlet(int index, short s);public void outlet(int index, String msg);public void outlet(int index, int[] i_array);public void outlet(int index, String[] str_array); и так далее .

На данный момент нет подходящих методов , которые позволяют выводить из объекта сообщения , у которого больше чем один аргумент . Например , если вы хотите вывести что -то вроде [ setdim 64 32 ] вы должны использовать метод :outlet(int idx,String msg,Atom[] args) .

Например таким образом :

public void bang(){outlet(0,"setdim", new Atom[]{ Atom.newAtom(64),Atom.newAtom(32)});}

Также , следует знать , что следующий вызов также синтаксически верен :

public void bang(){outlet(0, new Atom[]{Atom.newAtom("setdim"),Atom.newAtom(64), Atom.newAtom(32)});}

24

MaxJava API

Page 25: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 25/39

Если первый аргумент вашего сообщения является основным числовым типом , ваше сообщение автоматически становится списком (list ), поэтому следующие два вызова также эквивалентны :

public void firstway(){

outlet(0,new Atom[]{Atom.newAtom(11.5), Atom.newAtom(23))}

public void secondway(){outlet(0,"list", new Atom[]{Atom.newAtom(11.5),Atom.newAtom(23)});}

Отправка сообщений через info- выход

На данный момент в MaxJava API не существует методов для отправки сообщений напрямую через info- выход . По умолчанию , info- выход автоматически создается для каждого Java-external’ а. Если вы хотите получить доступ к info- выходу , можно использовать метод getInfoIdx для определения его номера и любой другой метод для вывода информации через него . Например , вы можете сделать так , чтобы в ответ на сообщение dump объект выводил свое внутреннее состояние через info- выход :

public void dump(){//_frequency, _load, и _stepsize объявлены как private-// переменные этого класса

int info_idx = getInfoIdx();outlet(info_idx, new Atom[]{Atom.newAtom("frequency"),Atom.newAtom(_frequency));outlet(info_idx, new Atom[]{Atom.newAtom("load"),Atom.newAtom(_load)});outlet(info_idx, new Atom[]{Atom.newAtom("stepsize"),Atom.newAtom(_stepsize)});}

Использование атрибутов Атрибуты – это еще одно свойство MaxJava API, которое позволяет расширить функциональность ваших объектов . Те , кто знакомы с библиотекой Cycling ’74 Jitter должны быть знакомы с принципами работы атрибутов .

Атрибуты можно рассматривать как элементы вашего external’a. Атрибуты могут быть изменяемыми или быть только для чтения , в зависимости от того , как вы их объявите в вашем классе . Когда что -то объявляется как атрибут – вам необходимы интерфейсы для изменения его значения или состояния . Эти интерфейсы предоставляет прокси -объект mxj . Методы для объявления атрибутов содержатся в классе MaxObject .

25

MaxJava API

Page 26: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 26/39

Преимущества использования атрибутов будут показаны на примере Java-external’a,который выдает определенное количество сообщений bang в ответ на входящее сообщение bang :

import com.cycling74.max.*;public class banger extends MaxObject

{private int repeat; // количество выводимых сообщений bang в public banger() // ответ на каждый входящий bang{repeat = 2; // по умолчанию , 2 исходящих bang на один входящий declareIO(1,1); // один вход , один выход declareAttribute("repeat"); // объявление атрибута ‘repeat’}public void bang(){for(int i = 0; i < repeat; i++)

outletBang(0);}}

Объявление переменной repeat в качестве атрибута , позволяет вашему Java-external’ у по-умолчанию реагировать на сообщения repeat int и getrepeat . Если вы захотите поменять число выводимых сообщений bang на 10 – можно отослать в ваш external сообщение repeat 10 , а соответственно узнать текущее их количество при помощи сообщения

getrepeat . Если в вашем объекте есть info- выход , то через него будет выведено текущее значение repeat , перед которым будет название атрибута (например , repeat 20 ). Если info- выхода не существует (вы вызвали метод createInfoOutlet(false)) , то название и значение атрибута будет выведено в консоль .Код выше , эквивалентен следующему классу (если бы разработчик не применил объявление атрибута ):

public void repeat(int val){repeat = val;}public void getrepeat(){int info_idx = getInfoIdx();if(info_idx == -1)post("repeat "+repeat);elseoutlet(info_idx,repeat);}

Еще одно преимущество использования атрибутов , что разработчик не должен заботиться об инициализации атрибута при помощи конструктора . Значение атрибута можно установить при помощи использования символа @, в создаваемом object box. Чтобы установить начальное значение атрибута repeat пользователь должен впечатать в object

box что -то вроде [mxj banger @repeat 33] и переменная repeat будет инициализирована значением 33. В любое время , пользователь может отослать сообщение repeat int в ваш объект , чтобы изменить количество выводимых сообщений bang .

26

MaxJava API

Page 27: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 27/39

Все основные типы данных Java поддерживаются атрибутами :

boolean, byte, char, short, int, long, float, double,String,boolean[], byte[], char[], short[], int[], long[],float[], double[], String[]

Когда атрибут представляет собой массив , действия по его инициализации будут примерно такими же , за исключением того , что в сообщении по инициализации атрибута будет несколько аргументов , соответствующих элементам массива . Соответственно , при опрашивании состояния подобного атрибута , вы будете получать список значений . Если вы объявите в своем классе переменную frequencies типа int[] в качестве атрибута , то сообщение инициализация атрибута будет выглядеть следующим образом :

frequencies 1 33 4 55 66 77 2 1 66 78 99

Специальная обработка атрибутов

Иногда необходимо изменять способы задавания или получения значений атрибутов . Это может быть полезно , когда вы хотите ограничить диапазон значений атрибута или использовать другое представление атрибута для пользователя , нежели его истинное представление внутри объекта . Для этого существуют специальные функции объявления атрибутов , которые позволяют определить особые методы определителя и/или получателя атрибутов (attribute getter/setter), отличные от тех , что предлагает mxj по умолчанию .

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

import com.cycling74.max.*;public class foo extends MaxObject{private static final double PI_OVER_180 = Math.PI / 180.0;private static final double 180_OVER_PI = 180.0 / Math.PI;private double angle;// величина угла в градусах public foo(){angle = 0.0;declareIO(1,1);declareAttribute("angle","getangle","setangle");

}private void setangle(double angle){angle = angle * PI_OVER_180; // конвертирует из градусов в радианы }private double getangle(){return angle * 180_OVER_PI; // конвертирует из радиан в градусы }}

Также можно представить ситуацию , когда у вас есть переменная , которая не является основным типом данных , поддерживаемых прокси -объектом mxj .

27

MaxJava API

Page 28: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 28/39

Например , java.awt.Point – это класс , который хранит координаты точки x и y , в декартовой плоскости .

import com.cycling74.max.*;import java.awt.Point;public class foo extends MaxObject

{private Point coord;public foo(){coord = new Point(0,0);declareIO(1,1);declareAttribute("coord","getcoord","setcoord");}private void setcoord(int x, int y){coord.x = x;

coord.y = y;}private int[] coord_ret = new int[2];private int[] getcoord(){coord_ret[0] = coord.x;coord_ret[1] = coord.y;return coord_ret;}}

Обратите внимание , что в обоих случаях методы определителя и получателя (getter/setter)объявлены как private . Это потому , что если бы они были объявлены как public , они были бы зарегистрированы как обработчики сообщений , приходящих из Max.Можно задать вопрос , почему нужно объявлять переменную в качестве атрибута , а не воспользоваться обычными средствами mxj для передачи значения переменной ?Одна из причин - это передача значения атрибута через @- сообщения , а другая причина – это будущая интеграция mxj с семейством объектов pattr .

Не обязательно создавать как особый определитель , так и особый получатель (getter/setter)атрибута – вы можете определить только один из них . Чтобы это сделать – просто при вызове метода declareAttribute , впишите null в качестве аргумента для того определителя или получателя (getter/setter), который вы хотите сделать по умолчанию .

declareAttribute("foo",null,"setfoo");// получатель по умолчанию ,// особый определитель

declareAttribute("foo","getfoo",null);// особый получатель ,// определитель по умолчанию

Все методы определения атрибутов (включая “только чтение ”) перечислены в html-документации класса MaxObject .

28

MaxJava API

Page 29: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 29/39

4. Многопоточное программирование .

Многопоточная модель Max

По умолчанию , вся обработка событий в Max производится в главном потоке (main thread)

среды исполнения . События порождаются MIDI- командами , щелчками мыши , объектами тайминга (типа metro ), а также другими событиями , которые требуют некоторого времени на свою обработку . Время , которое требуется на обработку события , зависит от того , что требуется вычислить системе для успешной обработки события . Например , если кто -то отсылает в ваш объект сообщение bang и вы просто выводите какое -то число , используя несложные вычисления – время , которое затрачивается на обработку события , очень мало .С другой стороны , если кто -то отсылает в ваш объект сообщение bang , а в ответ ваш external производит сложные погодные вычисления - это уже может занять некоторое время . Во время этого процесса расчета погоды , среда Max не сможет обрабатывать другие события , так как главный (и единственный ) поток - занят . Это может привести к тому , что пользовательский интерфейс перестанет отвечать на запросы , или Max вообще

“зависнет ” на все время вычисления . Это потому , что все события (помимо ваших погодных вычислений ) обрабатываются в одном потоке : объекты тайминга ,пользовательский интерфейс , щелчки мышью , прорисовка окон и пр. Поэтому , если у вас есть процесс , который требует некоторого времени на вычисление или обработку – все вышеперечисленные сервисы будут блокированы , пока обработка вашего процесса не закончится .

Когда пользователь включает режим Overdrive (Options->Overdrive), в среде исполнения Max создается еще один поток , который предназначен для обработки данных . Это позволяет включить планировку событий для обработки данных , в то время как Max будет продолжать откликаться на команды . Этот поток называется планировщиком (scheduler)или высокоприоритетным потоком , так как планировка событий в этом потоке , имеет более высокий приоритет , чем очередь обработки основного потока .Соответственно , основной поток среды исполнения Max называется низкоприоритетным потоком , потому что обработка событий этим потоком работает в пониженном приоритете (относительно планировщика ).

Так как событиям в планировщике имеют высокий приоритет , это позволяет достигнуть ускоренной реакции на события , так как планировщик вызывается гораздо чаще и не загружен задачами пользовательского интерфейса . Очень важно понять , что планировщик (как и основной поток ) одновременно может обрабатывать только одно задание , поэтому если оно требует некоторого времени на выполнение – все остальные задания будут отложены . Правильно написанный Java-external не будет использовать планировщик для функций , выполнения которых может занимать продолжительное время . Подобные “тяжелые ” функции должны выполняться в отдельном Java- потоке или в низкоприоритетном потоке Max, используя методы класса MaxSystem . В дополнение ,можно применить объект MaxQelem , чтобы убедится в том , что в очереди выполнения заданий не будет находиться несколько одинаковых функций в одно и то же время .

Вывод информации в высоком приоритете

Если в вашем Java- классе есть метод , который реагирует на входящее сообщение выводом

другого сообщения , то сообщение на выходе объекта будет находиться в том же потоке ,что и сообщение , входящее в объект .

29

MaxJava API

Page 30: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 30/39

Например , сообщения bang из объекта metro выполняются в планировщике ,соответственно ваш метод bang , реагирующий на сообщения metro тоже будет выполняться в планировщике . События , вызванные пользовательским интерфейсом , типа щелчков мышью по объектам message box, будут выполняться в низкоприоритетном потоке .

Но возможно переместить выполнение событий из других потоков в планировщик . Если по причинам тайминга вам требуется выполнение сообщения в высокоприоритетном потоке – вы можете использовать метод outletHigh , который переместит выполнение сообщения в планировщик и позволит выполнить его как можно быстрее . Обратите внимание , что поток планировщика создается только тогда , когда пользователь включил режим Overdrive. Если планировщик не создан , тогда использование метода outletHigh примерно соответствует использованию метода outlet .

Использование объектов MaxClock и Callback

Если у вас есть задачи , чувствительные ко времени , например функция , выполняемая через определенные промежутки времени , MaxClock API предоставляет механизмы для решения подобных задач . Чтобы осуществить подобное , вам необходимо поместить вашу функцию в реализацию интерфейса com.cycling74.max.Executable . Вот простой пример реализации метронома , который после получения сообщения start выводит каждые 500 мс сообщения bang , а после получения сообщения stop прекращает выводить сообщения bang .

importcom.cycling74.max.*;public class simplemetro extends MaxObject{

MaxClock c;public simplemetro(){declareIO(1,1); // один вход , один выход c = new MaxClock(new Callback(this, "dobang"));// создается экземпляр MaxClock, который будет // вызывать функцию dobang всякий раз , когда он " тикает "}private void dobang(){outletBang(0); // вывод bang через первый выход

c.delay(500.0);// устанавливает часы на исполнение через 500 мс }public void start(){c.delay(0.0); // вынуждает часы выполнить функцию немедленно }public void stop(){c.unset(); // остановить часы }

30

MaxJava API

Page 31: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 31/39

// метод notifyDeleted вызывается средой Max,// когда пользователь удаляет ваш объект из патча // или закрывает патч , частью которого является ваш класс .

public void notifyDeleted(){

c.release(); // освобождает ресурсы //Max, связанные с объектом MaxClock.// Это очень важно . Если этого не сделать -// ресурсы будет невозможно вернуть обратно .}}

В этом примере присутствует объект Callback , который реализует интерфейс Executable и определяет функцию , которая должна вызываться , когда он “тикает ”.

Первый аргумент конструктора объекта Callback - это экземпляр объекта , в котором содержится функция , которую нужно выполнять (в нашем случае – это указатель this ,т.к. функция реализована в том же самом классе , что и Callback ). Если вы не хотите использовать Callback , следующий код полностью эквивалентен :

public simplemetro(){declareIO(1,1); //one inlet, one outletc = new MaxClock(new Executable(){public void execute(){outletBang(0);c.delay(500.0);}});}

Использование Callback повышает читабельность вашего кода . Вы можете использовать экземпляр объекта Callback в любой ситуации , где необходимо создание Executable , потому что сам объект Callback является реализацией интерфейса Executable . Есть еще ситуации , где использование Callback очень полезно – случаи ,когда вам необходимо передать аргументы в функцию , которую вы хотите выполнить при

вызове Callback .

Также полезно знать , что MaxClock предоставляет конструктор , в котором вы можете напрямую указывать функцию , которую нужно выполнить . Следующий конструктор MaxClock является эквивалентным двум предыдущим примерам :

MaxClock c;public simplemetro(){declareIO(1,1); // один вход , один выход // создать экземпляр MaxClock который будет вызывать // функцию dobang всякий раз когда он " тикает "c = new MaxClock(this, "dobang");}

31

MaxJava API

Page 32: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 32/39

Выполнение “тяжелых ” функций в основном потоке

Объект MaxQelem предоставляет механизм , при помощи которого вы можете перенести выполнение события в главный поток . Это может быть полезным при выполнении “тяжелых ” функций , которые вызваны из планировщика . Вместо того , чтобы задерживать работу планировщика (а соответственно и выполнение остальных задач , чувствительных к таймингу ), можно перенести исполнение таких функций в главный поток и задерживать задачи пользовательского интерфейса и других событий не столь чувствительных к точному времени выполнения . Можно также использовать объект MaxQelem , для гарантии того , что только один экземпляр события будет находиться в главном потоке в текущий момент времени .

Например , представьте себе , что в ответ на входящий параметр Java-external будет заполнять массив , состоящий из нескольких миллионов элементов . Соответственно ,нужно выполнять такой процесс в главном потоке :

import com.cycling74.max.*;public class qelemtest extends MaxObject{private MaxQelem q;private double[] darray;private double someParameter;public qelemtest(){declareIO(1,1);q = new MaxQelem(new Callback(this,"fillarray"));}private void fillarray(){double thisParameter = someParameter;darray = new double[10000000];// массив из 10 миллионов элементов for(int i = 0; i < darray.length;i++){darray[i] = Math.sin(System.currentTimeMillis()+ thisParameter);}}public void inlet(double d){

someParameter = d;q.set();// переносит выполнение fillarray в низкоприоритетный главный // поток . Функция fillarray была определена как // qelem- функция , когда в конструкторе был создан объект // MaxQelem q.}public void notifyDeleted(){q.release();// освобождает ресурсы

//Max, связанные с объектом MaxQelem.

// Это очень важно .}}

32

MaxJava API

Page 33: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 33/39

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

Использование Java- потоков для выполнения “тяжелых ” функций

В external’ ах можно использовать и встроенные многопоточные возможности Java, чтобы разгрузить потоки среды исполнения Max и перенести выполнение “тяжелых ” функций в JVM. Поэтому , для вашего процесса можно создать отдельный Java- поток , вместо использования планировщика или главного потока .

Вот еще один простой пример , в котором по сообщению bang большой массив заполняется значениями , а во время заполнения , через info- выход отсылается bang .Обратите внимание , что поведение Java- потоков немного отличается от “изолированной ” работы MaxQelem , однако это позволяет продолжить обработку событий в среде Maxпосле получения объектом сообщения bang , в то время как массив заполняется в отдельном потоке .

import com.cycling74.max.*;public class threadtest extends MaxObject{private double[] darray;public threadtest(){declareIO(1,1);darray = new double[1000000];}public void bang(){// создание нового потока для заполнения массива Thread t = new Thread(){public void run(){for(int i = 0; i < darray.length;i++){darray[i] = Math.sin(System.currentTimeMillis());}outletBang(getInfoIdx());// вывести bang через

// info- выход когда массив заполняется

}};t.start(); // запустить поток }}

33

MaxJava API

Page 34: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 34/39

Нет ничего плохого в использовании Java- потоков внутри вашего external’ а, но если в этих потоках будут осуществляться вызовы обратно в среду Max, то эти вызовы будут автоматически обрабатываться в низком приоритете главного потока , при использовании метода outlet , и в высоком приоритете планировщика при использовании метода outletHigh . Это все потому , что внутри среды исполнения Max известны только два потока : планировщик и главный поток . Дополнительный Java- поток неизвестен внутри

Max. Поэтому , если ваши Java- потоки чувствительны к таймингу , вам необходимо использовать методы outletHigh , чтобы дальнейшая обработка осуществлялась в планировщике .

34

MaxJava API

Page 35: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 35/39

5. Примеры программирования .

Игра “Пятнашки ”

Данный Java-external через свой левый выход подключается к объекту jit.cellblock ,

который должен иметь четыре столбца и четыре строки (это будет игровое поле ).По сообщению rand объект случайным образом расставляются фишки на игровом поле и начинает игру . Когда игра будет успешно завершена , на экран выведется сообщение и игра опять будет начата сначала . Для управления игрой используются сообщения : up ,down , right и left . Для отслеживания клавиатуры можно применить объект keyup .Для “ускорения ” процесса игры существует сообщение cheat , которое расставит фишки в выигрышной ситуации (достаточно одного хода , чтобы успешно завершить игру ). Через правый выход Java-external’ а выводятся данные о количестве сделанных ходов с начала новой партии . Данный класс предназначен для версии MaxMSP не ниже 4.5.3.

import com.cycling74.max.*;

import java.util.Random;// импорт класса Random для нужд рандомизации поля

public class fifth_game extends MaxObject //Programmed by I.Tikhonov {private Random rnd = new Random(); // создание объекта типа Random private int counter; // счетчик ходов private int zerox; // номер строки , содержащей пустую фишку private int zeroy; // номер столбца , содержащего пустую фишку private int[][] matrix=new int[4][4]; // массив игрового поля private final int[][] refer={{1,5,9,13},{2,6,10,14},{3,7,11,15},{4,8,12,0}};// выигрышный массив для сравнения с полем ( перечисление столбцов )private Atom[] out=new Atom[3]; // массив Atom[] для вывода через левый выход

public fifth_game (){ // конструктор объекта declareInlets(new int[]{DataTypes.ALL}); // один вход declareOutlets(new int[]{DataTypes.ALL, DataTypes.ALL}); // два выхода createInfoOutlet(false); // не создавать info- выхода setInletAssist(new String[] {"input commands"}); // подсказка для входа setOutletAssist(new String[] {"connect to jit.cellblock", "move number"});// подсказки для выходов }

public void rand(){ // случайно расставляем фишки на поле

counter=0; // обнуляем счетчик ходов int init=0; // этими значениями заполним поле for(int a=0; a<matrix.length; a++) // цикл через все ячейки поля for(int b=0; b<matrix.length; b++){matrix[a][b]=init; // заполняем по порядку все ячейки значениями от 0 до 15init ++; // увеличиваем на 1}for(int i = 0;i<100;i++){ // цикл от 0 до 100 int a = rnd.nextInt(4); // случайно получаем числа от 0 до 3… int b = rnd.nextInt(4); //… при помощи метода nextInt, который генерирует … int a2 = rnd.nextInt(4); //… случайные целые числа от нуля ( включая ) до …int b2 = rnd.nextInt(4);//… аргумента вызова метода ( не включая ) int c = matrix[a][b]; // временно сохраняем содержимое 1 й

// случайно выбранной ячейки поля matrix[a][b] = matrix[a2][b2]; // сохраняем содержимое 2 й случайно выбранной

// ячейки в 1 ю случайно выбранную ячейку matrix[a2][b2] = c; // сохраняем значение 1 й ячейки во 2 ю случайную ячейку }this.print(); // вызов метода print ( его описание – ниже ) outlet(1, counter); // вывод счетчика ходов через правый выход }

35

MaxJava API

Page 36: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 36/39

private void print(){ // метод print заполняет объект jit.cellblock значениями

outlet(0,"clear","all"); // очистить jit.cellblock for(int i=0; i<matrix.length; i++) // цикл через все ячейки поля for(int j=0; j<matrix.length; j++){if (matrix[i][j]==0) continue; // если ячейка равна нулю – продолжить следующую

// итерацию , не заполняя эту ячейку jit.cellblockout[0]=out[0].newAtom(i); // если содержимое не равно нулю

// заполнить 0 й элемент массива out номером столбца out[1]=out[1].newAtom(j); // заполнить 1 й элемент массива out номером строки out[2]=out[2].newAtom(matrix[i][j]); // заполнить 2 й элемент массива out

// значением ячейки outlet(0, "set", out); // вывести массив с командой set, которая установит

// значение ячейки в объекте jit.cellblockoutlet(1, counter);// вывод счетчика ходов через правый выход }// нахождение нулевой ячейки в матрице и занесение ее “ координат ” в переменные //zerox и zeroy for(int d=0; d<matrix.length; d++)

for(int e=0; e<matrix.length; e++){if(matrix[d][e]==0) {zerox=d;zeroy=e;}}

}

private void refer(){ // сравнение матрицы с “ эталонной ” для выяснения выигрыша

int error=0; // переменная для подсчета несоответствий с эталоном for(int i=0; i<matrix.length; i++) // цикл через матрицу for(int j=0; j<matrix.length; j++){if(matrix[i][j]!=refer[i][j]) error++; // если значение в матрице не равно // соответствующему значению эталона , то увеличение числа несоответствий на // единицу }if (error==0) { // если несоответствий нет …ouch("Congratulations, You Win!"); //… то вывод поздравительного сообщения this.rand(); // новая игра ! }}

public void up(){ // метод для поднятия фишки вверх

if(zeroy!=3){ // если “ пустая ” фишка не находится в самом низу … matrix[zerox][zeroy]=matrix[zerox][zeroy+1]; //… поменять ее местами с нижней matrix[zerox][zeroy+1]=0; // заполнение ячейки снизу нулем zeroy++; // увеличение на единицу вертикальной “ координаты ” нулевой фишки counter++; // увеличение счетчика ходов this.print(); // заполнение новыми данными объекта jit.cellblock this.refer(); // проверка окончания игры }}public void down(){ // метод для опускания фишки вниз

if(zeroy!=0){ // если “ пустая ” фишка не находится в самом верху … matrix[zerox][zeroy]=matrix[zerox][zeroy-1]; //… поменять ее местами с верхней matrix[zerox][zeroy-1]=0; // заполнение ячейки сверху нулем zeroy--; // уменьшение на единицу вертикальной “ координаты ” нулевой фишки counter++; // увеличение счетчика ходов this.print(); // заполнение новыми данными объекта jit.cellblockthis.refer(); // проверка окончания игры }}

36

MaxJava API

Page 37: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 37/39

public void right(){ // метод для смещения фишки вправо

if(zerox!=0){ // если нужная фишка не является крайней левой … matrix[zerox][zeroy]=matrix[zerox-1][zeroy]; //… поменять ее местами с левой matrix[zerox-1][zeroy]=0; // заполнение ячейки слева нулем zerox--; // уменьшение на единицу горизонтальной “ координаты ” нулевой фишки counter++; // увеличение счетчика ходов this.print(); // заполнение новыми данными объекта jit.cellblockthis.refer(); // проверка окончания игры }}

public void left(){ // метод для смещения фишки влево

if(zerox!=3){ // если нужная фишка не является крайней правой … matrix[zerox][zeroy]=matrix[zerox+1][zeroy]; //… поменять ее местами с правой matrix[zerox+1][zeroy]=0; // заполнение ячейки справа нулем zerox++; // увеличение на единицу горизонтальной “ координаты ” нулевой фишки counter++; // увеличение счетчика ходов this.print(); // заполнение новыми данными объекта jit.cellblockthis.refer(); // проверка окончания игры }}

public void cheat(){ // схитрить …

int[][] cheater = {{1,5,9,13},{2,6,10,14},{3,7,11,0},{4,8,12,15}};// создание массива для последнего “ победного ” хода ( перечисление столбцов )matrix=cheater; // приравнивание игрового поля к созданному массиву this.print(); // заполнение новыми данными объекта jit.cellblock }}

37

MaxJava API

Page 38: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 38/39

Объект pac

Java- объект pac будет немного походить на стандартные объекты Max pak и pack .Этот объект (как и его “ родственники ”) будет собирать входящие сообщения в списки и отсылать их через свой выход . Единственное отличие от pak и pack (помимо упрощенной работы ) будет состоять в том , что pac будет отсылать собранный список только тогда ,

когда во все его входы поступят сообщения .

import com.cycling74.max.*;

public class pac extends MaxObject //Programmed by I.Tikhonov {private Atom[] outlet; // массив типа Atom, для вывода информации из объекта private boolean[] reference; // подтверждение заполнения массива outlet private boolean flag = false; // флаг , предупреждающий , что массив outlet может

// содержать нулевые указатели

public pac(int arg) // конструктор с одним аргументом типа int, который будет // означать количество входов в объекте

{int[] inlets_type=new int[arg]; // массив для описания кол - ва входов объекта for(int i=0; i<arg; i++) inlets_type[i]=DataTypes.ALL; // заполнение массива

// типами входов для объекта String[] inlets_assist=new String [arg]; // создание массива типа String для

// подсказок к входам объекта for(int j=0; j<arg; j++) inlets_assist[j]="inlet "+j; // заполнение массива

// подсказками + номер входа declareInlets(inlets_type); // описание типов входов заполненным массивом declareOutlets(new int[]{DataTypes.ALL}); // один выход setInletAssist(inlets_assist); // описание подсказок для входов заполненным

// массивом setOutletAssist(new String[]{"combined list"}); // подсказка для выхода

createInfoOutlet(false); // без info- выхода outlet=new Atom[arg]; // создание массива для вывода информации , кол - во

// элементов соответствует кол - ву входов reference=new boolean[arg]; // создание массива подтверждения , кол - во

// элементов соответствует кол - ву входов this.referfill(); // вызов функции referfill ( см . далее ) для заполнения массива // подтверждения значениями false, т . к . ни один из элементов массива outlet// на данный момент не определен . }

public pac() // конструктор без аргументов . если пользователь не укажет // кол - во входов – объект не будет создан , а в консоль выведется ошибка .{bail("wrong args"); // вывод ошибки в консоль }

private void referfill() // заполнение массива подтверждения значениями false,// т . к . ни один из элементов массива outlet на данный момент не определен .{for(int i=0; i<reference.length;i++) reference[i]=false ;// цикл через весь

// массив и заполнение значениями false}

38

MaxJava API

Page 39: MaxJava API

8/4/2019 MaxJava API

http://slidepdf.com/reader/full/maxjava-api 39/39

private void print() // метод для вывода информации из объекта {int error=0; // переменная для подсчета ошибок for(int i=0; i<reference.length; i++) // цикл через весь массив referenceif(reference[i]==false) error++; // если хотя бы один элемент массива reference // является false ( т . е . какой - то элемент массива outlet еще не определен )// кол - во ошибок увеличивается на 1if(error==0) {outlet(0,outlet); this.referfill();flag=true;} // если ошибок нет //( то есть все элементы массива outlet заполнены ), то выводится массив outlet}

public void inlet(int i) // если в объект поступает целое число {int inlet=getInlet(); // получение номера входа в который пришло число outlet[inlet]=outlet[inlet].newAtom(i); // занесение входящего числа в // массив outlet. номер элемента , в который будет занесено число , будет // равняться номеру входа , в который пришло сообщение reference[inlet]=true; // подтверждение , что этот элемент массива outlet

// заполнен this.print(); // попытка вывода данных }

public void inlet(float f) // если в объект поступает вещественное число {int inlet=getInlet(); // получение номера входа в который пришло число outlet[inlet]=outlet[inlet].newAtom(f); // занесение входящего числа в массив //outlet. номер элемента , в который будет занесено число , будет равняться // номеру входа , в который пришло сообщение reference[inlet]=true; // подтверждение , что этот элемент массива outlet

// заполнен this.print(); // попытка вывода данных }

public void anything(String msg, Atom[] args) // если в объект поступает символ {int inlet=getInlet(); // получение номера входа в который пришел символ outlet[inlet]=outlet[inlet].newAtom(msg); // занесение входящего символа в // массив outlet. номер элемента , в который будет занесен символ , будет // равняться номеру входа , в который пришло сообщение

reference[inlet]=true; // подтверждение , что этот элемент массива outlet// заполнен

this.print(); // попытка вывода данных }public void bang() // обработчик сообщения bang, при котором будет произведена

// попытка досрочного вывода списка ( т . е . массива outlet). это будет возможно // только тогда , когда массив outlet полностью заполнялся хотя бы один раз .// для этого служит переменная flag, которая изменяет свое значение на true,// когда массив outlet успешно выводится {if(flag==true) // если flag равен true( т . е . массив outlet уже выводился )-… try{outlet(0, outlet);} //… попробовать вывести массив outlet. при этом может //( но не должно ) “ выброситься ” исключение NullPointerException ( т . е . массив //outlet не полностью заполнен и содержит нулевые указатели ),… catch(NullPointerException e) //… которое нужно обработать … {post("error");} //… и вывести в консоль Max сообщение об ошибке }}

MaxJava API