JSON File Parser

When using javascript in MaxMSP you can query most of the attributes of the available objects. Things like the screen co-ordinates, the scripting name and whether the object is included in presentation mode. There are a few things that it cannot tell you with one example being the number of inlets or outlets an object has. One way to do this is to parse the file in the uncompressed text format. MaxMSP files are stored as JSON so reading them inside javascript isn’t too difficult. We can then query any of the values that you can see if you open a file as text. I’ve written a script to load in the parent patch and report object attributes in a few different ways. Here’s the code:

// includejson.js

outlets = 2;

var memstr;

function loadbang() {
	if(!max.loadbangdisabled) {
		init();
		outlet(1,this.patcher.filepath);
		outlet(1,1);
	}
}

function init() {
	memstr = "";
	data = "";
	maxchars = 800;
	target = this.patcher.filepath;
	f = new File(target,"read");
	f.open();
	if (f.isopen) {
		while(f.position<f.eof) {
			memstr+=f.readstring(maxchars);
		}
		f.close();
	} else {
		post("Error\n");
	}
	mem = eval("("+memstr+")");
	post("Loaded!\n");
}

function object(classtype,property) {
	for(i=0; i<mem.patcher.boxes.length; i++) {
		if ((mem.patcher.boxes[i].box.maxclass == classtype) || (mem.patcher.boxes[i].box.maxclass == "newobj" &&  mem.patcher.boxes[i].box.text.split(" ")[0] == classtype)) {
			outlet(0,mem.patcher.boxes[i].box[property] || "<undefined>");
		}
	}
}

function name(scriptname,property) {
	for(i=0; i<mem.patcher.boxes.length; i++) {
		if (mem.patcher.boxes[i].box.varname == scriptname) {
			outlet(0,mem.patcher.boxes[i].box[property]);
		}
	}
}

function query(property) {
	for(i=0; i<mem.patcher.boxes.length; i++) {
		if (mem.patcher.boxes[i].box[property]) {
			outlet(0,mem.patcher.boxes[i].box[property]);
		}
	}
}

function count(classtype) {
	num = 0;
	for(i=0; i<mem.patcher.boxes.length; i++) {
		if ((mem.patcher.boxes[i].box.maxclass == classtype) || (mem.patcher.boxes[i].box.maxclass == "newobj" &&  mem.patcher.boxes[i].box.text.split(" ")[0] == classtype)) {
			num++;
		}
	}
	outlet(0,classtype,num);
}

function anything() {
	all = arrayfromargs(messagename,arguments);
	for(i=0; i<mem.patcher.boxes.length; i++) {
		if (mem.patcher.boxes[i].box[all[0]] == all[1]) {
			outlet(0,mem.patcher.boxes[i].box[all[2]] || "<undefined>");
		}
	}
}

autowatch = 1;

// EOF

The first section will load the parent file into the object when the patch is opened, this can also be done with the “init” message. It will also turn on the [filewatch] object if it is connected to the second outlet, useful for auto-updating every time the patch is saved. The next section loads the JSON data. It uses the javascript eval function rather than JSON parsing code as we can be fairly sure that the file is formatted properly. Keep in mind that this could cause problems if you make any changes to the code or try to load a corrupted file. The following blocks define functions to describe certain messages which can be sent to the object. These are:

  • count [class]: reports how many objects of type [class] there are in the patch.
  • query [attribute]: outputs the value of the [attribute] for each object in the patch.
  • object [class] [attribute]: outputs the value of the [attribute] for each object of type [class] present in the patch.
  • name [varname] [attribute]: outputs the value of the [attribute] for each object named [varname] in the patch.
  • [attribute one] [value] [attribute two]: will output the value of [attribute two] for each object where [attribute one] is equal to [value]. For example “presentation 1 varname” will output all the scripting names of objects included in presentation mode.

Included below is an example patch, uncompressed so Max4 users have a chance of understanding it.

{
	"boxes" : [ 		{
			"box" : 			{
				"maxclass" : "newobj",
				"text" : "trigger 3 4 i f",
				"numoutlets" : 4,
				"outlettype" : [ "int", "int", "int", "float" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 288.0, 123.0, 77.0, 20.0 ],
				"numinlets" : 1,
				"id" : "obj-3",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "message",
				"text" : "presentation 1 varname, presentation 1 patching_rect",
				"linecount" : 2,
				"numoutlets" : 1,
				"outlettype" : [ "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 248.0, 31.0, 166.0, 32.0 ],
				"numinlets" : 2,
				"id" : "obj-17",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "message",
				"text" : "send",
				"numoutlets" : 1,
				"outlettype" : [ "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 167.0, 169.0, 37.0, 18.0 ],
				"numinlets" : 2,
				"id" : "obj-37",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "message",
				"text" : "message",
				"numoutlets" : 1,
				"outlettype" : [ "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 103.0, 169.0, 59.0, 18.0 ],
				"numinlets" : 2,
				"id" : "obj-30",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "newobj",
				"text" : "prepend count",
				"numoutlets" : 1,
				"outlettype" : [ "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 103.0, 192.0, 87.0, 20.0 ],
				"numinlets" : 1,
				"id" : "obj-24",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "newobj",
				"text" : "filewatch",
				"numoutlets" : 1,
				"outlettype" : [ "bang" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 141.0, 252.0, 57.0, 20.0 ],
				"numinlets" : 1,
				"id" : "obj-26",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "message",
				"text" : "bigtrig numoutlets",
				"numoutlets" : 1,
				"outlettype" : [ "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 65.0, 78.0, 105.0, 18.0 ],
				"numinlets" : 2,
				"id" : "obj-20",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "newobj",
				"text" : "prepend name",
				"numoutlets" : 1,
				"outlettype" : [ "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 65.0, 98.0, 88.0, 20.0 ],
				"numinlets" : 1,
				"id" : "obj-6",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "message",
				"text" : "trigger numoutlets",
				"numoutlets" : 1,
				"outlettype" : [ "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 47.0, 31.0, 107.0, 18.0 ],
				"numinlets" : 2,
				"id" : "obj-21",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "newobj",
				"varname" : "bigtrig",
				"text" : "trigger 1 2 hat bat cat -6578 \"hello world\"",
				"numoutlets" : 7,
				"outlettype" : [ "int", "int", "hat", "bat", "cat", "int", "hello world" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 288.0, 77.0, 227.0, 20.0 ],
				"numinlets" : 1,
				"id" : "obj-19",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "newobj",
				"text" : "trigger i f l",
				"numoutlets" : 3,
				"outlettype" : [ "int", "float", "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 288.0, 100.0, 63.0, 20.0 ],
				"numinlets" : 1,
				"id" : "obj-18",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "toggle",
				"varname" : "charles",
				"numoutlets" : 1,
				"outlettype" : [ "int" ],
				"presentation_rect" : [ 284.0, 249.0, 20.0, 20.0 ],
				"patching_rect" : [ 306.0, 167.0, 20.0, 20.0 ],
				"presentation" : 1,
				"numinlets" : 1,
				"id" : "obj-31"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "message",
				"numoutlets" : 1,
				"outlettype" : [ "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 405.0, 242.0, 50.0, 18.0 ],
				"numinlets" : 2,
				"id" : "obj-32",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "button",
				"numoutlets" : 1,
				"outlettype" : [ "bang" ],
				"patching_rect" : [ 469.0, 220.0, 20.0, 20.0 ],
				"numinlets" : 1,
				"id" : "obj-9"
			}

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

		}
, 		{
			"box" : 			{
				"maxclass" : "message",
				"text" : "hello, 12, 3.1415",
				"numoutlets" : 1,
				"outlettype" : [ "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 403.0, 178.0, 99.0, 18.0 ],
				"numinlets" : 2,
				"id" : "obj-14",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "newobj",
				"text" : "cycle 3",
				"numoutlets" : 3,
				"outlettype" : [ "", "", "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 403.0, 198.0, 85.0, 20.0 ],
				"numinlets" : 1,
				"id" : "obj-7",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "newobj",
				"text" : "send grumble",
				"numoutlets" : 0,
				"fontsize" : 12.0,
				"patching_rect" : [ 288.0, 247.0, 83.0, 20.0 ],
				"numinlets" : 1,
				"id" : "obj-33",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "newobj",
				"text" : "send two",
				"numoutlets" : 0,
				"fontsize" : 12.0,
				"patching_rect" : [ 288.0, 223.0, 59.0, 20.0 ],
				"numinlets" : 1,
				"id" : "obj-15",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "newobj",
				"text" : "send one",
				"numoutlets" : 0,
				"fontsize" : 12.0,
				"patching_rect" : [ 288.0, 199.0, 60.0, 20.0 ],
				"numinlets" : 1,
				"id" : "obj-34",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "message",
				"text" : "message text",
				"numoutlets" : 1,
				"outlettype" : [ "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 159.0, 31.0, 80.0, 18.0 ],
				"numinlets" : 2,
				"id" : "obj-36",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "message",
				"text" : "patching_rect",
				"numoutlets" : 1,
				"outlettype" : [ "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 148.0, 122.0, 83.0, 18.0 ],
				"numinlets" : 2,
				"id" : "obj-25",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "newobj",
				"text" : "prepend query",
				"numoutlets" : 1,
				"outlettype" : [ "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 84.0, 145.0, 88.0, 20.0 ],
				"numinlets" : 1,
				"id" : "obj-23",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "message",
				"text" : "numinlets",
				"numoutlets" : 1,
				"outlettype" : [ "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 84.0, 122.0, 62.0, 18.0 ],
				"numinlets" : 2,
				"id" : "obj-22",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "newobj",
				"text" : "prepend object",
				"numoutlets" : 1,
				"outlettype" : [ "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 47.0, 54.0, 90.0, 20.0 ],
				"numinlets" : 1,
				"id" : "obj-2",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "message",
				"text" : "init",
				"numoutlets" : 1,
				"outlettype" : [ "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 141.0, 274.0, 32.5, 18.0 ],
				"numinlets" : 2,
				"id" : "obj-8",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "newobj",
				"text" : "print fromjs",
				"numoutlets" : 0,
				"fontsize" : 12.0,
				"patching_rect" : [ 65.0, 252.0, 70.0, 20.0 ],
				"numinlets" : 1,
				"id" : "obj-4",
				"fontname" : "Arial"
			}

		}
, 		{
			"box" : 			{
				"maxclass" : "newobj",
				"text" : "js includejson",
				"numoutlets" : 2,
				"outlettype" : [ "", "" ],
				"fontsize" : 12.0,
				"patching_rect" : [ 65.0, 230.0, 95.0, 20.0 ],
				"numinlets" : 1,
				"id" : "obj-1",
				"fontname" : "Arial"
			}

		}
 ],
	"lines" : [ 		{
			"patchline" : 			{
				"source" : [ "obj-17", 0 ],
				"destination" : [ "obj-1", 0 ],
				"hidden" : 0,
				"midpoints" : [ 257.5, 215.0, 74.5, 215.0 ]
			}

		}
, 		{
			"patchline" : 			{
				"source" : [ "obj-8", 0 ],
				"destination" : [ "obj-1", 0 ],
				"hidden" : 0,
				"midpoints" : [ 150.5, 294.0, 56.0, 294.0, 56.0, 227.0, 74.5, 227.0 ]
			}

		}
, 		{
			"patchline" : 			{
				"source" : [ "obj-7", 2 ],
				"destination" : [ "obj-9", 0 ],
				"hidden" : 0,
				"midpoints" : [  ]
			}

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

		}
, 		{
			"patchline" : 			{
				"source" : [ "obj-7", 0 ],
				"destination" : [ "obj-11", 0 ],
				"hidden" : 0,
				"midpoints" : [  ]
			}

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

		}
, 		{
			"patchline" : 			{
				"source" : [ "obj-37", 0 ],
				"destination" : [ "obj-24", 0 ],
				"hidden" : 0,
				"midpoints" : [ 176.5, 189.0, 112.5, 189.0 ]
			}

		}
, 		{
			"patchline" : 			{
				"source" : [ "obj-36", 0 ],
				"destination" : [ "obj-2", 0 ],
				"hidden" : 0,
				"midpoints" : [ 168.5, 51.0, 56.5, 51.0 ]
			}

		}
, 		{
			"patchline" : 			{
				"source" : [ "obj-30", 0 ],
				"destination" : [ "obj-24", 0 ],
				"hidden" : 0,
				"midpoints" : [  ]
			}

		}
, 		{
			"patchline" : 			{
				"source" : [ "obj-26", 0 ],
				"destination" : [ "obj-8", 0 ],
				"hidden" : 0,
				"midpoints" : [  ]
			}

		}
, 		{
			"patchline" : 			{
				"source" : [ "obj-25", 0 ],
				"destination" : [ "obj-23", 0 ],
				"hidden" : 0,
				"midpoints" : [ 157.5, 142.0, 93.5, 142.0 ]
			}

		}
, 		{
			"patchline" : 			{
				"source" : [ "obj-24", 0 ],
				"destination" : [ "obj-1", 0 ],
				"hidden" : 0,
				"midpoints" : [ 112.5, 215.0, 74.5, 215.0 ]
			}

		}
, 		{
			"patchline" : 			{
				"source" : [ "obj-23", 0 ],
				"destination" : [ "obj-1", 0 ],
				"hidden" : 0,
				"midpoints" : [ 93.5, 215.0, 74.5, 215.0 ]
			}

		}
, 		{
			"patchline" : 			{
				"source" : [ "obj-22", 0 ],
				"destination" : [ "obj-23", 0 ],
				"hidden" : 0,
				"midpoints" : [  ]
			}

		}
, 		{
			"patchline" : 			{
				"source" : [ "obj-21", 0 ],
				"destination" : [ "obj-2", 0 ],
				"hidden" : 0,
				"midpoints" : [  ]
			}

		}
, 		{
			"patchline" : 			{
				"source" : [ "obj-20", 0 ],
				"destination" : [ "obj-6", 0 ],
				"hidden" : 0,
				"midpoints" : [  ]
			}

		}
, 		{
			"patchline" : 			{
				"source" : [ "obj-2", 0 ],
				"destination" : [ "obj-1", 0 ],
				"hidden" : 0,
				"midpoints" : [ 56.5, 215.0, 74.5, 215.0 ]
			}

		}
, 		{
			"patchline" : 			{
				"source" : [ "obj-14", 0 ],
				"destination" : [ "obj-7", 0 ],
				"hidden" : 0,
				"midpoints" : [  ]
			}

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

		}
, 		{
			"patchline" : 			{
				"source" : [ "obj-1", 1 ],
				"destination" : [ "obj-26", 0 ],
				"hidden" : 0,
				"midpoints" : [  ]
			}

		}
 ]
}

This might not be overwhelmingly useful to everyone but on the off chance that you’ve ever needed to know more than javascript has been willing to tell you before it could be helpful. It is meant to be used in an open patch rather than in a collective where the JSON is bundled in with everything else included in the .mxf file so unfortunately it won’t be much help if you’re dynamically scripting objects in a standalone.

There are other uses for this method. The JSON also includes patch cord information which you otherwise don’t get access to so it could be used to dynamically reconnecting or paste-replace objects programatical. The box details are included in order of creation so you could also get a patch to build itself step by step which could make for some interesting slideshow style tutorials.

About these ads

One thought on “JSON File Parser

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s