Category: OSC

Arduino + WiFly sends OSC

 
OSC is a widely used protocol for wireless communication between devices.  Arduino is a tremendously popular platform to create physical computing devices.  So naturally, one would think that engaging in OSC communication using Arduino’s would be straight-forward and well documented.  Unfortunately, I found very little help on the internet on this topic.  Most searches led to one of two existing methods to get OSC out of an Arduino:
 
1.  Using Processing as a middleman – this requires sending data from the Arduino over serial to a computer running Processing, which then generates and transmits OSC.  So to talk between two Arduino’s, an entire computer is required?  No good.
 
2.  Using the Ethernet Sheild and a library called ArdOSC – excellent stuff, but this library is written to work with the ethernet library only, and I’m using an RN-XV WiFly module.  No wires.
 
Neither of these solutions worked for me so I figured this is a topic worth exploring further.  Previously, I had been able to use the RN-XV to send raw data over UDP.  OSC data is also transmitted over UDP, so it should just be a matter of correctly generating OSC on the Arduino.
 
Start Simple
 
To test this hypothesis, I took some simple OSC from OpenSoundControl.org
 2f (/)  6f (o)  73 (s)  63 (c)
69 (i) 6c (l) 6c (l) 61 (a)
74 (t) 6f (o) 72 (r) 2f (/)
34 (4) 2f (/) 66 (f) 72 (r)
65 (e) 71 (q) 75 (u) 65 (e)
6e (n) 63 (c) 79 (y) 0 ()
2c (,) 66 (f) 0 () 0 ()
43 (C) dc (Ü) 0 () 0 ()

The byte array equivalent in C for Arduino looks like this:

char data[] = {0x2f, 0x6f, 0x73, 0x63, 0x69, 0x6c, 0x6c, 0x61, 0x74, 0x6f, 0x72, 0x2f, 0x34, 0x2f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x00, 0x2c, 0x66, 0x00, 0x00, 0x43, 0xdc, 0x00, 0x00};

Since this is kind of difficult to look at and work with, we can instead use char arrays.  Char arrays can be more readable, but how do you convert a float to a char array?  There’s a neat “trick” to do this in C using the union keyword.  Here’s some working Arduino code for sending OSC messages with a single float argument.  The first message sends 0.1, the next 0.2, and so on until 1.0 is reached and then it’s reset back to 0.1.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include "RNXV.h"
 
RNXV rnxv = RNXV();
float f;
union u_tag {
  byte b[4];
  float fval;
} u;
void setup() {
  f = 0.1;
 
  Serial.begin(9600);
  Serial1.begin(9600);
 
  rnxv.setUart(&Serial1);
  rnxv.join("SSID_HERE","PASSPHRASE_HERE");
  rnxv.enableUdp("192.168.1.5", 3000, 4000);
  rnxv.sendCommand("join", "AOK");
  Serial.println(rnxv.ip());
}
void loop()
{
  delay(1000);
  if (f > 1) f = 0;
  f = f + 0.1;
 
  char data[32] = "/oscillator/4/frequency\0,f\0\0";
  u.fval = f;
  data[28] = u.b[3];
  data[29] = u.b[2];
  data[30] = u.b[1];
  data[31] = u.b[0];
 
  Serial.print("print use loop: ");
  for (int i = 0; i <= 31; i++){
    Serial.print(data[i]);
  }
  Serial.println();
 
  rnxv.sendOsc(data, 32);
}

The code references an RN-XV library I’ve been working on to set up UDP and send the byte array as follows:

1
2
3
4
5
6
void RNXV::sendOsc(char data[], int size)
{
  for(int i = 0; i < size; i++)
    _uart->print(data[i]);
  delay(75);
}

I tried various delays and a delay of 75 seemed just enough that there wouldn’t be any corrupted OSC messages even when running the code for hours. This delay and the minimal code above resulted in about 13 OSC messages transmitting per second.  It is also necessary to loop and send the exact number of chars as a message contains, or else the receiving end doesn’t recognize the end of the message and throws errors.

 
On the receiving end, I once again used the sample app that comes with Cinder and it’s OSC Cinder block.  See the “Listening with Cinder” section in this post to see how to run the sample app, no code is required.  (Note that you may need to restart the app once because at first it inadvertently receives a message “exit” which is the RN-XV going into data mode).  If everything is working you should see a window like this one where the white section slowly expands:

 

 OscPkt and AVR-STL

At this point, having proved the concept, I was about to dive into writing my own library to generate the OSC, but thought I’d try one last time to find something off the shelf to do this.

OscPkt, the minimalittlest OSC library for C++ seemed perfect for the job, being super concise and all contained in a single header file. It also was not tightly coupled with any UDP library so I could use my sendOsc function (above). However it depended heavily on C++ Standard Library classes (like vector) which don’t exist for Arduino.

Except they do – a brilliant piece of work by Andy Brown is AVR-STL. It brings STL to Arduino. He has all the instructions on his blog post.  Simply download and put all header files in the include folder into …arduino-1.0.1\hardware\tools\avr\avr\include.  

Once AVR-STL was integrated, I took oscpkt.hh, renamed it to oscpkt.h and added the following two #includes at the top (as per the instructions found on the AVR-STL page):

1
2
#include 
#include

Then placed it in a folder “oscpkt” which I threw into my Arduino “libraries” folder. Now you can add the following to any Arduino sketch:

1
2
3
4
5
6
7
8
9
#include "oscpkt.h"
setup() {
  oscpkt::Message msg;
  oscpkt::PacketWriter wr;
  msg.init("/foo");
  wr.init().addMessage(msg);
  Serial.println(wr.packetSize());
  Serial.println(wr.packetData());
}
 
