jit.leapmotion リープモーションのステレオ赤外線カメラ画像取得できるExternalオブジェクト #maxmsp #jitter

スクリーンショット 2014-11-04 21.43.12
Jitter Externalの勉強がてらLeap Motionのステレオ赤外線カメラ画像を取得できるExternalオブジェクトを書いてみました。Mac OSX Yosemite環境にて開発してるので、それ以外で動くかは謎です。

ダウンロード

Cycling74 Max Tool。パッケージにまとめてあるので、Application/Max6.1/packages 以下に落としたファイルを置けば使えると思います。

注意点

スクリーンショット 2014-10-31 19.49.15

  • Leap Motionをインストールするとメニューバーに出てくるLeap Motionコントロールパネルにて、イメージを許可するにチェックをしないと動かないです。
  • 解像度は640×240で固定。Leap Motion SDKの仕様で、動作が重くなると自動的に640×120に変更されてしまう事があるのですが、その場合は縦に引き伸ばしています。

Max External開発 simplemaxオブジェクトのサンプルコードを読み解く #maxmsp

スクリーンショット 2014-10-25 2.08.50
MaxでもopenFrameworksみたいにCやC++の資産を活用したい!aka.leapmotionを参考にLeapMotion v2.のオブジェクトも開発してるので、そのうち公開したい!ということで、久しぶりにMax External勉強してます。

今回は、MaxSDKをダウンロードすると付いて来るXcodeプロジェクトサンプルから、simplemaxのコードを読んでみます。ちなみに Yosemite / Xcode6でやってます。

インクルード

#include "ext.h"	// standard Max include, always required
#include "ext_obex.h"	// required for new style Max object

この2つは大抵のオブジェクトでインクルードします。C言語の入門書におまじないって書いてあるやつですね。

Maxオブジェクトの構造体定義

////////////////////////// object struct
typedef struct _simplemax 
{
	t_object	ob;	// the object itself (must be first)
} t_simplemax;

プライベート変数やプロキシを利用する場合は、構造体メンバとして定義する必要があるそうです。MaxAPI Document参照。

関数プロトタイプ宣言

///////////////////////// function prototypes
//// standard set
void *simplemax_new(t_symbol *s, long argc, t_atom *argv);
void simplemax_free(t_simplemax *x);
void simplemax_assist(t_simplemax *x, void *b, long m, long a, char *s);

(Max側から呼び出したい)登録したいメソッドは、ここでプロトタイプ宣言しといてmain関数で登録する。maxsimpleがインスタンス化する時に必要なnewと解放する(消す)時に必要なfreeは必須。assist関数は、必ず必要なものでは無いようです。

クラスの登録

//////////////////////// global class pointer variable
void *simplemax_class;


int C74_EXPORT main(void)
{	
	// object initialization, NEW STYLE
	t_class *c;
	
	c = class_new("simplemax", (method)simplemax_new, (method)simplemax_free, (long)sizeof(t_simplemax), 
				  0L /* leave NULL!! */, A_GIMME, 0);
	
	/* you CAN'T call this from the patcher */
        class_addmethod(c, (method)simplemax_assist,"assist",A_CANT, 0);  
	
	class_register(CLASS_BOX, c); /* CLASS_NOBOX */
	simplemax_class = c;

	post("I am the simplemax object");
	return 0;
}

C74_EXPORTは、おまじないでMaxからこのmain関数が呼べるようになるマクロのようです。t_class *cのポインタにclass_newでクラスを生成しています。simplemax_new / simplemax_free は、プロトタイプ宣言してあるのでここで関数ポインタを渡してクラスメソッドとして登録していますね。さらにそのclassインスタンスにsimplemax_assistメソッドを登録しています。このメソッドは、inletやoutletにマウスポインタを合わせるとポップアップで説明がでてくるタイプのメソッド。class_registerでCLASS_BOXへクラスの登録をすることでMaxからsimplemaxクラスが探せるようになります。このmain関数で一度作成し登録したクラスは、グローバル変数のsimplemax_classにポインタを保存しておくみたい。たぶんMax起動時に一度だけこのMain関数が呼ばれてクラスだけ登録しておいて、simplemaxがインスタンス化される場合は使いまわしている。

メソッドの実装

