I am afraid have gotten to your OSC messages a bit late, I can only 
read lists at web archives at present and the jack lists have been
down...

> * No service discovery. This is a big deal, but can be solved /if/ we

I don't know of a database, which I guess is not a good situation.
CNMAT might be interested in doing the basic administration required
for a port register.  I think that a database of static port numbers
is preferable to a dynamic system *if* it is workable.  If a dynamic
system were neccessary it should be implemented as an OSC server!  I
am actually not exactly sure what you mean by service discovery?

> I'm very happy to discussus a GPL'd library implementation or

I have had to do some work on the OSC implementation I have been 
using
in order to address two issues.  I think you will need to address
these with liblo also.  They are: 1. type coercion and 2. variable
argmument messages.  

I am going to attach the note I wrote about the implementation below,
which describes these in detail, but briefly on type coercion:

Given the message shape ("/foo/bar" "fi") as in the testlo.c file, a
receiver should match not only ("/foo/bar" "fi" 2.0 23) but also
("/foo/bar" "ii" 2 23) and ("/foo/bar" "if" 2 23.0) and in fact all
other possible numerical encodings, and provide them to the handler in
the form requested.

The work I have done *only* provides the byte string decoder and
encoder, but it does support all the extended basic OSC types and
numerical and string coercion.  I think you could use it as is if you
wanted, or of course just take whatever you need.  I will happily
implement/apply any changes/fixes required to make it usable for you.
The implementation is in the file 'osc.c' in the jack.clock or
jack.scope archives at <http://www.alphalink.com.au/~rd>.  It
works for me but is otherwise untested!

Apart from the above the design looks good, although personally I
agree with James McCartney, see SC3 or recent post to OSC_dev, that
combining the verb and the subject in the address is a bad idea, and
would prefer to see a library that discourages that use ;) (This would
also make the handler type declarations simpler...)

Regards,
Rohan

TN-16 - OSC C-Language Parser/Constructor

This note describes a C language OSC Parser/Constructor library.  The
library is designed for use in processes where the address space is
fixed and dispatch is argument based. [1]

The design requirements are that the library should:

  * be thread safe and re-entrant
  * not allocate any memory or call any other non-RT safe procedure
  * handle arbitrary length and variable length messages
  * provide all reasonable type coercion [2]
  * be efficient

There are three primary public interfaces, the type 'osc_data_t' and
the procedures 'osc_parse_message' and 'osc_construct_message'.  There
are two secondary public interfaces, the procedures 'osc_message_dsc'
and 'osc_match_dsc'.

'osc_data_t' is a union of all valid OSC argument types. The field
names are the same as the type characters.

typedef union
{
  int32_t i ;
  int64_t h ;
  uint64_t t ;
  float32_t f ;
  float64_t d ;
  const char *s ;
  const char *S ;
  uint32_t c ;
  uint32_t m ;
  uint32_t r ;
  struct { const char *data ; int32_t size ; } b ;
}
osc_data_t ;

'osc_parse_message' determines if an OSC message matches an address and
a type descriptor string.  If the message matches it parses the
arguments into a provided data array in host order type coherent form.

int32_t
osc_parse_message ( const char *addr , const char *dsc , 
                    const char *packet , int32_t packet_sz ,    
                    osc_data_t *data ) ;

'addr' is an address string.  For OSC compliance the address should
start with a forward slash.  'dsc' is a type string describing the
arguments that the message must match.  'packet' is the OSC message,
the message is 'packet_sz' bytes long.  'data' must be allocated to at
least as many places as there are type tags at 'dsc'.

If 'packet' matches 'addr' and 'dsc' the parser returns the offset to
the end of the arguments as described in 'dsc' at 'packet', else the
parser returns zero.

'packet' matches 'addr' iff the address strings are equal.  'packet'
matches 'dsc' iff the packet contains at least as many arguments as
given at 'dsc' and all of the encoded argument types can be coerced to
the requested types.  The parser implements type coercion between all
numerical types, and between all string types.

On a successful match the parser writes host order values for the
types given at 'dsc' to 'data'.  Any memory locations stored at
'data', for 's', 'S' and 'b' argument types, are of the read-only
storage at 'packet'.

Handling variable argument messages is only indirectly addressed by
this design, importantly it is not precluded.  The receiver can read
the type descriptor of the incoming packet using 'osc_message_dsc'.
The receiver can then evaluate this type descriptor against a
dynamically determined required type descriptor using 'osc_match_dsc',
which returns non-zero iff the type descriptors can be coerced one
into the other.  If the incoming packet is conforming the receiver
uses the dynamically determined type descriptor to parse the incoming
message.

'osc_construct_message' encodes an OSC message.

int32_t
osc_construct_message ( const char *addr , const char *dsc , 
                        const osc_data_t *data , 
                        char *packet , int32_t packet_sz )

'osc_construct_message' encodes 'addr', 'dsc' and the host order
arguments at 'data' as an OSC message writing to 'packet', which has
'packet_sz' places.  The return value is the number of bytes the
encoding uses, or zero if the encoding failed.  Aside from corrupt
'data' the encoding should only fail because 'packet_sz' is inadequate
to store the message.

This library is demonstrated in jack.clock, see
<http://www.alphalink.com.au/~rd>.  This library requires the
byte-order library documented in TN-15.

[1] This is the OSC subset advocated for by James McCartney and
implemented in SuperCollider.  This subset of OSC is in essence a
mechanism for byte encoding a typed vector with the requirement that
the first element be a string.  This subset does not combine the
operator and the subject in the OSC address, the OSC address is the
operator only and is matched using string equality.

[2] OSC parsers should be lenient about incoming arguments types.  OSC
parsers in languages where names refer to entities of fixed type
should not require a one to one relation between the type of the name
that is to be bound to an argument of an OSC message and the type of
the argument of the message.  It is, for instance, reasonable for a
process to encode all OSC numerical data as double precision floating
point.  Receivers should advertise that, for instance, a particular
message requires an unsigned integer argument as an index to a frame
buffer, but should accept that value in any numerical encoding.

Reply via email to