RT OSC User Manual
==================
Mark McCurry

RT OSC a library for simply using Open Sound Control messages in a realtime
context.

The C Layer
-----------

For basic use of OSC messages, there is very little reason to complicate things
more than needed.
As such each message is simply stored in a buffer and assumed to be contiguous
and stored properly.
All manipulations of the OSC packets can be done with fixed sized buffers in a
real time environment.

The simplest and most useful function is _rtosc_message()_, which allows for the
generation of OSC messages.

[source,C]
-----------------------------------------------------------------------
char buffer[64];
int len = rtosc_message(buffer, sizeof(buffer), "hello", "s", "world");
-----------------------------------------------------------------------

In this example _len_ now contains the length of the message and _buffer_
contains a well formed OSC message (or at minimum one that is self consistent
within this library).
To see the message, we can print the buffer and the zeroth argument:

[source,C]
-------------------------------------------------------
printf("%s %s!\n", buffer, rtosc_argument(buffer,0).s);
//hello world!
-------------------------------------------------------

As the OSC message consists of null delimited path, argument string, and
arguments, the path can be found at the start of the buffer and the argument can
be fetched to get the fields.

Other properties of this message can be found with library calls on the message
buffer.

[source,C]
-------------------------------
rtosc_narguments(buffer);
//1
rtosc_argument_string(buffer);
//"s"
rtosc_type(buffer, 0);
//'s'
rtosc_message_length(buffer);
//same as len from above
-------------------------------

While this is a fairly simple interface, which may appear restrictive, this
library's goal is to permit the simple use of basic RT OSC messages, nothing too
much more, so for more complex construction of messages, I recommend liblo.
This is not to say that all that all features are currently implemented.

For more complex messages there are also varargs and array versions of message

[source,C]
--------------------------------------------------------------------
rtosc_vmessage(buffer, sizeof(buffer), address, args, va_arguments);

rtosc_arg_t args[] = {
  {.s = "foo"},
  {.i = 1234},
  {.f = 1024.2}
}
rtosc_amessage(buffer, sizeof(buffer), "/path", "sif", args);
--------------------------------------------------------------------

//TODO message verification layer

The C++ Layer
-------------

Once you have an OSC message, that is nice, but not terribly useful.
As the primary motivation for this project is to ease the use of OSC for RT
audio, this layer provides several key features:

- A Thread Link, which makes transmitting messages over jack ringbuffers simple.
- An implementation of Ports for dispatching OSC messages to their destinations.
- A trivial midi lookup table for use with the Ports implementation

As this library is based upon the concept of using fixed sized buffers to avoid
memory allocation, and no size universally works, these classes are templates
with respect to their size.

ThreadLink
~~~~~~~~~~

For simple usage, calls to _write()_ replace any calls to _rtosc_message()_.
One thread is intended to call _write()_ when messages are sent and the other is
expected to periodically _read()_ all of the messages.

[source,cpp]
-----------------------------------------
ThreadLink link(1024,128);
link.write("hello", "s", "world");
link.hasNext(); //true
link.read(); //yields the hello:s:world message
-----------------------------------------

Ports
~~~~~

Defining all of the possible ways a message can be sent to various parts of an
audio application is next to impossible, so the implementation of Ports result
in a description of OSC methods handled by various patterns.
With trivial programs, one might want to establish one table of ports to
describe all of the possible connections, but this is not feasible for moderately
sized to large sized applications.
As such each set of ports defines one layer of a tree of ports statically.
As all of the data presented via the Port interface can be statically
specified, this means that the tree can easily be used as a read only data
structure by both the frontend and RT backend.

The _Port_ class defines one port which works on a OSC message and value.
Below is a simple example port.

[source,cpp]
----------------------------------------------------------------------------------------------
Port port("a_port:f", ":doc\0=Example port\0", [](const char*, RtData&){puts("port called")});
----------------------------------------------------------------------------------------------

The verbose way to read this is that this defines a port named "a_port" which
accepts messages of type "f" (float) with one mapped property which defines the
doc string "Example port" and a callback which is called at dispatch time.
The concise way is to state that port maps float messages to "a_port" to the
given function.

The justification for the use of std::function rather than just plain old function
is due to the recent addition of C\++11 lambda functions.
Let's look at how this can be used with classes:

[source,cpp]
----------------------------------------------------------------
#include <rtosc/ports.h>

class Foobar
{
    float a,b,c,d;
}

Ports ports = {
    {"a:f", "", NULL,
        [](const char *m, void *f){((Foobar*)f)->a = argument(m,0).f;}),
    {"b:f", "", NULL,
        [](const char *m, void *f){((Foobar*)f)->b = argument(m,0).f;}),
    {"c:f", "", NULL,
        [](const char *m, void *f){((Foobar*)f)->c = argument(m,0).f;}),
    {"d:f", "", NULL
        [](const char *m, void *f){((Foobar*)f)->d = argument(m,0).f;})
};
----------------------------------------------------------------

This is however quite verbose mainly due to the associated setter functions.
As this field is a std::function and not just a simple function pointer it is
possible to abstract this with a generated function (or a macro, though
generated functions lead to more _interesting_ possibilities).

One option is to use the included syntax sugar which simplifies the port
definitions massively.


[source,cpp]
----------------------------------------------------------------
#include <rtosc/ports.h>
#include <rtosc/port-sugar.h>

class Foobar
{
    float a,b,c,d;
};

#define rObject Foobar

Ports ports = {
    rParamF(a, "doc str"),
    rParamF(b, "doc str"),
    rParamF(c, "doc str"),
    rParamF(d, "doc str"),
};
----------------------------------------------------------------

