Max及びMax for Live(以下m4l)は、オブジェクトをパッチでつなぐビジュアルプログラミング言語だが、テキスト記述型のプログラミング言語を使ってオリジナルのオブジェクトを作成する場合がある。その際、Cでエクスターナルオブジェクトを作るか、jsオブジェクトを利用してjavascriptを書く、というのが一般的であるように思うが、どうもmxjオブジェクトというのがあって、Javaも使えるらしい。もっともそれについて検索して出てくる情報は古いものばかりな気もするが。自分の環境(Windows10, Ableton Live 11 Suite)で使えるかどうか試してみた。
サンプルのクラスファイルを使ってみる
基本的に、javaのコードを書いて、それをjavacでクラスファイルにコンパイルしたものが使えるかどうか試すということをしようと思うのだけれど、その前に、すでにmxjオブジェクトのためのjavaクラスファイルが用意されていて、これを利用することができる。これを試してみよう。
上掲の画像のMaxコンソールに示された’MXJClassloader CLASSPATH’のフォルダ内(C:\ProgramData\Ableton\Live 11 Suite\Resources\Max\resources\packages\max-mxj\java-classes\classes)にあるこれらのファイルは、すでにJavaランタイムがインストールされていれば、そのまま使うことができる。もしJavaランタイムが入っていなければ、コンソールに次のようなエラーが出て、オブジェクトが使えない。その場合は、JavaのサイトからJavaランタイムをダウンロードしてインストールすればすぐに使えるようになる。
オブジェクト名’mxj’につづいて記述するargumentは、ファイル名。クラスパス内にあるファイルなら拡張子を除いたファイル名のみを記述すればよいが、例えばclasses/net/tcp/にあるrecv.classを使いたいのであれば、オブジェクトには’mxj net.tcp.recv’と記述する必要がある。またこれらの利用可能なjavaクラスファイルの中のいくつかは、Help用のパッチが用意されていて、オブジェトを右クリックしてこれを参照することができる。
javaクラスファイルのサンプルをいくつか見ていて面白いと思ったのは、’Morse Code Generator’。その名の通りメッセージで送ったテキストからモールス信号を生成する。今どのアルファベットを打っているかもリアルタイムに表示される。9/25の即興演奏ブログの投稿にはこれを用いた。
JDKを試してみる
javaのコードを書いて、クラスファイルを生成するには、jdk(Java Development Kit)をインストールする必要がある。最新版ならJavaのDownloadのページからすぐにダウンロードできる。OSはWindowsを選び、’x64 MSI Installer’を選んでインストールすれば良い。筆者の環境では以前にインストールしていたVer.16が入っていた。
jdkがインストールされているならば次に、mxjオブジェクトのためのjavaのコードを書くために、max.jarをクラスパスに通しておく必要がある。これについては先のMaxコンソールの画面に’MXJ System CLASSPATH’として示されいた。これらのパスを始めに通しておく必要がある。コマンドプロンプト(Win + rで開いたウィンドウにcmdと入力)上で
set CLASSPATH=C:\ProgramData\Ableton\Live 11 Suite\Resources\Max\resources\packages\max-mxj\java-classes\lib\jitter.jar;C:\ProgramData\Ableton\Live 11 Suite\Resources\Max\resources\packages\max-mxj\java-classes\lib\jode-1.1.2-pre-embedded.jar;C:\ProgramData\Ableton\Live 11 Suite\Resources\Max\resources\packages\max-mxj\java-classes\lib\max.jar
全部通さなくても、さしあたってはmax.jarさえ通しておけば特に困らないかもしれない。
set CLASSPATH=C:\ProgramData\Ableton\Live 11 Suite\Resources\Max\resources\packages\max-mxj\java-classes\lib\max.jar
カレントディレクトリを’MXJClassloader CLASSPATH’に変える。
cd C:\ProgramData\Ableton\Live 11 Suite\Resources\Max\resources\packages\max-mxj\java-classes\classes
javacが上手く通るか、試しにサンプルプログラムの中のfibonacci.javaをコンパイルしてみた。
javac -encoding utf-8 fibonacci.java
ちなみに、あらかじめset CLASSPATHでmax.jarなどのパスを通さずに、javacでのコンパイル時に-classpath(または-cp)オプションでパスを通してもいいかもしれない。その場合、カレントディレクトリがclassesである状態で、次のように打ち込めばいい。
javac -cp ../lib/max.jar -encoding utf-8 fibonacci.java
上手くいったら、ableton liveでm4lを立ち上げてオブジェクト’mxj fibonacci’を配置してみる。すると、オブジェクトは正しく認識されず、コンソールに次のようなエラーメッセージが表示された。
java.lang.UnsupportedClassVersionError: fibonacci has been compiled by a more recent version of the Java Runtime (class file version 60.0), this version of the Java Runtime only recognizes class file
versions up to 52.0
クラスファイルヴァージョンというものがあるらしい(参考サイト: classバージョン)。jdk16の場合それは60.0だが、それでは新しすぎるので52.0までにしてくれというのである。
クラスファイルヴァージョンが52.0というのは、jdkでいうとver.8(1.8)ということのようなので、jdk8をインストールしてそれを使ってコンパイルし、クラスファイルを生成する必要がある。
oracle社のページから古いバージョンのjdkをダウンロードしようとすると、アカウントの作成を求められる。それは手間なので、OpenJDKからVersion8のJDKで.zipのものをダウンロードして解凍したものの中身を適当なフォルダ(C:\Program Files\Java\jdk-1.8.0など)に配置。
jdkの複数バージョンが存在することになるので、その切り替え等、以下のサイトなどを参考に管理することにした。
https://qiita.com/ifrit_anplosia/items/e918b5813a3d29a0e8fc
https://www.javadrive.jp/start/install/index4.html
環境変数の設定の画面に行くのはWindows10なら、Win + Pause/Break からシステムの詳細設定をクリックしていくのが一番早い気がする。タスクバーの検索窓にそのまま’環境変数’と入力してもよい。
環境変数のJAVA_HOMEにjdk8のパス(C:\Program Files\Java\jdk-1.8.0\binなど)が通っている状態で、また、コマンドプロンプト上でjavac -versionと入力すれば、javac 1.8.0_*と表示される状態で再び、上掲のプロセスを繰り返す。max.jar等をset CLASSPATHで通し、カレントディレクトリを’MXJClassloader CLASSPATH’に変え、javac -encoding utf-8 fibonacci.javaとしてコンパイルしてみる。
コンパイルが通ったら、再びm4lのウィンドウ上にオブジェクト’mxj fibonacci’を配置してみると、エラーもなく正常に認識され使用可能な状態となる。
以上をまとめると、jdk8をダウンロードして任意のディレクトリに配置し、そのパスを環境変数に通して、コマンドプロンプトを立ち上げてmax.jar等の外部モジュールのクラスパスを通し、カレントディレクトリを’MXJClassloader CLASSPATH’にする。
もっとも、mxjオブジェクトにメッセージ’viewsource’を送ると、簡易的なエディタが立ち上がる。そのエディタを用いれば、コマンドプロンプトを立ち上げて、javacコマンドでjavaファイルをコンパイルする作業が必要なくなる。その際、MXJ Compile Windowの’Compiler Command:’の欄にjdk8(1.8)のjavac.exe(binフォルダの直下にある)のパスを設定する。
チュートリアルを試してみる
ようやく環境が整ったので、チュートリアルを試してみることができる。
mxjのチュートリアルは、C:\ProgramData\Ableton\Live 11 Suite\Resources\Max\resources\packages\max-mxj\java-doc\tutorial\htmlにある。また、java-docフォルダ内には、mxjのPDFマニュアルやAPIリファレンスなど一式そろっている。
java-docフォルダ内にあるこのチュートリアルは英文だが、これを日本語訳したサイトもあって参考になる。
以下は、チュートリアル05のソースコードを改良して、組み込みのPlusオブジェクトのすべての機能の実装を試みたもの。チュートリアル05に掲載されているのは、組み込みのPlusオブジェクトの基本的な機能ををmxjで再現したもので、そこからさらに未実装のマイナーな機能を付加した。classesフォルダ内にuserフォルダを設けて、そこにPlus2.javaを置いた。よって、(カレントディレクトリがC:\ProgramData\Ableton\Live 11 Suite\Resources\Max\resources\packages\max-mxj\java-classes\classesの状態で)javac -encoding utf-8 user/Plus2.javaでコンパイルし、オブジェクトは、’mxj user.Plus2’となる。
カレントディレクトリがclasses/userにある状態で、javac -encoding utf-8 Plus2.javaとしてコンパイルしても問題ないが、いずれにしろclassesディレクトリを基準とし、ソースコードに’package user;’の一文は必要で、オブジェクトも’mxj user.Plus2’とするのは変わらない。
package user;
import com.cycling74.max.*;
public class Plus2 extends MaxObject {
private Atom addend = Atom.newAtom(0);
private Atom result = Atom.newAtom(0);
public Plus2(Atom[] args) {
declareIO(2,1);
if (args.length > 0) {
if (args[0].isInt() || args[0].isFloat()) {
addend = args[0];
}
}
}
public void bang() {
if (result.isInt()) {
outlet(0, result.getInt());
} else {
outlet(0, result.getFloat());
}
}
public void list(Atom[] nums) {
if (nums.length >= 2) {
if ((nums[0].isInt() || nums[0].isFloat()) && (nums[1].isInt() || nums[1].isFloat())) {
if (nums[0].isInt() && nums[1].isInt()) {
result = Atom.newAtom(nums[0].getInt() + nums[1].getInt());
setAddendInt(nums[1].getInt());
} else if (nums[0].isInt() && nums[1].isFloat()) {
result = Atom.newAtom((float)nums[0].getInt() + nums[1].getFloat());
setAddendFloat(nums[1].getFloat());
} else if (nums[0].isFloat() && nums[1].isInt()) {
result = Atom.newAtom(nums[0].getFloat() + (float)nums[1].getInt());
setAddendInt(nums[1].getInt());
} else {
result = Atom.newAtom(nums[0].getFloat() + nums[1].getFloat());
setAddendFloat(nums[1].getFloat());
}
bang();
}
}
}
public void inlet(int i) {
if (getInlet() == 0) {
if (addend.isInt()) {
result = Atom.newAtom(i + addend.getInt());
} else {
result = Atom.newAtom((float)i + addend.getFloat());
}
bang();
} else {
setAddendInt(i);
}
}
public void inlet(float f) {
if (getInlet() == 0) {
if (addend.isInt()) {
result = Atom.newAtom(f + (float)addend.getInt());
} else {
result = Atom.newAtom(f + addend.getFloat());
}
bang();
} else {
setAddendFloat(f);
}
}
public void setAddendInt(int i) {
if (addend.isInt()) {
addend = Atom.newAtom(i);
} else {
addend = Atom.newAtom((int)i);
}
}
public void setAddendFloat(float f) {
if(addend.isInt()) {
addend = Atom.newAtom((float)f);
} else {
addend = Atom.newAtom(f);
}
}
}
mxjのAPIによって提供されるAtomクラスは、整数も浮動小数点も文字列もリスト型も扱えるabstractなクラス。これはヴィジュアルプログラミング言語であるMaxのオブジェクトのためには必要なものに思える。これに関してはJavaScriptのような動的型付け言語が有用ということになるだろうか。
Javaの使い道、そしてJavaScriptとは
以上見てきたように、m4lでJavaは使えるようだ。m4lでJavaが使えるということは、Ableton LiveでJavaが使えるということでもある。そこにメリットはあるかもしれない。しかしながら、Max及びm4lでしばしば使用されるテキストベースのプログラミング言語は、JavaScriptのようである。M4lでJavaを使う用途はどのようなものが考えられるだろうか。
サンプルのクラスファイルには通信関連のものは、一通りそろっているようである。もっともUDPについてはMaxに組み込みのオブジェクトがあるし、無償のPackでConnection Kitもある。音楽用途の通信プロトコルとして使われるOSCを使うのに、今あえてJavaを使う機会はあまりないのかもしれない。TouchDesignerとAbleton LiveをOSCを介して連携させることができるようだけれど、これにもTDAbletonというツールが用意されている。TCPを使うのが望ましい場合とか、あるいは音楽以外の通信用途で、Max/MSPを使う場合にJavaは有効となるかもしれない。
様々なリスト処理のクラスファイル群が、listフォルダ内にある。これらをそのまま使うなどしてリスト処理用途にjavaを活用するのも良いかもしれない。
あとは、利用したいライブラリがあるとか、オブジェクト指向プログラミングの手法を活用したいといったことがJava特有の使い道としてあるだろうか。
最後に、JavaScriptについても触れておこう。MaxでJavaScriptが活用される理由は、JavaScriptという言語がどういうものであるかというところにあると考えられる。
これについてMaxのDocumentationのBasic Javascript programming for the js and jsui objectsのページからOverview of js Object Extensions to Javascriptの項の冒頭を引用してみよう。
Javascript is a language designed to control the software in which it is embedded. Put another way, it is a language designed to script an application. Javascript code always executes within a script context that can add new properties and functions – this is, for example, how Netscape added browser-specific features familiar to Web developers.
https://docs.cycling74.com/max8/vignettes/jsintro
以下は、google翻訳による和訳。
Javascript は、それが組み込まれているソフトウェアを制御するために設計された言語です。別の言い方をすれば、アプリケーションをスクリプト化するために設計された言語です。 JavaScript コードは常に、新しいプロパティと関数を追加できるスクリプト コンテキスト内で実行されます。これは、たとえば、Netscape が Web 開発者になじみのあるブラウザ固有の機能を追加した方法です。
https://docs.cycling74.com/max8/vignettes/jsintro
google翻訳は全体的にはこなれていない訳文だが、太字部分、scriptを’スクリプト化する’と訳しているのはうまい訳だと思う。scriptは台本を書くなどの訳語が当てられるが、to scriptとto writeは違うので、’書く’という語を使わずに訳した方が意味が通りやすいということはあると思う。