void *simplemax_new(t_symbol *s, long argc, t_atom *argv)
{
	t_simplemax *x = NULL;
        long i;
    
	// object instantiation, NEW STYLE
	if ((x = (t_simplemax *)object_alloc(simplemax_class))) {
        object_post((t_object *)x, "a new %s object was instantiated: %p", s->s_name, x);
        object_post((t_object *)x, "it has %ld arguments", argc);
        
        for (i = 0; i < argc; i++) {
            if ((argv + i)->a_type == A_LONG) {
                object_post((t_object *)x, "arg %ld: long (%ld)", i, atom_getlong(argv+i));
            } else if ((argv + i)->a_type == A_FLOAT) {
                object_post((t_object *)x, "arg %ld: float (%f)", i, atom_getfloat(argv+i));
            } else if ((argv + i)->a_type == A_SYM) {
                object_post((t_object *)x, "arg %ld: symbol (%s)", i, atom_getsym(argv+i)->s_name);
            } else {
                object_error((t_object *)x, "forbidden argument");
            }
        }
	}
	return (x);
}

void simplemax_free(t_simplemax *x)
{
	;
}

void simplemax_assist(t_simplemax *x, void *b, long m, long a, char *s)
{
	if (m == ASSIST_INLET) { // inlet
		sprintf(s, "I am inlet %ld", a);
	} 
	else {	// outlet
		sprintf(s, "I am outlet %ld", a); 			
	}
}

simplemax_newはオブジェクトがインスタンス化される場合に呼ばれる。このサンプルは、渡された引数をひたすらMaxWindowにポストしてくれてる。argvにアーギュメントがargc個入っていて、t_atom型はa_typeメンバをみると型が書いてあるよう。atom型はゲット関数が用意されている。メンバ変数などの初期化は、ここに書けば良さそう。

simplemax_freeの方は特に何もしてないけど、インスタンス化したオブジェクト自体は裏で勝手に開放してくれているのかな?。自分でインスタンス化したオブジェクトがあればここで開放したい。simplemax_assistは、アシスト表示を使うときのテンプレートのようです。

メソッド追加(余談)

void simplemax_bang(t_simplemax*x)
{
    post("bang");
}

class_addmethod(c,(method)simplemax_bang,"bang", A_SYM,0);

このsimplemaxオブジェクトは、どんなメッセージにも反応しないサンプルとしてはかなり駄目な子です。そこでメソッドを定義して、クラスに登録してみたらちゃんと動きました。トップ絵はbangを送って動作させてる様子です。C言語だけどオブジェクト思考の匂いがする。


簡易アタック検出を行う External Object をつくってみた:Max/MSP, Max SDK, DSP

簡易アタック検出オブジェクトをつくってみた

Max SDKで、まずは手短に実装できてライブで役に立ちそうな物を練習がてら作ってみました。「オーディオを読み込んでアタック部分を検出するオブジェクト」です。上記の動画がデモになります。右下のリストに、アタック部分の開始タイミング(ms)が入り、選択すると音の頭から再生が始まっています。

今回のエクスターナルオブジェクトの作成で、Max SDKを使えば、非リアルタイムにバッファをいじって、1サンプル毎の処理をかけるという事も確かめられました。

プログラムの簡単な解説

  1. 音声バッファをフレームに分割
  2. フレーム毎に振幅の最大値を計算
  3. フレーム間の振幅の差分を計算
  4. 差分がある一定の大きさ以上であればアタック

という結構簡単な処理で上記のような結果を得られました。

ただし楽曲などの複雑なオーディオ信号の場合は失敗してしまいます。もっと精度の良い検出をしたければ、各フレームに対してFFTを使って周波数領域にした上で、振幅や位相の変化から検出したりすると精度があがるようです。今後やってみたいです。

参考文献


Max SDK のサンプルプロジェクトから自分のプロジェクトをつくる:Max/MSP, Max SDK, Xcode

プロジェクトを作ってみよう

前回はMax SDK 付属のサンプルプロジェクトをコンパイルし、エクスターナルオブジェクトが作成できる事を確認しました。今回は、サンプルプロジェクトから自分のプロジェクトを作成してみます。

プロジェクトフォルダのコピー

スクリーンショット 2013-01-25 17.01.57

