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言語だけどオブジェクト思考の匂いがする。

Gen codebox内でfor文を使った平滑化フィルター #maxmsp #jitter

スクリーンショット 2014-10-24 19.37.12
genでfor文の使い方メモ。genで配列使いたい。

Codebox / genexpr

size = 10;
offset = floor(size/2);
scale = 1/(dim+1);
pix = 0;

for(x = 0 ; x < size ; x = x + 1){
	
	for(y = 0 ; y < size ; y = y+1){
	
		delta = (vec(x,y) - offset) * scale;
		pix = pix + sample(in1,norm + delta,boundmode="clamp")/(size*size);
	}
}

out1 = pix;

続きを読む Gen codebox内でfor文を使った平滑化フィルター #maxmsp #jitter

SVGの背景を透過するサンプル jit.mgraphics × jit.gl.pix #maxmsp #jitter #gen

スクリーンショット 2014-10-17 11.57.59jit.mgraphicsで描画したSVGに透過色を持たせたい場合には、jit.gl.pixで特定の色を透過させる処理を書くと良さそうです。上の画像は、カメラのキャプチャにSVGの描画を載せたサンプル。棚がとっ散らかってますが、お気にせず・・・

jit.mgraphicsで背景黒にして描画

スクリーンショット 2014-10-17 11.56.39svgでピンクの丸を描画してます。ちなみにillustratorでSVGをつくりました。(左側に、ちょっと、余分なコードも入ってますがお気にせず。)

jit.gl.pix 黒を透過

スクリーンショット 2014-10-17 12.06.54厳密に言うと、黒に近いほど透過されるコードに成ってますが、とりあえず目的に適うのでオッケーです。

Code(シェーダ部分)


----------begin_max5_patcher----------
757.3oc0WssahCCD84juBK+LKxNAnj8s86.UgLItgoqwNxwbYaU+2WamKjvF
pnkVDqPJANy3wGe73gwuFFfWoNvKwnehVfBBdMLHvC4.Bp+c.dC6PpfU5cCK
46UqdFOpxjgev3geFLiyEiKfCn8fLSsuwimTRSI7B24EMZLoFVs0H3FyeJ3U
StK.KyEKcAbqliGgvXzi0NK2tAjV28LfdDrJHdznZzBlIcMHyWp4olpPGSlZ
mVTzL+qjI9ePFSZCuihR1FOSv+RCLQC4gLOlcA+C5Lb2ofqq0nZQxFEPv2w0
kfR1glAXVQQG3fNCworOq7AZ1nVHPVAQagz7cPy3SZQYZ6B0XWkN4xwxCymg
qL9VXyjeTEhnIN0GQmG6E.5CtWwSiNJD1s97TknZ5WfHiSF04AsuiBU5u4d4
gz.pJ3RPVn4kbogYpYbq4L9SrsByxgyH5a+IVJ+rCdv8p.btFxTRGI5MRGby
zs.Q8IAtmGWLdOjrhAFboccrsbES61AVI3cR0rI+Jknuo1Mc6YHlD1vLbCTQ
1HRaPgMEZPZ5MQbIyFi0koZkPzKTUV1MfkLadQJeOjYV6iUWoz5NTzrEfa0n
LHmWZ5iYX4k8Q5UTnaBa2hC8veuhD8KTTtGdAoyW003YxHFrNQaUgyVYXfpC
csLPEBJweXHwexX5zSKP79EINsPQTDtA+svvluL5qWI2.G9FDw3OqHNm30sI
d4axrqTDo2HQTvk41iO2eIizod8bR7UJjjajPtimhHUe9FTyIeV0Lt5zL0Kl
O7v0IlzjajXBRD8aPEIeVUzVYbpsYApukAxUJh2HMzt5tXQ7BO4RtjJfwj49
WWYt1jgjoi8rH.449KZOyb1GV+JUa0oMIK0+gksEudrz1+fAjssvsnsVxoNt
Fxx52xTUWFktdVp5N7h1s+nbldoTN5+OJ6bjdWP4nKkySteT4jOhLeev4ANW
8NbN5KfynGCOh3eVWa4zaq5n8I2R8jan9u2N8b2L0NOuE9W.Vv2VrA
-----------end_max5_patcher-----------

こういう微妙なコードをBlogに書いとくと、後で再利用しやすいのが良いですね。Max7だと、コードスニペット機能が充実するそうなので、楽しみですな〜。

Cycling74 Max レッスン生徒さんご紹介 その1 TY0004さん #maxmsp

TY0004さん アイコン

130810

Cycling 74 Maxを使い始めたきっかけを教えて下さい