Previous posts about this project include the following topics:
 
1.  A low-cost and easy Robot Chassis to serve as the body of the robot.
2.  Adding a RN-XV WiFly Module to enable wi-fi connectivity.
3.  A Python Server which communicates with the robot.
4.  Adding a Sensor and Actuator and transmitting data as JSON.
 
In #3 and #4, I utilized a Python Server with JSON as the data format.  Here we try out a C++/Cinder Server with OSC as the communication protocol.
 

 

Ableton Live Talks OSC to Cinder

The goal here is to have Ableton Live transmit all track data and user actions to a C++ program which can use that data to generate unique visuals.  If you want to create interactive visuals for a music performer, the obvious way is to use a live audio feed.  However you can only do so much with such a feed and visuals end up only responding to the master level.  With the help of a tool called LiveOSC, it’s possible to get OSC data out of Ableton Live.  OSC or Open Sound Control is a data format which is usually transmitted over a wifi using a protocol called UDP, and this data can be picked up by a C++ application.  In this case we’re using a C++ framework called Cinder and the OSC is interpreted into visualizations.  This OSC data can tell us stuff like:

– when the set begins or ends
– when each beat occurs (as in once a second for 60 bpm)
– when any track level or the master level is changed
– when the user switches to the next track
– when the user tweaks any knob

I’m using the following tools to accomplish this task.

Ableton Live 8.2.6 (OSX in my case)
LiveOSC
Cinder
XCode or VisualStudio 2010 (or Eclipse which I’m using, but that’s a whole other topic)

Ableton Live gets LiveOSC

LiveOSC is a simple way to get OSC data out of Live.  It’s hosted here by its creator:

There’s not much help on the site, but it really is that simple to get it working.

1. install python 2.5.1 (Do not skip!)
2. place LiveOSC in Live.App/Contents/App-Resources/MIDI Remote Scripts/
3. go to Preferences -> MIDI Sync and select LiveOSC as a Control Surface

Live should now be transmitting OSC data over UDP on port 9001, as well as listening on port 9000.  However we don’t yet have a way of listening to the transmission.  You could probably use some sort of network monitoring tool to check if it’s working.  But it’s actually easier to proceed with setting up the next tool, Cinder, since it comes with a sample app called OSCListener which will pick up this OSC data and parse and display it.

[As an aside, by default LiveOSC seems to transmit to it’s own host machine’s IP, my next goal is to make it transmit to a different IP]

Listening with Cinder

Cinder is an excellent C++ framework that makes it a breeze to make complex interactive and visual apps. You can download it for free and it comes with many sample apps as well as a set of tutorials by a talented artist, Robert Hodgin.  My preferred way of setting up Cinder is with Git, using these instructions.

Once you are setup correctly, you should be able to launch any of the sample apps that the Cinder library comes with.  Go into cinder/blocks/osc/samples/OscListener/ and then launch either the Xcode or VS2010 app depending on your platform of choice.

Now in the source file OscListenerApp.cpp, make one simple change.  Look for the following line and change the port number from 3000 to 9001:

listener.setup(9001);

Now run OscListenerApp and then go to Ableton Live and move the master level slider up and down.  You should see some OSC data pop up in you Xcode console!

The master level slider will also effect the OscListener app screen.  The white part of the window should extend to the right as you increase the volume.  This slider will have this effect while others may not.  In the code the simple visual effect is only performed when the first argument is a float.

Making sense of the OSC

I’m still figuring out the nitty gritty of interpreting the OSC messages from LiveOSC.  Most of it is pretty self explanatory.  Here’s an example.  The output is reformatted so it looks more readable (to me)
 
–> /live/play  #args:1  [0]int32: 2  
–> /live/beat  #args:1  [0]int32: 1  
–> /live/beat  #args:1  [0]int32: 2  
–> /live/beat  #args:1  [0]int32: 3  
–> /live/beat  #args:1  [0]int32: 4  
–> /live/beat  #args:1  [0]int32: 5  
–> /live/beat  #args:1  [0]int32: 6  
–> /live/scene  #args:1  [0]int32: 3  
–> /live/clip/info  #args:3  [0]int32: 0  [1]int32: 2  [2]int32: 3  
–> /live/beat  #args:1  [0]int32: 7  
–> /live/clip/info  #args:3  [0]int32: 0  [1]int32: 1  [2]int32: 1  
–> /live/clip/info  #args:3  [0]int32: 0  [1]int32: 2  [2]int32: 2  
–> /live/beat  #args:1  [0]int32: 8  
–> /live/beat  #args:1  [0]int32: 9  
–> /live/beat  #args:1  [0]int32: 10  
–> /live/beat  #args:1  [0]int32: 11  
–> /live/play  #args:1  [0]int32: 1

Things to note:
– we get a message on start and stop with the address /live/play
– we get a message on every beat with the address /live/beat
– we get a message when switching tracks with the address /live/clip/info
– the last argument in some cases is an int that represents the following values:

0 = empty
1 = stopped
2 = playing
3 = triggered

So the 3 /live/clip/info messages were sent when I triggered the new clip, the old clip stopped, and the new clip started.

TouchOSC talks to Cinder

This section is not really related to the above, but is another simple proof of concept.  Another way to send OSC signals to a Cinder app is to use your phone.  Just install an app called TouchOSC (free on Android, $5 and more full featured on iOS).  Make sure your phone and computer are connected to the same wifi network, open up TouchOSC, and configure it with the following settings:

Host: 192.168.1.2             Port (outgoing):  9001
Port (incoming):  9000

Now just start up one of the touch layouts in TouchOSC, start up your OscListener app, and like magic, you should see messages coming in to your Cinder app.