Everything about Jamoma Modular 0.6

The next version of Modular framework is based one a new library : the NodeLib.

The NodeLib is made to represent any environment structure as tree of Node
and retrieved them via a Node Directory.

A Node Directory is useful to maintain the tree structure, observe any creation
or destruction and access quickly to a Node using osc addresses (with wildcard eventually).

Another important feature of Jamoma 0.6 is about Peer Object Model in order
to share the work done in Jamoma. So the last part introduces the work on a
Peer Object Model for Modular 0.6 and explains how this framework is now
available elsewhere than in Max/MSP.

How to get Modular 0.6

  1. Use the Mac installer

or

  1. Checkout on the 0.6-alpha branch for Modular framework.
    (Max/MSP implementation is only available for Mac because the framework is temporary broken on Windows)
    cd Modules/Modular
    git checkout --track remotes/origin/0.6-alpha (only the first time)
    git checkout 0.6-alpha
    git pull
    
  1. Build Modular frameworks using the script in the Modular folder :
    ./build.rb Deployment clean
    
The following externals have been completely redesigned :
  • jcom.hub have been renamed into jcom.model or jcom.view
  • jcom.parameter/message/return
  • jcom.send, jcom.receive
  • jcom.in/out(~)
  • jcom.init
  • jcom.map
  • jcom.ui
  • jcom.cuemanager

A focus on three brand new externals :

  • jcom.namespace allows Max developers to explore the tree structure looking for specific objects (using attribute values as criteria)
    and outputing the formated result to fill an umenu.
  • jcom.preset handles the preset part of 0.5's jcom.hub but it is in a separate external (it would create /preset node for you model)
  • jcom.remote is directly and remotely connected to a jcom.parameter/message/return in order to send/receive value to/from it.
    This external is also registered in the namespace with the same name than the parameter/message/return it binds.
  • jcom.modular allows to manage communication protocoles (OSC, Minuit, Copperlan, ...) to handle a Jamoma patches and other applications
    By default the loaded configuration allow you to control a patch sending OSC messages to the 8002 port.
  • An overview of the Modular 0.6 way of patching is available in /documentation/examples, it will help getting into Jamoma Modular 0.6

How to move on Modular 0.6 in Max

Modular 0.6 break the jcom.hub <> jcom.parameter relation ship, The way the registration is done
is totally new and allows a new way of patching (even if the former way still works after few changes).
Example patches are available into the documentation/example folder.

Here is a kind of FAQ about how to do things with the Modular 0.6.

  1. Modify all modules using jcom.send jcom.remote.module.to : this is doesn't work anymore because you could use wilcard now.
    There would be a lot of missing features here so... let me know.
  2. Modify all modules using jcom.receive jcom.remote.module.from : this is doesn't work anymore because you could use wilcard now.
    There would be a lot of missing features here so... let me know.

How To keep old Jamoma 0.5 patches working

  1. Rename jcom.hub into jcom.model
  2. Remove jcom.in(~) <---> jalg.patch message connection (the second one from the right).
    The jcom.in/out is now only used for signal input/output.
    If the jcom.in was only used for message driving remove it.
  3. Connect the leftmost output of jcom.model <---> jalg.patch
    I know this is ugly but now this way of patching doesn't make sens because hub/model and parameters/messages/returns should be into the algorithm.
    This should introduce double sends when a message will be sent to the hub/model...
  4. Add a jcom.preset external
    Just create it near the hub/model but you don't need to make any connection.
    Without a jcom.preset in your patch, your model could not have state memorisation.
  5. If your model has a panel : directly connect the second outlet of jcom.ui <---> [p inspector].
    This will create an internal /view/panel message.
  6. jcom.ui doesn't need to be configured to display mix, mute, gain,.... It look into the namespace of your model to know if they exists.

Note
it's really hard to be sure that all users Jamoma patching ways are still available. Let's me know if you have troubles during this transition.

How to change namespace exploration mechanism using the Modular 0.6

Former Components Modular 0.6 way
jcom.getModuleNames jcom.namespace @filter/list model
jcom.getParameterNames jcom.namespace @filter/list parameter
jcom.getMessageNames jcom.namespace @filter/list message
jcom.getReturnNames jcom.namespace @filter/list return
jcom.getAllAttributes jcom.namespace @output attributes
jcom.getOneAttribute jcom.receive
jcom.moduleDumper (?)
jcom.namespaceBrowse (?)
jcom.osc2opml jcom.namespace with message write and writeagain (broken)
(new feature) jcom.namespace @output children
(new feature) jcom.namespace @output brothers

Modules already modified

The following modules have been completely ported to 0.6 :

  • mouse
  • degrade~
  • sur.multi.in~
  • sur.multi.out~
  • sur.dbap~

Some new modules have been designed (they may be unfinished) :

  • mapperMulti
  • mapperBCF

About Peer Object Model development

One important feature of Jamoma 0.6 is about Peer Object Model in order to share the work done in Jamoma as C++ class instead of code using the Max API.

For the Modular framework this means the basic elements and mechanisms of modularity made in Max have to be transferred in C++ classes using the Foundation framework.

So, as you can read, the following explanations would be more for C++ developers than Max patchers...

