Max/MSPでシングルトンなパッチをつくる

Max/MSP でのプログラミングで,
軽いつもりのパッチが不思議に重くなっていて, しらべてみたら同じパッチが何枚も立ち上がっていた, なんてことがよくあります.

オブジェクト指向言語では, 同時に存在するインスタンスをつねにひとつに制限する「[シングルトン](http://ja.wikipedia.org/wiki/Singleton_パターン)」というプログラムの書き方があるのですが, Max でもこれができないかと思い, 試してみることにしました.

以下が完成したパッチです.

![singleton.png](https://qiita-image-store.s3.amazonaws.com/0/8510/92367aa0-d212-e720-0327-dde8c5484c4c.png)


#### パッチの要点
- - -

作成にあたり, 方針を以下のように定めました.

1.  肝となるインスタンス ( =パッチ) 数の管理に [value] オブジェクトを使う
2.  パッチ起動時にガードをかけるのが理想. しかし手だてがない.
　そこで, 「同じパッチを立ち上げるとすぐパッチを閉じる」という方針とした.
3.  なるべく基本的なオブジェクトを使って作成する.



#### 処理のながれ
- - -

実際に処理の流れを追いかけて, どのようにシングルトンが実現されているのかを説明します.

*- 凡例 -*
- `[foobar]`  foobar というオブジェクトをあらわします
- `"tomtom"`  tomtom というメッセージをあらわします

#####  1つめのパッチの起動 〜  [value] に 1 が格納される

- [value] の, 「未初期化状態では "bang" に反応しない」という性質を利用しています.
- [if] は "1 == 0" を評価して偽 ( "0" をアウトレット1から出力 ) を送信します.
- この結果、[value] に "1" が送信され,  [value] に 1 が格納されます.

#####  2つめのパッチの起動 〜 パッチクローズする

- [value] には, 1 が格納されているため, [loadbang] により [value] が "1" を送信します.
- [if] は "1 == 1" を評価して真 ( "1" をアウトレット1から出力 ) する.
- [thispatcher] に "wclose" が送信され, 当該パッチが閉じる.
- [onebang] は, 1つめのパッチで [value] の値の更新を1度きりと制限するために入れています.


#### サンプルパッチ
- - -
以下のコード片をテキスト形式で保存して, Max で開くことができます.

```json:singleton.maxpat
{
	"patcher" : 	{
		"fileversion" : 1,
		"appversion" : 		{
			"major" : 6,
			"minor" : 0,
			"revision" : 0
		}
,
		"rect" : [ 149.0, 93.0, 331.0, 353.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-4",
					"maxclass" : "comment",
					"numinlets" : 1,
					"numoutlets" : 0,
					"patching_rect" : [ 9.0, 22.0, 142.0, 24.0 ],
					"presentation_rect" : [ 23.0, 38.0, 0.0, 0.0 ],
					"text" : "二重起動を防止する"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Hiragino Maru Gothic Pro W4",
					"fontsize" : 12.0,
					"id" : "obj-1",
					"maxclass" : "comment",
					"numinlets" : 1,
					"numoutlets" : 0,
					"patching_rect" : [ 9.0, 5.0, 143.0, 24.0 ],
					"text" : "singleton patch in Max"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-46",
					"maxclass" : "newobj",
					"numinlets" : 2,
					"numoutlets" : 1,
					"outlettype" : [ "" ],
					"patching_rect" : [ 110.0, 201.0, 145.0, 20.0 ],
					"text" : "if $i1 == $i2 then 1 else 0"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-44",
					"maxclass" : "newobj",
					"numinlets" : 2,
					"numoutlets" : 1,
					"outlettype" : [ "" ],
					"patching_rect" : [ 110.0, 175.0, 56.0, 20.0 ],
					"text" : "pack 1 0"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-35",
					"maxclass" : "newobj",
					"numinlets" : 1,
					"numoutlets" : 2,
					"outlettype" : [ "bang", "bang" ],
					"patching_rect" : [ 110.0, 110.0, 34.0, 20.0 ],
					"text" : "t b b"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-29",
					"maxclass" : "newobj",
					"numinlets" : 1,
					"numoutlets" : 2,
					"outlettype" : [ "", "" ],
					"patching_rect" : [ 137.5, 310.0, 69.0, 20.0 ],
					"save" : [ "#N", "thispatcher", ";", "#Q", "end", ";" ],
					"text" : "thispatcher"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-27",
					"maxclass" : "message",
					"numinlets" : 2,
					"numoutlets" : 1,
					"outlettype" : [ "" ],
					"patching_rect" : [ 137.5, 286.0, 47.0, 18.0 ],
					"text" : "wclose"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-24",
					"maxclass" : "message",
					"numinlets" : 2,
					"numoutlets" : 1,
					"outlettype" : [ "" ],
					"patching_rect" : [ 110.0, 257.0, 37.0, 18.0 ],
					"text" : "set 1"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-23",
					"maxclass" : "newobj",
					"numinlets" : 1,
					"numoutlets" : 1,
					"outlettype" : [ "" ],
					"patching_rect" : [ 147.0, 145.0, 61.0, 20.0 ],
					"text" : "v _static_"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-22",
					"maxclass" : "newobj",
					"numinlets" : 1,
					"numoutlets" : 1,
					"outlettype" : [ "bang" ],
					"patching_rect" : [ 110.0, 57.0, 60.0, 20.0 ],
					"text" : "loadbang"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-21",
					"maxclass" : "newobj",
					"numinlets" : 2,
					"numoutlets" : 2,
					"outlettype" : [ "bang", "bang" ],
					"patching_rect" : [ 110.0, 84.0, 67.0, 20.0 ],
					"text" : "onebang 1"
				}

			}
, 			{
				"box" : 				{
					"fontname" : "Arial",
					"fontsize" : 12.0,
					"id" : "obj-20",
					"maxclass" : "newobj",
					"numinlets" : 3,
					"numoutlets" : 3,
					"outlettype" : [ "bang", "bang", "" ],
					"patching_rect" : [ 110.0, 227.0, 74.0, 20.0 ],
					"text" : "select 0 1"
				}

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

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

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-35", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-21", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-21", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-22", 0 ]
				}

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

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-23", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-24", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-29", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-27", 0 ]
				}

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

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-44", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-35", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-46", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-44", 0 ]
				}

			}
, 			{
				"patchline" : 				{
					"destination" : [ "obj-20", 0 ],
					"disabled" : 0,
					"hidden" : 0,
					"source" : [ "obj-46", 0 ]
				}

			}
 ],
		"dependency_cache" : [  ]
	}

}
```