Max/MSP で JavaScript を実行する

またもや Max/MSP の外部連携系の小ネタです.

JavaScript を使って自作オブジェクトを作ることはできるけども, 
「JavaScript のコードそのものをパッチ上で実行できないか？」
というと, 意外なほどにこれと言ったオブジェクトが見当たりません.

[shell] オブジェクトによる Unix コマンドや [shell] を介した AppleScript は実行できるのに,
JavaScript はどうしてできないのか?

乱数を作るのに, `Math.random()` の手っ取り早さをパッチに取り込んでみたいこともあるよね, 
ということでサンプルパッチを作ってみました.

#### 前段 : コマンドラインでの実行
- - -

結論から言うと, 我々にはすでに [shell] オブジェクトがあるのだから, 
コマンドラインで JavaScript が実行できればほぼ解決だろう, ということです.

今回は Mac OS X に標準でインストールされている, 
コマンドライン JS 実行エンジンを活用してみます.

```bash
# 気軽に利用できるよう コマンドjscにOSX標準のJS実行エンジンをリンク
$ ln /System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc /usr/local/bin
```

これで Terminal 上で JavaScript が実行し放題です.
ヘルプをみると次のような形式で使われることを意識しているみたいですが

`jsc somefile.js`

Max 上でこれをやるなら既に [js] オブジェクトがあるので, 
次のようにパイプを使ってワンライナーを渡すスタイルが主になるかとおもいます.

```bash
$ echo 12 + 3  | jsc
15
$ echo Math.PI | jsc
3.141592653589793
$ echo 'd = new Date()' | jsc
Fri Nov 15 2013 03:11:12 GMT+0900 (JST)
```

#### 本題 : Max のなかでの JavaScript 実行 
- - - 
ここまで来たら, あとは Max 上で [shell] オブジェクトを経由して
任意のコードを実行してやるだけです.

以下のようなメッセージを [shell] に送ってみましょう.

 - `echo 1+2 | jsc`
 - `echo 'Math.random()' | jsc`
 - `echo Math.random\\(\\) | jsc`
 - `echo 'dd = new Date()' | jsc`

