Skip to content

Instantly share code, notes, and snippets.

@satoruhiga
Created September 23, 2011 00:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save satoruhiga/1236458 to your computer and use it in GitHub Desktop.
Save satoruhiga/1236458 to your computer and use it in GitHub Desktop.
ofxRecordableOscReceiver
#pragma once
#include "ofMain.h"
#include "ofxOsc.h"
#define OFX_RECOSC_SAVE_XML
#ifdef OFX_RECOSC_SAVE_XML
#include "ofxXmlSettings.h"
#endif
/*
#include "testApp.h"
#include "ofxRecordableOscReceiver.h"
ofxRecordableOscReceiver receiver;
float rotX = 0;
float rotY = 0;
void testApp::setup()
{
ofSetFrameRate(60);
ofSetVerticalSync(true);
receiver.setup(9001);
}
void testApp::update()
{
// same interface with ofxOscReceiver
while (receiver.hasWaitingMessages()) {
ofxOscMessage m;
receiver.getNextMessage(&m);
if (m.getAddress() == "/rot")
{
rotX = m.getArgAsFloat(0);
rotY = m.getArgAsFloat(1);
}
}
}
void testApp::draw()
{
glTranslatef(ofGetWidth()/2, ofGetHeight()/2, 0);
glRotatef(rotY, 1, 0, 0);
glRotatef(rotX, 0, 1, 0);
ofNoFill();
ofBox(0, 0, 0, 200);
}
void testApp::keyPressed(int key)
{
if (key == 's')
{
receiver.save();
}
else if (key == 'l')
{
receiver.load();
}
}
*/
/*
maxpat
----------begin_max5_patcher----------
942.3oc0YtsaaBCFG+5jmBKTuZJqEehC6t8bLUMQ.2TVIXD3nltp9tOiMjl1
lTLAGuzarEFpye98cx70mmOyaIeKqwC7Cvu.yl877YyTK0tvrtqm4sNYaZQR
i5w7R4qWyJEdKz2Sv1JTqWyR40Yfa.UEIOsLI8g9m3NdonI+ur1mBht1ua4x
MqyKKXB0tB6VrJQjded4peK2MgVUPHU92.Hj1QH0ucBIGA295Fw2H52o9sOO
SoJ9x+78.39RoLYsRJd+rNOovq8FuLed6vBCIPI6Q419A.TvSxVyZZ.694zx
R7TES+p34sSzSDJHjhFjn1oPz.LA9QlPicBSZXE.Hv+n.YYR4JuEuNaM.AgZ
BgUSjfAHD9.DJxtDRvWspfcTRjKCo1Wbi4sT6.Pw8iivMH7TdUZ8xSVw9f09
JHf56e5d+U0rFYpkDQNubu2x.+tXekUzua3vvBcbXQvwpsIPsMjP0EQihVD2
jHIujIeCONGWLcVFFNLKwCyxnPiBuPGfkT6xxykOoodW3H3D8tHgec7tL0Oo
mJmteBg5Dpv1VUCtJGJO+BDEdM3a.bf8yjQ6vQLZ3nO3vQeDcMNXz3q+SHeE
wpo.p2sC4e5.BaW.UkmJZJxyX0e5Q.V7YmDvjzOpQe+cSiHRCYQCeUxCfap4
Bo+8mlrwxIZPX0GKnqtMNCNNxMEjtIsfkTa8TKD8oiPD7jNjD1GqyPo+nK+w
WFCG5HN1H3UVGiXcpUDMZRXD4qCDiUS3S3z.3.6hw6J3xeyixK4sSD69RrSs
7FR6CBisQ4MDTERO3W7efTYXxEL7FYQrofAriBEqYOlWlY+bZA5B2jo8geHc
aR5BFIwiOXD8erW.GgMHbm2AYRwZcMRJjz6cM1xln.q5IUv4UfqfV2UpKmDh
BmlqjFWwQu1vkQ5I4ppiscg09UGiCsQ.ILfre0wfS.iTmkYqsq1m+1Gz2uRM
f6RXMNj3ltbuIqR5YjAJ3oIE2yaDfXeenk50OR2cJjlBPb33a1ugTPsgpdg7
t+4GJU0t9aQSCeScZuUuuA5fW0UFqQjWphW16gjIG2+gtOOKiUtuvWmmUwko
66DA31CZnLVSxxT.3PZh5dMMHmftUSgFno2I7ytlnFno1y05PMQHlvI2pIpQ
Zxs93DircX2pIrAZhD5VMYRbGww1NjA4LID2qoA4ja8mvl3OgeaAnytlHlpI
j6zjI06ba4Nb3kmjBt3jD5xyvgt7LbHSLbH2VVAQu7vD7LKI4EuL+evWkJJF
-----------end_max5_patcher-----------
*/
class ofxRecordableOscReceiver
{
typedef ofPtr<ofxOscMessage> ofxOscMessageRef;
typedef deque<ofxOscMessageRef> MessageList;
MessageList messageQueue;
ofxOscReceiver receiver;
bool recording, playback, looping;
unsigned int currentPlaybackFrame;
vector<MessageList> recordedMessages;
public:
ofxRecordableOscReceiver()
{
currentPlaybackFrame = 0;
recording = playback = looping = false;
}
// ofxOscReceiver interface
void setup(int listen_port)
{
receiver.setup(listen_port);
ofAddListener(ofEvents.update, this, &ofxRecordableOscReceiver::onUpdate);
}
bool hasWaitingMessages()
{
return !messageQueue.empty();
}
bool getNextMessage(ofxOscMessage* m)
{
if (messageQueue.empty()) return false;
*m = *messageQueue.front();
messageQueue.pop_front();
return true;
}
// record & playback interface
void play()
{
stop();
playback = true;
rewind();
}
void record()
{
stop();
recording = true;
clear();
rewind();
}
void stop()
{
recording = false;
playback = false;
}
void rewind()
{
currentPlaybackFrame = 0;
}
void clear()
{
recordedMessages.clear();
}
void loop(bool yn)
{
looping = yn;
}
void seek(unsigned int head)
{
currentPlaybackFrame = ofClamp(head, 0, recordedMessages.size()-1);
}
bool isRecording() const { return recording; }
bool isPlayback() const { return playback; }
void onUpdate(ofEventArgs&)
{
messageQueue.clear();
MessageList frameMessage;
while (receiver.hasWaitingMessages()) {
ofxOscMessage m;
receiver.getNextMessage(&m);
string addr = m.getAddress();
if (addr == "/record")
{
record();
}
else if (addr == "/play")
{
play();
}
else if (addr == "/stop")
{
stop();
}
else if (addr == "/rewind")
{
rewind();
}
else if (addr == "/seek")
{
seek(m.getArgAsInt32(0));
}
else if (addr == "/clear")
{
clear();
}
else if (addr == "/loop")
{
loop(m.getArgAsInt32(0));
}
ofxOscMessage *mm = new ofxOscMessage(m);
frameMessage.push_back(ofxOscMessageRef(mm));
}
if (playback)
{
if (!recordedMessages.empty())
{
messageQueue = recordedMessages[currentPlaybackFrame];
currentPlaybackFrame++;
if (looping)
{
currentPlaybackFrame = currentPlaybackFrame % recordedMessages.size();
}
else
{
currentPlaybackFrame = ofClamp(currentPlaybackFrame, 0, recordedMessages.size()-1);
}
}
}
else
{
messageQueue = frameMessage;
if (recording)
{
recordedMessages.push_back(frameMessage);
}
}
}
#ifdef OFX_RECOSC_SAVE_XML
void save(string path = "")
{
if (path == "")
{
ofFileDialogResult res = ofSystemSaveDialog("recording.xml", "");
path = res.getPath();
}
ofFile f(path);
if (f.exists())
{
f.remove(false);
}
ofxXmlSettings xml(path);
xml.addTag("data");
xml.pushTag("data");
for (int i = 0; i < recordedMessages.size(); i++)
{
MessageList &l = recordedMessages[i];
if (!l.empty())
{
for (int k = 0; k < l.size(); k++)
{
ofxOscMessage &m = *l[k];
string path = m.getAddress();
int tagid = xml.addTag("message");
xml.setAttribute("message", "frame", i, tagid);
xml.setAttribute("message", "path", path, tagid);
xml.pushTag("message", tagid);
for (int j = 0; j < m.getNumArgs(); j++)
{
switch (m.getArgType(j))
{
case OFXOSC_TYPE_INT32:
{
int vid = xml.addValue("v", m.getArgAsInt32(j));
xml.setAttribute("v", "t", "i", vid);
break;
}
case OFXOSC_TYPE_FLOAT:
{
int vid = xml.addValue("v", m.getArgAsFloat(j));
xml.setAttribute("v", "t", "f", vid);
break;
}
case OFXOSC_TYPE_STRING:
{
int vid = xml.addValue("v", m.getArgAsString(j));
xml.setAttribute("v", "t", "s", vid);
break;
}
}
}
xml.popTag();
}
}
}
xml.popTag();
xml.saveFile();
}
void load(string path = "")
{
if (path == "")
{
ofFileDialogResult res = ofSystemLoadDialog();
path = res.getPath();
}
ofxXmlSettings xml(path);
xml.pushTag("data");
int num_tags = xml.getNumTags("message");
if (num_tags == 0) return;
int num_frames = xml.getAttribute("message", "frame", 0, num_tags-1);
recordedMessages.clear();
recordedMessages.resize(num_frames + 30); // post roll
for (int i = 0; i < num_tags; i++)
{
int frame = xml.getAttribute("message", "frame", 0, i);
string path = xml.getAttribute("message", "path", "", i);
ofxOscMessage *m = new ofxOscMessage();
m->setAddress(path);
xml.pushTag("message", i);
int num_value = xml.getNumTags("v");
for (int k = 0; k < num_value; k++)
{
string t = xml.getAttribute("v", "t", "", k);
if (t == "i")
{
m->addIntArg(xml.getValue("v", 0, k));
}
else if (t == "f")
{
m->addFloatArg(xml.getValue("v", 0.0, k));
}
else if (t == "s")
{
m->addStringArg(xml.getValue("v", "", k));
}
}
xml.popTag();
recordedMessages[frame].push_back(ofPtr<ofxOscMessage>(m));
}
xml.popTag();
}
#endif
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment