strange tractor
Javascript Argument library

The following standardised library for handling argument setup is being implemented using the new #include mechanism.

This library provides the same argument and attribute parsing as non-javascript patchers. Arguments are read in order, and associated with the correct variable. Attributes (named @ATTRIBUTE/value pairs) are properly named and declared, and behave the same way as patcher attributes.

Syntax example
-----------------------------------------------
include("<argHandler>");

args = new argHandler;
// note - declare arguments in order;
var ARG1 = 100;
args.setUpArgument("ARG1");
// match declaration with setUpArgument line

var ARG2 = 0;
args.setUpArgument("ARG2");

// note - attributes can be declared in any order;
var ATTR1 = 100;
args.setUpAttribute("ATTR1");
// match declaration with setUpAttribute line

args.argumentParser(jsarguments);
// required : reads supplied arguments

args.reportAttributes();
// posts all attributes as per a non-js patcher

-----------------------------------------------

Note : the nature of argument and attribute handling requires eval() calls. These are minimised as much as possible, to one per argumentParser() call, and one per reportAttributes() call. argumentParser() is only called when the js/jsui object is initialised, and reportAttributes() should only be used within the standardised getstate() function call.


Javascript Inlet/Outlet library

The following standardised library for handling inlet and outlet setup is being implemented using the new #include mechanism.

Syntax example
-----------------------------------------------
include("<IOletHandler>");

iolet = new IOletHandler;
// note - declare inlets and outlets in order!
iolet.declareInlet("inlet1");
iolet.declareOutlet("outlet1");
iolet.declareOutlet("outlet2");

iolet.setupIOlets();

-----------------------------------------------


Javascript Includes Part2

Having implemented an include mechanism, and a main javascript code template, it made sense to develop a standard include-file template as well. When starting to do so, I took the time to tidy up the original code template, including standardising a certain amount of descriptive documentation.

One thing that became clear was that the amount of comments et.c. added significantly to the size of an included file. As a result, I decided to provide a method for removing this overhead, in the form of a 'cleaned' include file, stripped of comments and extraneous whitespace. A 'clean' include file would be file-suffixed '.h.js', and the 'full' version, used for code maintenance would retain the '.js' suffix. The original include code was modified to use a 'clean' include file first, if present, or, in its absence, the 'full' version.

To simplify the process of 'cleaning' header files, a simple perl utility, called strippa was written capable of generating a 'clean' include file from every javascript file in directory. The utility is also capable of modifying the self-reporting 'post' messages in include files.

The revised requirements for an include file are thus:

Requirements:

  • The same code fragment for the function include() must be present in javascript using includes.
  • Include files with comments should be named in the form name.js.
  • Include files with comments should contain the start and end lines
    post("included IOletHandler.js\n");
    and
    post("including IOletHandler.js\n");
    to aid in debugging
  • Streamlined include files, cleaned of comments etc should be named in the form name.h.js.
  • Include files without comments should contain the start and end lines
    post("included IOletHandler.h.js\n");
    and
    post("including IOletHandler.h.js\n");
    to aid in debugging


Javascript Includes

A basic #include type functionality was implemented to allow the easier and more modular development of Javascript within MAX/MSP. This would allow the use of reusable Javascript code in a clean and straightforward fashion,

The #include functionality was modelled after the C preprocessor, allowing the inclusion of local Javascript files as well as those in a central 'library' location (chosen to be %MAXROOT%/Cycling '74/jsincludes)

Requirements:

  • The same code fragment for the function include() must be present in javascript using includes.
  • Include files should be named in the form name.h.js.
  • Include files should contain the start and end lines
    post("included IOletHandler.h.js\n");
    and
    post("including IOletHandler.h.js\n");
    to aid in debugging

The use of this mechanism is as follows
includes = ""; clear include buffer
include("<library>"); loads library.h.js from %MAXROOT%/Cycling '74/jsincludes/
include("local"); loads local.h.js from same folder as parent .js file
eval(includes); interprets the code
includes = ""; frees up buffer

This code should have been fairly straightforward, but issues with line-end characters caused a certain amount of headscratching. The current code, which grabs lines one at a time, might be slower, but it more forgiving of EOL issues. The implementation reads all the included module code into a single buffer then evals() it. That uses a higher memory footprint, but less processing overhead.


Javascript in MAX/MSP

Having decided there were numerous advantages in using Javascript within MAX/MSP for the development process, it became important to consider the development process.

After carrying out some brief tests to ensure that the jsui was indeed capable of handling the kind of UI interactivity required, I concentrated on structuring my Javascript development in a more convenient and rationalised manner.

One of the first stages was sidestepping the very limited coding envirinment included in MAX (a very primitive text editor) in favour of the Komodo IDE, and use of the command

this.autowatch = 1;

which causes MAX/MSP to reload a js or jsui object when it has been modified. This combination meant that I could edit documents in a fully-fledged IDE, with minimal overhead.


Javascript Standardised IO methods

The following functionality was developed to allow a consistent approach to MAX/MSP IO from a js/jsui object:

  • inlet/outlet declarations - set up an inlet or outlet and tooltip in one line

    declareInlet("tooltip for the first inlet");
    declareOutlet("tooltip for the first outlet");
    declareOutlet("tooltip for the 2nd outlet");

  • argument handling - set up an argument, and its default value, in two lines. all object argument-value pairs are correctly parsed at object creation time.

    var ARGUMENT1 = 127;
    setUpArgument("ARGUMENT1");

    var ARGUMENT2 = 0;
    setUpArgument("ARGUMENT2");

  • attribute handling - set up an attribue, and its default value, in two lines. all object attributes are correctly parsed at object creation time, all attributes can be queried with getstate, and set/read with appropriate messages

    var ATTRIBUTE1 = "RGBA";
    setUpAttribute("ATTRIBUTE1");

  • pattr data storage/retrieval(*) - standardises storage and retrieval routines for use with pattr messages.



(*)not fully implemented as yet

Javascript standardised code

The following public functions have been or will be implemented in the template as 'hardcoded' methods, or stubs, providing handling of a standardised MAX message set.

(hardcoded public functions)

  • getstate() - return all attribute values
  • getvalueof() - return state for pattr handling
  • setvalueof() - set state for pattr handling

(stubs for public functions)

  • anything() - respond to uncaught messages
  • bang() - handle 'bang' messages
  • loadbang() - handle loadbang state
  • msg_int() - handle integer values as messages
  • msg_float() - handle float value as messages
  • list(array) - handle data lists as messages

The following private functions are implemented in the template as 'hardcoded' methods, or stubs, to support the implementation of the standardised MAX message set.

(hardcoded private functions)

  • generic_assistance() - used in inlet/outlet handling
  • declareInlet() - used in inlet/outlet handling
  • declareOutlet() - used in inlet/outlet handling
  • setUpArgument() - used in argument/attribute handling
  • argumentParser() - used in argument/attribute handling
  • attributeCheck() - used in argument/attribute handling
  • setUpAttribute() - used in argument/attribute handling
  • validateAttribute() - used in argument/attribute handling
  • reportAttributes() - used in argument/attribute handling

(stubs for private functions)

  • flatten() - used in pattr handling
  • inflate() - used in pattr handling

Some of these methods are implemented using 'eval', which is known to be inefficient. All of this usage of eval currently occurs at the initialisation stage, but a method for avoiding repeated calls to eval is required. This may be resoved by my intention to try and implement #include functionality, which also replace the need for hardcoded functions.


Javascript : template js document

Javascript maps slightly awkwardly to the MAX/MSP paradigm, but much has been provided to provide a framework which 'hooks in' to the MAX box/patcher model. However, I realised that much of the code required to handle this would be duplicated from one js/jsui object to the next, so one of the first taks I undertook was to develop a 'template' javascript document, which was (a) well structured and (b) contained as much useful reusable io functionality as possible.

The current implementation of this template provides a consistent framework for the development of new javascript objects, with the folllwing advantages

  • consistent style and layout
  • clear division of code into distinct functional sets
    • load-time initialisation code
    • MAX-usable external methods - standard methods
    • MAX-usable external methods - object-specific methods
    • private methods - standard methods (not to be edited)
    • private methods - object-specific
  • standard in-code documentation style
  • provision of consistent support methods
  • provision of consistent 'stub' methods for expected normal MAX messages
  • support methods allowing cleaner and more consistent IO setup


Reboot...

June 2012
Officially restarting the Strange Tractor site from scratch.