![execJavascriptInMax.png](https://qiita-image-store.s3.amazonaws.com/0/8510/797add9e-f614-3bf1-2111-7a5320f5c495.png)

#### サンプルパッチ
- - - 
以下のコードをテキストファイルに保存して, Max 6で開いてください.

```json:execJavascriptInMax.maxpat
{
	"patcher" : 	{
		"fileversion" : 1,
		"appversion" : 		{
			"major" : 6,
			"minor" : 0,
			"revision" : 0
		}
,
		"rect" : [ 136.0, 79.0, 735.0, 382.0 ],
		"bglocked" : 0,
		"openinpresentation" : 0,
		"default_fontsize" : 12.0,
		"default_fontface" : 0,
		"default_fontname" : "Arial",
		"gridonopen" : 0,
		"gridsize" : [ 15.0, 15.0 ],
		"gridsnaponopen" : 0,
		"statusbarvisible" : 2,
		"toolbarvisible" : 1,
		"boxanimatetime" : 200,
		"imprint" : 0,
		"enablehscroll" : 1,
		"enablevscroll" : 1,
		"devicewidth" : 0.0,
		"description" : "",
		"digest" : "",
		"tags" : "",
		"boxes" : [ 			{
				"box" : 				{
					"fontname" : "Hiragino Maru Gothic Pro W4",
					"fontsize" : 12.0,
					"id" : "obj-16",
					"maxclass" : "comment",
					"numinlets" : 1,
					"numoutlets" : 0,
					"patching_rect" : [ 237.5, 69.0, 458.0, 24.0 ],
					"text" : "あらかじめTerminalで以下のツールをjscコマンドとして呼び出せるようにしておく"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Monaco",
					"fontsize" : 9.0,
					"frgb" : [ 0.0, 0.0, 1.0, 1.0 ],
					"id" : "obj-15",
					"linecount" : 2,
					"maxclass" : "comment",
					"numinlets" : 1,
					"numoutlets" : 0,
					"patching_rect" : [ 237.5, 88.0, 443.0, 31.0 ],
					"text" : "ln /System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc /usr/local/bin",
					"textcolor" : [ 0.0, 0.0, 1.0, 1.0 ]
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Hiragino Maru Gothic Pro W4",
					"fontsize" : 14.0,
					"id" : "obj-13",
					"maxclass" : "comment",
					"numinlets" : 1,
					"numoutlets" : 0,
					"patching_rect" : [ 22.5, 24.0, 300.0, 27.0 ],
					"text" : "Maxパッチから Javascript を実行するテスト"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-12",
					"maxclass" : "message",
					"numinlets" : 2,
					"numoutlets" : 1,
					"outlettype" : [ "" ],
					"patching_rect" : [ 214.0, 229.0, 155.0, 18.0 ],
					"text" : "echo 'dd = new Date()' | jsc"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-11",
					"maxclass" : "message",
					"numinlets" : 2,
					"numoutlets" : 1,
					"outlettype" : [ "" ],
					"patching_rect" : [ 214.0, 201.0, 148.0, 18.0 ],
					"text" : "echo 'Math.random()' | jsc"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-10",
					"maxclass" : "newobj",
					"numinlets" : 1,
					"numoutlets" : 0,
					"patching_rect" : [ 274.5, 297.0, 34.0, 20.0 ],
					"text" : "print"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-9",
					"maxclass" : "message",
					"numinlets" : 2,
					"numoutlets" : 1,
					"outlettype" : [ "" ],
					"patching_rect" : [ 214.0, 172.0, 85.0, 18.0 ],
					"text" : "echo 1+2 | jsc"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-7",
					"maxclass" : "message",
					"numinlets" : 2,
					"numoutlets" : 1,
					"outlettype" : [ "" ],
					"patching_rect" : [ 126.0, 122.0, 59.0, 18.0 ],
					"text" : "which jsc"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-6",
					"maxclass" : "message",
					"numinlets" : 2,
					"numoutlets" : 1,
					"outlettype" : [ "" ],
					"patching_rect" : [ 126.0, 96.0, 32.5, 18.0 ],
					"text" : "env"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-5",
					"maxclass" : "message",
					"numinlets" : 2,
					"numoutlets" : 1,
					"outlettype" : [ "" ],
					"patching_rect" : [ 126.0, 69.0, 85.0, 18.0 ],
					"text" : "echo $SHELL"
				}

			}
, 			{
				"box" : 				{
					"bgcolor" : [ 0.4, 1.0, 0.4, 1.0 ],
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-4",
					"linecount" : 2,
					"maxclass" : "message",
					"numinlets" : 2,
					"numoutlets" : 1,
					"outlettype" : [ "" ],
					"patching_rect" : [ 88.0, 297.0, 178.0, 32.0 ],
					"text" : "Fri Nov 15 2013 02:54:00 GMT+0900 (JST)"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-3",
					"maxclass" : "newobj",
					"numinlets" : 1,
					"numoutlets" : 1,
					"outlettype" : [ "" ],
					"patching_rect" : [ 88.0, 263.0, 73.0, 20.0 ],
					"text" : "fromsymbol"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-2",
					"maxclass" : "newobj",
					"numinlets" : 1,
					"numoutlets" : 1,
					"outlettype" : [ "" ],
					"patching_rect" : [ 88.0, 235.0, 58.0, 20.0 ],
					"text" : "aka.shell"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-1",
					"maxclass" : "newobj",
					"numinlets" : 1,
					"numoutlets" : 1,
					"outlettype" : [ "" ],
					"patching_rect" : [ 88.0, 207.0, 59.0, 20.0 ],
					"text" : "tosymbol"
				}

			}
 ],
		"lines" : [ 			{
				"patchline" : 				{
					"destination" : [ "obj-2", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-1", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-1", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"midpoints" : [ 191.0, 253.0 ],
					"source" : [ "obj-11", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-1", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-12", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-3", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-2", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-10", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-3", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-4", 1 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-3", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-1", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-5", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-1", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-6", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-1", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-7", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-1", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-9", 0 ]
				}

			}
 ],
		"dependency_cache" : [ 			{
				"name" : "aka.shell.mxo",
				"type" : "iLaX"
			}
 ]
	}

}
```

#### 参考記事
- - - 

*[aka.shell] の利用*
[UnixコマンドをインタフェースとしたMax-外部アプリ間の連携方法](http://qiita.com/tgck@github/items/f3d6a98fc1fa76a139f3)