command line osc
Sometimes I just want a quick way to send some OSC (open sound control) messages around. I can jump into a Python command line and use simpleosc easily enough, I guess.
>>> import osc
>>> osc.init()
>>> osc.sendMsg("/stupidoscsynth", ["on", 0.2], “127.0.0.1?, 9596)
But I spend a lot of time at a *nix command line, and it would be nice to just run a command to send a message. Maybe something like this:
aturley@machine% args2osc "/stupidoscsynth" sf on 0.2 127.0.0.1 9596
The first argument (“/stupidoscsynth”) is the message address, the next argument (“sf”) says that this message has two arguments whose types are string and float, the next two arguments (“on” and “0.2″) are the message’s string and float arguments, and the last two arguments (“127.0.0.1″ and “9596″) are the destination host and port.
I probably could have just written a little Python script and been done with it.
import osc
import sys
def convert_element(in_element_type, in_element):
type_dict = {"i":int,
"f":float,
"s":str}
if type_dict.has_key(in_element_type):
return type_dict[in_element_type](in_element)
return None
if "__main__" == __name__:
osc.init()
osc.sendMsg(sys.argv[1], [convert_element(t, v) for t, v in zip(sys.argv[2], sys.argv[3:-2])], sys.argv[-2], int(sys.argv[-1]))
But hey, why not write it in C++ using oscpack?
#include <sstream>
#include <iostream>
#include <string>
#include <vector>
#include "osc/OscOutboundPacketStream.h"
#include "ip/UdpSocket.h"
using namespace std;
int StringToInt(string inString) {
istringstream buffer(inString);
int outInt;
buffer >> outInt;
return outInt;
}
float StringToFloat(string inString) {
istringstream buffer(inString);
float outFloat;
buffer >> outFloat;
return outFloat;
}
vector< vector<string> > ZipStrings(const vector<string> &a, const vector<string> &b) {
vector< vector<string> > v;
vector<string>::const_iterator ia = a.begin();
vector<string>::const_iterator ib = b.begin();
for (;
ia != a.end() && ib != b.end();
ia++, ib++) {
vector<string> vt;
vt.push_back(*ia);
vt.push_back(*ib);
v.push_back(vt);
}
return v;
}
vector<string> CStringToStringVector(const char *str) {
vector<string> v;
int len = strlen(str);
for (int i = 0; i < len; i++) {
v.push_back(string(1, str[i]));
}
return v;
}
int main(int argc, char *argv[]) {
if (argc > 4) {
vector<string> typeVector = CStringToStringVector(argv[2]);
vector<string> argVector;
for (int j = 3; j < argc - 2; j++) {
argVector.push_back(argv[j]);
}
vector< vector<string> > typeArgPairs = ZipStrings(typeVector, argVector);
int bufferSize = 2048;
char buffer[bufferSize];
osc::OutboundPacketStream p(buffer, bufferSize);
UdpTransmitSocket transmitSocket(IpEndpointName(argv[argc - 2], StringToInt(string(argv[argc - 1]))));
p << osc::BeginMessage(argv[1]);
for (vector< vector<string> >::iterator i = typeArgPairs.begin(); i != typeArgPairs.end(); i++) {
if ((*i)[0] == "i") {
p << StringToInt((*i)[1]);
} else if ((*i)[0] == "f") {
p << StringToFloat((*i)[1]);
} else if ((*i)[0] == "s") {
p << (*i)[1].c_str();
}
}
p << osc::EndMessage;
transmitSocket.Send(p.Data(), p.Size());
}
}
Assuming you already have the oscpack library installed, you can put this in a file called args2osc.cpp (or anything you want) and compile it like this:
g++ -o args2osc args2osc.cpp -l oscpack -I/usr/include/oscpack/
This is a pretty nice tool for testing programs that receive OSC messages. Maybe later I'll add support for bundles.