Let's start by Foundation...

The NodeLib is made to represent any environment structure as tree of TTNode and retrieved them via TTNodeDirectory using directly /absolute/osc/address. This is based on two main TTElement of TTFoundation framework : the TTNode and TTNodeDirectory.

A TTNode allows environment builders to register any TTObject. The TTNodeDirectory is useful to maintain the tree structure, observe any creation or destruction and access quickly to a TTNode using osc addresses (optionally with wildcards).

Note : in the NodeLib an osc address is like /parent/name.instance:attribute The .instance part is mainly important because each TTNode sorts all his children in a hash table of names that points on hash tables of instances. There are also some OSC parsing tools.

Next step : Modular Framework

The Modular framework is a set of C++ classes stored in /Modular/library/PeerObject
to provide high level objects like :

TTApplicationManager : the main object of a Modular environment. It manages the local
application and other distant applications using communication plugins (like OSC, Minuit or Copperlan).

TTApplication : It creates a TTNodeDirectory,have version attribute and allows to load
conservion names table to have specific attribute names. It also contains communications
parameters depending on the plugin it uses.

TTData : to expose a value of an environment to control it or return it.
There is also a lot of features inside like RampUnit, Function, Dataspace, ... (see code for more info)

TTContainer : it binds on a part of the namespace and watches all TTData and TTContainer below
itself. TTContainer allows a relative osc address access. It can also generate a html description of his content.

TTSubscriber : to register any TTObject object in a TTNodeDirectory. The registration mechanism allows environment builders to describe elements as part of a Context inside another Context above up to a Top Level Context. A Context could be a patcher in Max or Pure Data, an html page or any modular part of an environment. A Context is just a pointer to a structural element of an environment. the TTSubscriber registration mechanism uses Context list that environment builder has to provide to register a Data, a Container or any TTObject.
A Subscriber could also exposed Attributes and Messages of TTObject as TTDatas and registered them into the namespace.

TTSender : set attribute's value of a registered TTObject.

TTReceiver : observes attribute's value of a registered TTObject.

TTViewer : this object is just embedded a TTSender and a TTReceiver.

TTMapper and TTMapperManager : to map Data's value on another by looking at their attributes to see if it's possible and scale the result.

TTPreset and TTPresetManager : to store Data's value, recall them, write them as xml files or load ones. The way a TTPreset is filled, updated, sorted and recalled is specific to the application.

TTCue and TTCueManager : to store a group of TTPresets, recall them, write them as xml files or load ones.

TTExplorer : to explore the namespace, to be notified of creation, destruction. The exploration can be done using criteria to precise TTObject types, attributes name and value that TTExplorer have to keep.

TTInput and TTOuput : it is used to drive any signal and exposed his attributes. There is no signal processing inside this class.

TTTextHandler and TTXmlHandler : read/write a description of a TTObject. To be handled by those class a TTObject has to implement writeAsText/readFromText or writeAsWml/readFromXml methods.

A first implementation example: Modular in Max

Except the some of one, all the classes are wrapped into jcom. external to load them in a Max patcher.
This wrapping mechanism is supported by /Modular/supports/max/TTModularClassWrapperMax files.

This wrapper is kindly the same as TTClassWrapperMax (which contains more audio class features...)
and allows developpers of TT Modular Class implementation in Max to declare specifics things
during the Class creation time (like class_addmethod) and instance creation time too (like deal with
arguments or make outlets).

As you can read in the TTModularClassWrapperMax, a wrapper declares automatically TTObject
attributes as Max attributes, TTObject messages as Max messages and set up all things that
have to be made in a Max external code.

Currently there is :

  • jcom.model | jcom.view : this is a wrapped TTcontainer registered in the tree using a TTSubscriber.
  • jcom.parameter/message/return : this is a wrapped TTData registered in the tree using a TTSubscriber.
  • jcom.send : it works. Now the attributes of the external are : 'address' and 'attribute' (instead of 'name')
  • jcom.receive : it works. Now the attributes of the external are : 'address' and 'attribute' (instead of 'name')
    There is still the 'enable' attribute.
  • jcom.map : which does what it did before and can binds on parameters/messages/returns to control/listen them remotely.
  • jcom.preset : this is a wrapped TTPresetManager. His messages are exposed in the tree using a TTSubscriber.
  • jcom.cuemanager : this is a wrapped TTCueManager. His messages are exposed in the tree using a TTSubscriber.
  • jcom.namespace : this is a wrapped TTExplorer.
  • jcom.modular : this is a wrapped TTApplicationManager.
  • jcom.remote : this is a wrapped TTViewer. It provides a design to manage the selection state of a gui pressing the shift key.
  • jcom.in(~) : this is a wrapped TTInput.
  • jcom.out(~) : this is a wrapped TTOutput.

Other implementations

Here is a huge question : Is it possible in Pure Data or other environments too ? Is the Peer Object Model
really available and are TTSubscriber, TTData and all other features too Max oriented or a real generic
proposition to build environment and expose control access ?

This is a call for anyone wants contribute to this development !

For instant Laurent Garnier (from Blue Yeti) is developing using Peer Objects.