/MaxSDK-6.0.4/example/basics 内のsimplemax等のフォルダをコピペします。そのコピーしたフォルダ名を好きなオブジェクト名に変更してください。(例えば mirrorboy.object ちなみに接頭語としてmirrorboyをつけたのは自分のオブジェクトであることを認識しやすいようにです。 )

プロジェクト名の変更

スクリーンショット 2013-01-25 17.06.02

そのフォルダ内のプロジェクトを開きます。まだ以前のプロジェクト名になっているので、左のリストからプロジェクトのトップを選択後、右上の方にあるIdentity → Project Name の設定欄から、プロジェクト名を mirrorboy.object などの名称に変更します。

参考:Xcode 4でプロジェクトの名称変更

 

オブジェクト名の変更

エクスターナルオブジェクトの名称は、*.c ファイルの class_new の第一引数で設定されているので、ここを”mirrorboy.object”等に変更します。ここまで出来ればコンパイルが通り,名称変更後のエクスターナルオブジェクトが作成されます。*.c ファイル内の変数名や.maxhlepファイルも置換で直しておくとより良いです。

 

Max.app 上でオブジェクトを作成し確認

スクリーンショット 2013-01-25 17.17.27

自分のプロジェクトでコンパイルしたエクスターナルオブジェクトがインスタンス化できる事を確認しました。あとは好き勝手に開発するだけでOKです。


Max SDK のサンプルプロジェクトから External Object を作成:Max/MSP, Max SDK, C

Max/MSPを使ったアプリケーションを実装する際に、音に関して非リアルタイム && 1sample毎に信号処理したい(例えば、読み込んだ音声波形を再生する前にグリッチしたり、音のアタック部分だけを分析したりといった事。)欲求が高まってきました。期待をいだいて GEN や Max in JavaScript に手をだしたんですが、それらでは不可能だったので遂にMax SDKに手を出し始めましたよ!

これからMax SDKを使ったエクスターナルオブジェクト作成について書いてみたいと思います。ちなみにMac OS 10.8 / Xcode 4 の環境でやります。またJavaじゃなくてC言語なのは、少し前にArduinoをやってC言語を勉強したからです。

準備

SDKのダウンロード先 →  Max SDK

ダウンロードしたフォルダ MaxSDK-6.0.4を適当な場所に置きます。自分は /Document/Max 以下に置きました。Maxのサーチパス下に置くとコンパイルしたオブジェクトをMaxが認識してくれるので都合がいいです。

Xcodeプロジェクトを開く

/MaxSDK-6.0.4/examples/basics/ 以下にサンプルプロジェクト(*.xcodeproj)がいくつか入っているので、例えばsimplemax.xcodeproj 開いてみると、Xcodeが立ち上がります。

.xcconfig の修正

スクリーンショット 2013-01-25 4.18.32

このままだとコンパイルが通らないので、/MaxSDK-6.0.4/maxmspsdk.xcconfig の33,34行目を

SDKROOT = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk
MACOSX_DEPLOYMENT_TARGET = 10.8

へと変更します。Mountain Lionには10.6のSDKが入ってないためです。

コンパイル

左上の三角ボタンを押して、コンパイルが完了です。/MaxSDK-6.0.4/sdk-build 以下に simplemax.mxo が作成されている事が確認できます。

Max6を起動

スクリーンショット 2013-01-25 4.23.19

/MaxSDK-6.0.4/sdk-buildフォルダがMaxのサーチパス内に入っていれば、Max6を起動し、simplemaxオブジェクトをインスタンス化する事が出来ます。すでにMaxが起動していた場合は、一旦Max.appを落としてから起動しなおしてください。せっかく作ったこのsimplemaxオブジェクト、実は何も入力を受け付けないオブジェクトなので、何もできないです。

/example 以下には、沢山のサンプルプロジェクトがあるので色々試して見てください。ちなみに全てのサンプルプロジェクトにヘルプパッチ(*.maxhelp)が付いているので、パッチの説明・使用例が見られます。

まとめ

今回は、Max SDK をダウンロードして、Xcodeにてサンプルプロジェクトのコンパイルを行ない、External Objectの作成を行ないました。

補足

プロジェクトフォルダ内になる *.def と *.vcproj は、Win用の開発環境であるVisual Studio 用のファイルのようですので、Macの方は気にしなくて良いようです。