This is now superseded by what is described in this post of a second iteration for a solution.. I’ve left this old iteration for reference only, and might later delete it.
In several OSC enabled applications, the namespace is very dense, and can comprise a tree-structure hierarchy with obvious repetition. Below is an example from Resolume Arena:
- /composition
- /composition/columns
- /composition/columns/n (1 – 9)
- /composition/layers
- /composition/layers/n (1 – 3)
- /composition/layers/n/clips
- /composition/layers/n/clips/n (1 – 9)
- /composition/layers/n/video
- /composition/selectedclip
- /composition/selectedlayer
- Etc.
Currently in OSC Query and other discovery protocols, there is some provision for describing such hierarchies.
In the Ossia library there is a mechanism where a node communicates the bounds of the sub-instances it can contain: “Instance Bounds”.
If min==max, it has no sub-instances. Otherwise, any sub-node can be treated as an instance. For example, columns, layers, and clips in Resolume. Or fixtures in the MadMapper namespace.
This is quite imperfect, just as is the analogous .1-.n notation of libossia’s OSC Query implementation, in that the node can only hold sub-instances, not a mixed sub-hierarchy. e.g., /shapes/cicle1, shapes/circle2, shapes/square1, shapes/square2, for instance.
It also doesn’t cover the use case of instances of the same sub-class also elsewhere in the hierarchy – e.g. that /someothershapes/othercircle1, is of the same type as /shapes/circle1.
Moreover, namespaces of complex applications grow very-very large, where often the size is due to repetition, e.g. when for each MadMapper fixture, all of its sub-namespace is repeated, per instance.
The TWO software implements a solution to these points, but one which doesn’t currently have any automatic discovery support, but requires manual setup by the end-user.
Instead of treating an application as having one big namespace, in TWO the big namespace can be split into several sub-namespaces. These can then be assembled into a separate tree-structure of “Addresses” in TWO - where a “Root Address” is a combination of a Namespace and IP/Port “Location”, and which can then have several sub-addresses, each of which can have its own OSC “Address Part”, and an optional Namespace.
So for example, the above Resolume hierarchy, becomes the separate namespaces of:
- Layer
- Clip
- Column
- Resolume
To represent the full namespace of Resolume through this model, the following “Address” hierarchy is created:
- Resolume {Resolume}
- Composition {null}
- Layers {null}
- Layer1 {Layer}
- Clips {null}
- Clip1- Clip9 {Clip}
- Temp {Clip}
- Clips {null}
- Layer2 (>>>)
- Layer1 {Layer}
- Columns {null}
- Column1 – Column9 {Column}
- Layers {null}
- selectedClip {Clip}
- selectedLayer {Layer}
- Composition {null}
The Root Address “Resolume” should have Namespace Resolume. “Layer1” etc and “selectedLayer” should have Namespace Layer. Clip1 through Clip9, and selectedClip, should be of namespace Clip. Column1 through Column9, namespace Column. “Composition”,” Layers”, “Clips”, “Columns”, should all not have a Namespace assigned at all, only an OSC Address Part, as they only serve for grouping.
SInce the purpose of this text isn’t to explain how TWO works in detail I’ll leave that part out. If you want to try the above, the creation and use of such a structure with Resolume, along with example .two files, is available here.
Finally, just to illustrate the above in TWO screenshots:
Before: One Big Namespace
After: Many Separate Namespaces…
And an address hierarchy linking them together.
Now to the interesting part - how can the above be made compatible with Discovery?
Discovery of Namespace & Address Hierarchies
Address as a name can stay as a placeholder, but I’d be more than happy for suggestions, and would then gladly change it also in TWO.
The solution can be separated into two sub-tasks - receiving separate namespaces instead of current functionality, and receiving an Address hierarchy of such namespaces.
Receiving separate namespaces
For each namespace, OSC Query is sufficient as-is, just that there is a need for a mechanism to transmit several.
At its simplest form, since all namespaces are defined at the same hierarchy level, would be a container node/”osc address part”, distinguished by a flag stating that all sub-namespaces are to be treated as separate. This is different to “Instance Bounds” only in that there is no hierarchy between them.
To receive these there can be a boolean Attribute to the OSC Query request sent, to distinguish between asking for several split namespaces, or the default current functionality.
NAMESPACE_HIERARCHY for example.
Receiving Hierarchy of Namespaces (Addresses)
This is analogous to extensions proposed a few years ago to OSC, of having OSC nodes that are “meta” nodes - the name eludes me. What I propose is I believe an improvement, in that the standard OSC specification is untouched and still fully compatible, in the spirit also of OSC Query.
This can be a separate OSC Query request Attribute, or the last Namespace received from a NAMESPACE_HIERARCHY request.
It can reuse the OSC Query format, but doing away with most of the attributes, down to only these:
DESCRIPTION
FULL_PATH
CONTENTS
NAMESPACE
NAMESPACE is the only new attribute proposed, and will be the name of the namespace from those returned with the NAMESPACE_HIERARCHY request. It can either be a string, or use the json null type to indicate that it is only a “container” of sub-addresses, and doesn’t reference any namespace itself.
{
“DESCRIPTION”: “root node”,
“FULL_PATH”: “/”,
“CONTENTS”: {
“resolume”: {
“DESCRIPTION”: “…”,
“FULL_PATH”: “/resolume”,
“NAMESPACE”: “Resolume”,
“CONTENTS”: {
“composition”: {
“DESCRIPTION”: “…”,
“FULL_PATH”: “/resolume/composition”,
“NAMESPACE”: Composition,
“CONTENTS”: {
“layers”: {
“DESCRIPTION”: “…”,
“FULL_PATH”: “/resolume/composition/layers”,
“NAMESPACE”: null,
“CONTENTS”: {
“layer1”: {
“DESCRIPTION”: “…”,
“FULL_PATH”: “/resolume/composition/layers/layer1”,
“NAMESPACE”: Layer
},
“layer2”: {
“DESCRIPTION”: “…”,
“FULL_PATH”: “/resolume/composition/layers/layer1”,
“NAMESPACE”: Layer
}
}
}
}
}
}
}
}
}
Discussion
I find this proposal solves many of the problems with large OSC namespaces with little overhead, and maintaining compatibility both with the original OSC spec, and OSC Query.
As it is, my above proposal only details requesting the full namespaces, but that is only for the sake of brevity. It seems straightforward for it to easily be extended so that only a single sub-namespace can be extended for example, or so that sub-addresses are created and deleted, essentially using the already defined optional Attributes of OSC Query for dynamic namespace manipulation and querying.
Let me know what you think in the thread below!