作品発表のための、表現力を高めたかったためです。

今回Maxによる、お子様向けの展示をつくったのは、どうしてですか?

環境・健康問題について、体を使ったゲームを楽しみながら、慣れ親しんで貰いたかったからです。

TY0004さんによる作品

kidz_01

kidz_04

※著者解説
綿毛やバイキンが降ってくるのを、触ったり避けたりする事を通して、環境や健康への認識を育む作品。TY0004さんにとって初のMaxによる作品制作でした。OpenNI / Xtionを使ったボーン認識や、jit.physを使った物理シュミレーション、jit.gl.*による描画など、少し高度な内容も含まれていましたが、明確に目的が決まっていたので制作は順調に進みました。

実際展示してみてどうでしたか?

ゲーム自体、とても楽しんでもらえました。体を動かし、中には転んでしまう程にたっぷりと満喫してもらうことが出来ました。(環境・健康の)難解な話だけであれば子供達の関心は向かなかったと思います。

Maxレッスンについての感想を教えて下さい

自身のやりたい事に合わせながら、とても丁寧に進めて下さっており、個人的な相談にも親身に耳を傾けて下さります。

今後、さらに勉強していきたい技術は、ありますか?

今後は、Maxだけではなくプログラミング全般も学んでいきたいです。

Maxレッスンについての詳細は、こちらのページを御覧ください!

maxurlのサンプルを試す #cycling74 #maxmsp #curl

スクリーンショット 2014-09-11 02.43.36
最近のアップデートで登場したcURLのMaxラッパーであるmaxurl。ついにMaxがインターネットと繋がる!と期待が高まり、勉強がてらサンプルコードを弄ってみました。

まずmaxurlのヘルプパッチを見るのがオススメです。タブになっていて、いくつものサンプルがいじれます。上記画像はヘルプパッチの良いねボタンサンプル。良いねボタンを押すとサーバー上のいいねカウントが1つあがる。

更に詳しい説明が書いてあったのは→Use MaxURL to Create a Realtime Instagram Collage

MaxでWeb APIを扱う2つの方法

どうやら、Maxがインターネッツとのリクエスト・レスポンスを扱う方法は二種類あるようです。

  1. maxurlとdictを使うパターン。JSONでクエリを生成し、それ以外はMaxらしいパッチングで行う方法
  2. jsオブジェクト(javascript)を使うパターン。XMLHttpRequestで行う方法

それぞれの方法についてCycling74のフォーラムにいくつかサンプルパッチがあったので試してみました。

MaxURL Weather Report

スクリーンショット 2014-09-11 02.12.47

Maxから天候を取得してみようというサンプル。このサンプルは、maxurlとdictでAPIを使う方法。

天候取得クエリ

[javascript]
{
"http_method" : "get",
"url" : "api.openweathermap.org/data/2.5/weather?q=Tokyo,jp",
"response_dict" : "data1",
"parse_type" : "json"
}
[/javascript]

元々のサンプルはロンドンの天気を取得していたのですが、東京の天気は、”London,uk” → “Tokyo,jp”と変更したら取得できました。

MaxURL SoundCloud

スクリーンショット 2014-09-11 02.19.12

MaxからSoundCloudのAPIを使うサンプル。SoundCloud Developerの登録が必要です。例えば “livetune”と検索すると、ヒットしたURLがumenuに登録されます。このサンプルは、jsオブジェクトでAPIを使う方法。

ニコニコ横断検索API

サンプルにも慣れて、そろそろ自分で一から試してみようとAPIを探してみると、検索キーワードに関連したタグを返してくる”タグ検索API”というのを発見。将来的に”あのタグで待ってる。“に組み込んだら面白いかなと思って試してみました。

[javascript]
{
"http_method" : "POST",
"url" : "http://api.search.nicovideo.jp/api/tag/",
"post_data" : {
"query" : "Free!",
"service" : [ "tag_video" ],
"from" : 0,
"size" : 5,
"issuer" : "apiguide",
"reason" : "ma10"
}
,
"response_dict" : "data4"
}
[/javascript]
こんなクエリーを投げると

スクリーンショット 2014-09-11 02.34.46
レスポンスが帰ってきた!しかし、応答のBodyに対して文字列がエスケープ?のバックスラッシュが付きまくっている!!!Maxで消す方法がわからなくて、データを利用できなかった。

取得できたタグを見ると”Free!のためなら死ねる!”とか面白いですが、タグとして抽象度が低いのは使いづらいかも?!maxurlの使い方は未知数なので、今後も情報収集していきたいです!!!!!