There, that is a concise representation of those parameters.
This can be further complicated by adding multiple layers to the process of
dispatching an event.

[source,cpp]
----------------------------------------------------------------
#include <rtosc/ports.h>
#include <rtosc/port-sugar.h>

class Barfoo
{
    float e;
    static Ports ports;
};

class Foobar
{
    float a,b,c,d;
    Barfoo baz;
};

#define rObject Barfoo

Ports Barfoo::ports = {
    rParamF(e, "doc str"),
};

#undef  rObject
#define rObject Foobar

Ports Foobar::ports = {
    rParamF(a, "doc str"),
    rParamF(b, "doc str"),
    rParamF(c, "doc str"),
    rParamF(d, "doc str"),
    rRecur(baz, "doc str"),
};
----------------------------------------------------------------

For more detail on the exact methods you should see the doxygen output, or for
the moment the source itself (it doesn't bite much).

While the default syntax sugar might not quite work out, it is possible to
define any other method of generating ports.
Notably some C++ templates might help with the definitions though the results
will likely not be as concise as the provided macros.

Finally as this system is designed to facilitate static inspection of the
parameter trees, it is very easy to add metadata to the various parameters.
Consider defining a min and max value for a parameter with an associated midi
mapping.
This can be done with several levels of verbosity:

-----------------------------------------------------------------------------
Ports Foobar::ports = {
    rParamF(a, ":scale\0=linear\0:min\0=1\0:max\0=15.2\0", "a verbose port"),
    rParamF(b, rMap(scale,linear),
               rMap(min, 0),
               rMap(max, 15.2), "a macro mapped port"),
    rParamF(c, rLinear(0,15.2), "a concise port"),
};
-----------------------------------------------------------------------------

Based upon this basic decomposition it should not be difficult to see how
similar macros could be constructed to define port metadata which can be used
within the callback or anything that might want to reflect on the ports.

Path Specifiers
^^^^^^^^^^^^^^^

The rough specification for the grammar of the path specifiers is:

---------------------------------------------------------
argument_specializer_delimiter := ':'
range_specifier   := '#'
subport_specifier := '/'

path      := location subport
           | location subport arguments

subport   :=
           | '/'

location  := text
           | text '#' number

arguments :=
           | ':' types arguments

types     :=
           | type types
---------------------------------------------------------

A brief justification of this grammar can be summarized in a few points which
echo the sentiment make 99% of code simple and the 1% possible:

* Array fields are common in signal processing and the '#' specifier is a
  simple means of explaining the ranges
* While paths could be denoted outside of this string, it is concise to label
  them with '/' which is disallowed from the subpaths from the OSC 1.0 spec
* Type checking arguments is a PITA that can be reduced by formally specifying
  all possible argument types. This also provides information when the tree is
  statically traversed
* All other edge cases can be either explained in the metadata or via the
  behavior of the handling function

Metadata
^^^^^^^^

Looking at all of this you may notice that the metadata field of the port is
left blank every time.
This field is not shown as it would complicate the above examples and it is only
really useful when attaching other code to this idiom of a series of ports.
The roughly established grammar for this specifier is:

---------------------------------------------------------
property_start := ':'
value_start    := '='
text           := [^\0]

entry       :=
            | ':' text '\0'
            | ':' text '\0' '=' text '\0'

metadata    :=
            | entry
            | entry metadata
---------------------------------------------------------

Most of this data has been structured s.t. it is easy to allow some UI to hook
onto the data to eliminate some data redundancy and to permit documenting
parameters where they are defined rather than in the mist of some horribly
convoluted UI code.
This field does not necessarily need to conform to the above structure, though
port based extensions will expect the strings to roughly conform and all
examples should conform.

For an example of code using this format, see the Fl_Osc_* collection of widgets
and meta-widgets in the complex example.

MidiTable
~~~~~~~~~

As this system is designed to be fairly lightweight and the ports expose plenty
of metadata about what arguments are accepted by each port, a logical next step
is to enable some form of midi integration.
The miditable is designed to allow for midi learning and general midi mapping of
controllers.
All this really amounts to is mapping a <controller id, channel id> to <path,
type, conversion-function?>.

SubTree-Serialization
~~~~~~~~~~~~~~~~~~~~~

While loading new modules without interrupting the realtime thread is easy
enough through techniques like pointer swaps, saving a running set of parameters
can be trickier.
Through some port reflection and a lot of c string manipulation it is possible
to serialize arbitrary subtrees of the graph formed by the rtosc::Ports
structures.
This currently transforms a readable set of ports into a bundle which contains
all of the values needed to restore the state of the underlying structures.
As with most things with this library, this feature is still experimental.

NOTE:: Problems may exist with array fields

Undo Support
~~~~~~~~~~~~

As, all mutations are prsented to the rtosc dispatcher in a set of ordered
actions, adding undo support is fairly trivial.
Upon being presentd with a new value, a control can emit (along with its
update) an undo event, which defines the transition from old to new values.
These undo events can be used to form a linearized history which can be
rewound or replayed.
When a change occurs it is broadcast out to all listeners.

Each undo message consists of some path and a before/after pair of values.
For example +/undo/handler sff "/volume_dB" 0.7f 20.0f+ would result in an
event to change +/volume_dB+ from 7dB to 20dB.
This event can be inserted into the undo history via
_UndoHistory::recordEvent()_.

By using _UndoHistory::seekHistory(-1)_ this event can be reversed.

NOTE:: UndoHistory instances are NOT realtime safe



This basic idea is certainly ynot perfect, as it is very dumb to start with 

