Open Sound Control?

I just started a project where I need to use the Open Sound Control protocol, but so far it looks like it’s way over my head.

Has anyone developed a plug-in that handles OSC?

John,
I’m in that same boat. Where did you end up? Find anything?
Thanks

I wrote an app that uses OSC about a year ago to control the EQ on a Midas or Behringer Mixer. It listens for OSC commands from one EQ and sends it to the others that are linked to it.
Here’s a link to a video about it. https://youtu.be/qYHIWLzCfuM
What are you trying to do?

Hey there.

Took a look at your app and it seems extremely useful. Nice job!

I have two apps: 1 Host (Mac/PC), and a hundred or so Clients(Linux/PIs). Host and Client currently communicate via UDP with a set of custom structured string commands but I would like to use OSC instead. That way I can use something like TouchOSC or integrate this into other apps, like Vezr.

// Simplified snippet of Client code.
UDPSocket1.Write("192.168.1.2","UD;RDY;1.0;192.168.1.3;1;1;0;1") 

Main core questions currently are:

  • How do I build the OSC command, ready for sending? It doesn’t look like just plain text. I’ve tried reading the specs at http://opensoundcontrol.org/spec-1_0 but get lost quick.
  • How would I parse the OSC command so I can use it? I bet that If the above bullet is solved, I can easily split or parse the data.
  • I’ve read about OSC Bundles and would like to use that too! How would I build a OSC bundle vs OSC message?

Here is some OSC commands I would like to use:
To specific IP:
/ud/move?m1=10 - Motor1, turn clockwise 30
/ud/move?m1=20&m2=-10 - Motor1: turn clockwise 20; Motor2: turn counterclockwise 10

To broadcast:
/ud/reportin - “Hey everyone on the network, tell me who you are”
/ud/ready?ver=1.0&ip=192.168.1.10&mot1=ready;mot2=ready;mot3=ready;mot4=offline - “reporting for duty”

Thanks for looking at this.

Part of what you’ll need to find out is what the receiving app can handle - is it expecting keystrokes, or blocks of text, or encapsulated data of some kind? Once you know that, you can send it.

After spending the past 12 hours on this, I’ve gotten to the point that the incoming data is:
/motors/control/5???,f???E?
-or-

The data shows up in monitoring apps like TinyOSC/OSCDataMonitor/etc as:
/motors/control/5 f 0.832386

I know an OSC packet is broken down thus:

  • /some/text/etc
  • some question marks. Nulls?
  • comma to start the data type identifiers followed by f for float, i for integer, s for string etc
  • some question marks. Nulls?
  • who knows afterward.

Now I’m trying to figure out how to parse it and handle whatever those questionmarks are, as well as how to separate the data if there are more data type identifiers. I’m at the point of giving up and going back to using my own method and tossing the OSC approach away.

So frustrating!

Check out opensoundcontrol.org, I got a document from there (“The Open Sound Control 1.0 Specification”) that includes basic info on OSC packets (including charming details such as the size of a packet is always a multiple of 4) and Address Spaces and OSC Addresses.

It also tells you that “i” is int32, “f” is float32, “s” is OSC-string, and “b” is OSC-blob. Also “d”, “h”, “t”, etc. To my mind, it was very confusing but I did eventually manage to wrangle it.

So that should be your first read. I wrote my own code to handle the whole thing, but at this point it’s part of a commercial product and I’m not at liberty to share it.

There is a Xojo module called AduroOSC, which I used briefly - but it wasn’t 64 bit at that point, so I wrote my own. I don’t know if it’s publicly available anywhere or not.

Getting closer. Just learned about Xojo’s memoryblock and am still diving deeper.

For OSC Packet: /motors/control/1 F 0.12345

Code thus far:

In the UDPSocket1 DataAvailable:

Dim d As DataGram
d = UDPReceive.Read

Dim mb As New MemoryBlock(0)
mb = d.Data

Dim tAddress, tType, tArguments as String

//Parse Incoming OSC Message.
' Get the Address
tAddress=mb.CString(0) // tAddress is now "/motors/control/1"

' Get the Type
tType = mb.CString(InStr(d.Data, ",")) //tType is now "F"

'Parse the Arguments, based on Type.
' TODO  Need to figure out how to parse tType (there can be multiple types such as IFSB, and more but are not official.
' TODO  Need to figure out where the byte is in the memory block, how to associate it with tType and how to get accurate data in

Having developed a commercially used module to handle this- the memory block data type is your friend. The spec McKernon mentioned answers a lot of your questions about argument data; remember that the packets are 32 bit aligned so you may need to shed some useless stuffing.

I’ll email you privately with a copy of my code and post the github here for future visitors when it’s fit for public consumption.

Thanks Sean!

TC,
What I did was create a class with the UDPSocket as it’s base.
I then used the UDPSocket1. ReadData to look for the type of data I was interested in and raised my own event when it was present. I then used memcpy to put it into a useful form.

Next, I overrode the write function with several versions. That way, I could pass it whatever I needed (strings, integers, blobs, etc) and let the compiler figure it out.

I would be happy to share it with you. You are welcome to use it as is, modify it or just incorporate what you need. Let me know how I could get it to you if you are interested.

PS I ay have the names of the methods wrong. I haven’t looked at this in about a year…

Martin: Would love to take a look! Can you send it my way?
Thanks!

I can send it today. Can you PM your e-mail address to me?
PS I grew up just outside of DC in the MD Burbs

Small World! PS: The traffic hasn’t gotten any better!
PM Sent. Thanks.

Hey there;

Found this thread in a search, wondering if anyone would be willing to share their Xojo code for parsing OSC messages? Save me reinventing the wheel!
Thank you.

Ok, real basic, no proper error checking and only s/f/i types (all I need for this project) and all messages are in #bundles in my case.

Works for parsing though, so it’s a good start for anyone looking to do this.

OscMsg Class: (Properties are: Address (String), Len (Integer), Param (String), Type (String))

Sub Constructor(M As MemoryBlock)
M.LittleEndian = False ' OSC uses Big-Endian

Address = M.CString(0).Trim

Dim Pos As Integer = ((Address.LenB \ 4) + 1) * 4 

If Chr(M.Byte(Pos)) <> "," Then
  MainWindow.ShowStatus("Type (Comma) not found")
  Return
End If

Type = M.CString(Pos + 1).Trim

Pos = Pos + ((Type.LenB \ 4) + 1) * 4

Select Case Type
Case "s"
  Param = M.CString(Pos).Trim
  Len = Pos + ((Param.LenB \ 4) + 1) * 4
Case "f"
  Param = Str(M.SingleValue(Pos))
  Len = Pos + 4
Case "i"
  Param = Str(M.Int32Value(Pos))
  Len = Pos + 4
End Select

End Sub

OSCBundle Class: (Properties Are: Address (String), Msgs() (OscMsg), Time (Int64))

Sub Constructor(M As MemoryBlock)
Dim MsgLen As UInt32
Dim MO As MemoryBlock

M.LittleEndian = False ' OSC uses Big-Endian

Address = M.CString(0).Trim

Dim Pos As Integer = ((Address.LenB \ 4) + 1) * 4 

If Address.Left(1) = "#" Then
  
  MainWindow.ShowStatus(Address)
  
  Time = M.Int64Value(Pos)
  
  Pos = Pos + 8
  
  While Pos < M.Size
    
    MsgLen = M.UInt32Value(Pos)
    Pos = Pos + 4
    MO = M.StringValue(Pos, MsgLen)
    Msgs.Append(New OSCMsg(MO))
    Pos = Pos + MsgLen
    
  Wend
  
End If
End Sub