すこしふしぎ.

VR/HI系院生による技術ブログ.まったりいきましょ.(友人ズとブログリレー中.さぼったら焼肉おごらなきゃいけない)

【Max/MSP】jsオブジェクトでプログラミング【javascript】

こんばんは.1000chです. 昨日の今日でまた更新です. javascriptネタ...と見せかけてMax/MSPネタです.

Maxってサウンド処理には便利なんですが,数値計算をプログラム風に行ったり,if文でのルーティングとかやろうとすると以外と面倒なところあるんですよね. そこで「もっとスクリプトベースでできないのかなー」と思っていたところ,チュートリアルjavascriptって節があるじゃないですか. ということで,Max/MSP中でjsスクリプトを利用する方法をメモっておこうと思います.

javascript in Max/MSP の参考資料

チュートリアルパッチを見ると何となくの使い方がわかります. 日本語訳してくださっているのがこちら.

Max チュートリアル

Max使うときはいつもお世話になってます.

ただ.このチュートリアルjavascript自身の使い方も多く,もう少し詳しい説明欲しいなぁと思ったりもします. そこで参考にするのはこちら,公式リファレンスです.

Javascript in Max

先程のチュートリアルとココのintroductionを読めば,何となくの利用はできそうです.

jsオブジェクトでスクリプトを読み込む

それでは上記を参考に,Max/MSPにおけるjavascriptの簡単な使い方を見ていきましょう. Maxでjavascriptを利用するには,

のが基本です.(jsオブジェクトを置いてそこからMax内のエディタでスクリプト書いたりもできます)

ということで,こんな感じのスクリプトを用意してみます.

// my_script.js
//グローバル変数
// 作成するオブジェクトのインレット,アウトレット数指定
var inlets = 2;
var outlets = 1;

// loadbangメッセージによって呼び出される関数
// 関数式による定義
var loadbang = function(){
    post("load max patch"); //maxウインドウに文字列表示.ラベルは'js'
    post(); //改行
}

// bangメッセージによって呼び出される関数
// 関数宣言による定義
function bang(){
    post("recieve bang message\n"); //これでも改行可能
}

// helloメッセージによって呼び出される関数
var hello = function(){
    post("hello world");
    post();
}

jsオブジェクトで利用する為のスクリプトの記述ルールは至ってシンプルです.

まずグローバル変数でinlet,outletを定義し数値を与えることで,jsオブジェクトのインレット,アウトレット数を設定します.

そして反応したいメッセージ名の変数を作成,関数を格納することで,メッセージに対応する処理を記述できます. スクリプト内でのthisはjsオブジェクトを指すようで,要するにjsオブジェクトにおけるメソッドを定義していくイメージですね.

さて,上記スクリプトを作成したディレクトリに,以下のようなパッチを作成します.

f:id:ism1000ch:20141006233722p:plain

この状態でhelloメッセージやbangメッセージを与えると,maxウインドウに各種メッセージが表示されると思います.

インレットとアウトレットを利用する

上記スクリプトだと固定メッセージしか出せないので,インレットに入ってきた値を2乗にしてアウトレットから出力するjsオブジェクトを作ってみます.

//square.js
inlets = 1;
outlets = 1;

// floatメッセージに対応する関数.
// float,intメッセージは,msg_[int/float]で定義する
var msg_float = function(in_val){
    outlet(0,in_val*in_val);
}

f:id:ism1000ch:20141006235152p:plain

インレットに入ってくる値は,定義する関数の引数として関数内部で利用できます. 上記スクリプトでいうと,jsオブジェクトのインレットに入ってくるfloatオブジェクトの値はmsg_float関数内でin_valとして取ることができます.

そしてデータを出力する際は,outlet関数を使います.第1引数に出力アウトレットの番号を,第2引数に出力するデータを設定します.

インレットによるルーティング

とここまではチュートリアル見ればわかるんですが,「入ってくるインレットによって処理を変える」というプログラムを書こうとすると急に困っちゃいます.

そこでリファレンスをいろいろ見てみると,universally available methodsの中にinletなるプロパティがあるようで. 曰く,

During the execution of a function, the inlet property reports the inlet number that received the message that triggered the function, starting at 0 for the leftmost inlet. This property’s value is 0 within global code.

意訳

関数実行時,inletプロパティはその関数実行するためのメッセージを受信したinletの番号を教えてくれる!一番左はinlet番合0だから注意しろ!ちなみに外部スコープでは常に0だぜHAHA!

ほう.てことは当然this.inletで参照できますね.という訳でコレを利用してルーティングを可能にしたのが次のコード.

// multiplier.js
var inlets = 2;
var outlets = 1;

var multiplier = 0.5;

var msg_float = function(r){
    switch(this.inlet){
        case 0:
        post("inlet_0\n");
        outlet(0,r * multiplier);
        break;

        case 1:
        post("inlet_1\n");
        multiplier = r;
        break;

        default:
        break;
    }
}

利用パッチはこんな感じで.

f:id:ism1000ch:20141007004608p:plain

左インレット(this.inlet==0)に入力があった時は入力値にmultiplierを乗算して出力. 右インレット(this.inlet==1)に入力があった時はmultiplierを更新するのみで出力は無し. という処理になってます.Maxっぽいですね.

別変数でr * multiplierを保存しておき,bangメッセージに対応して出力する,みたいな処理も簡単に追加できそうですねー.

まとめ

Max内でjavascriptを利用するためのjsオブジェクトの使い方をまとめました.

  • パッチと同ディレクトリにスクリプト配置
  • jsオブジェクトでロード
  • 各種メッセージに対応した関数定義でトリガ
  • inletはthis.inletで参照

Max * js はコレだけでなく,各種オブジェクトをプログラム的に配置したりもできるみたいです. いわゆるメタプログラミングの一種でしょうかね.時間を見つけて勉強していきたいです.