What if we want to transmit messages that involve multiple different OSC element types at once?
We'd want to model that as a struct, for example:
struct StatusMessage {
public int Action;
public float Energy;
public StatusMessage(int enumVal, float energy) { Action = enumVal; Energy = energy; }
}
Writing
Ideal API
var writer = new OscWriter();
var msg = new StatusMessage(1, 0.4f);
// the generic type should be implied in real code - this is to show it's generic
writer.Write<StatusMessage>(msg);
this OscWriter.Write<T> should work for any struct T that contains only:
fields that directly map to an OSC primitive / array of primitives (including non-standard types)
structs that recursively contain only fields matching the above rule
It would be nice if we could just constrain this T like where T: unmanaged, but lots of structs that would be valid OSC messages don't meet the unmanaged constraint.
Instead, i think we will have to rely on runtime errors.
I know how to do automated type-checking of projects via reflection in the Unity editor, but it's more hassle and code than i think is worth for this.
Implementation Details
As long as all fields of the struct map directly to an OSC primitive, then this is trivial, as OSC message have multiple fields.
struct OurOscMessage {
int NumberOf;
float DegreeOf;
}
becomes an OSC message with two fields: int then float.
this works recursively - as long as all contained structs' fields map directly to OSC primitives, trivial to do.
struct ComplexOscMessage {
int NumberOf;
float DegreeOf;
Vector3 Position;
}
becomes an OSC message with 5 elements:
oscWriter.Write(intValue);
oscWriter.Write(floatValue);
// next 3 are the Vector3 struct fields
oscWriter.Write(xFloat);
oscWriter.Write(yFloat);
oscWriter.Write(zFloat);
Array support
Arrays of primitives should be trivial.
struct IntBufferMessage {
int[] Data;
}
Serialization is fairly simple if the other size knows how to interpret the message:
1 OSC field of the proper type for each element in the array
foreach (int element in intBufferMsg)
{
oscWriter.Write(element);
}
However we may need to add Array type tags for some cases, where the receiver doesn't have the type definition of a message being received. OscCore doesn't really support this yet
// this runs during type tags writing step
const msgData = new int[16]; // assume this is real data not zeros
const intElemTags = new String("i", msgData.Length);
const string intArrTypeTags = $"[{intElemTags}]";
// actual array value serialization functions just as before
foreach (int element in intBufferMsg)
{ oscWriter.Write(element); }
struct Element {
public int Number;
public Vector3 Position;
}
struct Message {
public Element[] Data;
}
serializes like:
const bufferMsg = new Element[16]; // fill with real data
// this runs during type tags writing step
// repeat the Element struct's type tags ("ifff", int then 3 floats for Vector3)
const intElemTags = new String("ifff", msgData.Length);
const string intArrTypeTags = $"[{intElemTags}]";
// actual array value serialization functions just as before
foreach (int element in bufferMsg)
{
oscWriter.Write(element.Number);
oscWriter.Write(element.Position);
}
Basics
What if we want to transmit messages that involve multiple different OSC element types at once?
We'd want to model that as a struct, for example:
Writing
Ideal API
this
OscWriter.Write<T>
should work for any structT
that contains only:It would be nice if we could just constrain this
T
likewhere T: unmanaged
, but lots of structs that would be valid OSC messages don't meet theunmanaged
constraint. Instead, i think we will have to rely on runtime errors. I know how to do automated type-checking of projects via reflection in the Unity editor, but it's more hassle and code than i think is worth for this.Implementation Details
As long as all fields of the struct map directly to an OSC primitive, then this is trivial, as OSC message have multiple fields.
becomes an OSC message with two fields:
int
thenfloat
.this works recursively - as long as all contained structs' fields map directly to OSC primitives, trivial to do.
becomes an OSC message with 5 elements:
Array support
Arrays of primitives should be trivial.
Serialization is fairly simple if the other size knows how to interpret the message: 1 OSC field of the proper type for each element in the array
However we may need to add Array type tags for some cases, where the receiver doesn't have the type definition of a message being received. OscCore doesn't really support this yet
array support should also mean that fixed-size buffers in unsafe structs work.
Arrays of structs
serializes like: