音楽に同期して、複数PCの動画をフレーム同期しながら再生するMaxパッチを開発:Cycling’74 Max, OSC

スクリーンショット 2013-09-04 21.21.43

少し前の話になりますが、動画クリエーターで裸眼立体視の研究者であるAono.Y氏に誘われて、天野喜孝xHYDE展 [天命と背徳~NIPPON EVOLUTION~]内のFVP(裸眼立体視が体験可能な映像展示)向けにMaxパッチを作成しました。Aono.Yさんお誘いありがとう!

要件

  • 音楽に同期して、複数PC(10台以上)の動画(しかも高解像度)をフレーム同期しながら再生する
  • 一日の連続稼働12時間

実装・感想

  • フルHD以上の動画再生だったので、はじめはC++系じゃないとキツイかな?と思ってたんですが、Maxで試作したらあっさり動いて驚きました。
  • フレームレート 開発機のMacでは出てたがWinにした途端に落ちて困った → 動画圧縮形式の変更で対応
  • フレーム同期はマスターパッチから、UDPで各PCに同期信号をガンガン送りました。結構適当なやり方してたんですが、テスト動画もバッチリ再生されました。ネットワーク構築に使ったY社のルーターが優秀という噂がw
  • 現場でコーディングや修正が発生しても、直しやすいのも良かった。Maxで開発するのは楽しい。
  • 12時間連続稼働でも、特に落ちたとかの報告が来なかったので、安定稼働していたみたい。

JavaScript in Max の Templete : Max/MSP, JavaScript

[javascript]
"use_strict";
inlets = 2;
outlets = 1;
autowatch = 1;

var foo = 100;
declareattribute("foo",null,null,1);

function loadbang(){

out(messagename);
}

function bang(){

if(inlet == 0){

out(messagename);
}

foo++;
post("foo: " + foo);
post();
}

function msg_int(num){

out(num);
}

function msg_float(num){

out(num);
}

function message(){

var a = arrayfromargs(messagename,arguments);

out(a);

}

function list(){

var a = arrayfromargs(messagename,arguments);

out(a);
};

function anything()
{
var a = arrayfromargs(messagename,arguments);

out(a);
}

//////////////////////////////////////////////////////////////////////////////////////////

function init(){

post("jsarguments:");
for(var i = 0 ; i < jsarguments.length ; i++){

post(jsarguments[i]);
post();
}
}

function out(){

post(messagename + " :");

for(var i = 0 ; i < arguments.length ; i++){

post(arguments[i] + " ");
outlet(0,arguments[i]);
}

post();
}

//////////////////////////////////////////////////////////////////////////////////////////

function save(){

post("save");
post();

//When the js object containing this script is recreated, the function numchairs will be called
embedmessage("init");
}

//Assistance for Inlet
function describe_inlet(num){

assist("this is inlet number : " + num,num);
}
setinletassist(-1,describe_inlet);

//Assistance for Outlet
function describe_outlet(num){
assist("this is outlet number : " + num,num);
}
setoutletassist(-1,describe_outlet);

[/javascript]

jsオブジェクト内で記述する JavaScript in Max の書き方を忘れがちなので、自分用にTempleteをつくりました。jsオブジェクトをダブルクリックで開くエディタにコピペして、ご利用ください。

日本語を Max6 から Processing に OSC 経由で送る際の文字化けについて

oscP5-1

Max6 は文字コードのエンコーディングに UTF-8 を、Processing は内部的には Java なので UTF-16 を用いているのではと推測されます。そのため Processing 向けのoscP5は、Max6から受け取った UTF-8 の日本語バイト列を toString() すると、UTF-16 として解釈して文字化けしてしまいます(たぶん)。OscMessage や OscArgument のクラスなどひと通りみたのですが、エンコーディングに関するメソッドが見当たりませんでした。

そこで対策ですが、Max6 から受け取った OscMessage の Byte 列を一旦 UTF-8 として String に変換すれば問題が無くなりました。そんなに検証してないので問題あったら教えて欲しいっす!

[java]
void oscEvent(OscMessage theOscMessage) {

//このprintでは日本語の文字化けが確認される。
theOscMessage.print();

//OSCをByte列として取得
byte[] bytes = theOscMessage.getBytes();

try {

//Byte列をUTF-8として解釈
String str = new String(bytes, "UTF-8");

//Addrpatternとtypetagを削除する
String typeTagStr = theOscMessage.typetag();
str = str.substring(str.indexOf(typeTagStr) + typeTagStr.length());

//コンソールにMax6から送った日本語のメッセージが表示される
println("String:"+str);

}
catch(UnsupportedEncodingException e) {

e.printStackTrace();

};

}
}
[/java]

LiveAPIを使い、自分のトラックナンバーを得るパッチ:Javascript in Max, Max for Live

スクリーンショット 2013-04-09 1.14.11

[javascript]
//init
"use_strict";
inlets = 1;
outlets = 1;
autowatch = 1;

var api;// = new LiveAPI();

function loadbang(){

api = new LiveAPI();
}

//bangを受け取ると、このデバイスが刺さっているトラックナンバーを出力
function bang(){

//Loadbangの中で代入できない場合があった。
//LiveAPIの初期化は、非同期処理なのかな?
api.path = "this_device";

var pathStr = api.path;
var paths = pathStr.split(" ");
outlet(0,parseInt(paths[2]));
}

[/javascript]
LiveAPIを勉強してます。文字列処理は、Javascriptでやると簡単だと思う。