We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Hello,
I'm trying to implement a sensor based OSC controller. So far I've set up a handler for accelerometer events and I can see from the console output that accelerometer data is being captured properly in an onAccelerometerEvent handler. However, I haven't been able to send OSC directly from within the handler. I've seen e.g. in this example that, even though all necessary data is available within the handler, actual sending is done in the draw function. I've been able to do it like that in my own sketch as well but preferably I'd like to do it in the handler and not be dependant on the framerate at which the draw function executes. Why is it not possible to send OSC from within a sensor event handler? (or, if it is possible, what am I doing wrong?)
example code (I've moved over to AndroidStudio, so the below is translated back to processing - hope my code makes sense...)
import ketai.sensors.*;
import oscP5.*;
OscP5 oscP5;
NetAddress broadcastLoc;
OscMessage oscAcc;
KetaiSensor sensor;
void setup() {
oscP5 = new OscP5(this, 32000);
broadcastLoc = new NetAddress("192.168.1.5", 57120);
sensor = new KetaiSensor(this);
}
void draw() {
}
void onAccelerometerEvent(float x, float y, float z, long time, int accuracy) {
println("x: " + x + "\ny: " + y + "\nz: " + z + "\naccuracy: " + accuracy);
oscAcc = new OscMessage("/acc");
oscAcc.add(x);
oscAcc.add(y);
oscAcc.add(z);
println("broadcastLoc: " + broadcastLoc + "\nOSC msg: " + oscAcc + "\noscP5: " + oscP5);
try {
oscP5.send(oscAcc, broadcastLoc);
} catch(Exception e) {
// prints just "sending failed: null"
println("sending failed: " + e.getMessage());
}
}
Answers
Most hardware-based libraries create their own Thread in order to be run asynchronously.
In your example above, at the very least, both KetaiSensor & OscP5 got their own threads.
When onAccelerometerEvent() triggers, it's run under KetaiSensor's Thread I believe.
Then you instantiate a
new
OscMessage.BtW, I wonder whether it would be better to just do it once within setup(), rather than creating new 1s on-the-fly for each trigger under a foreign Thread? :-/
The problem w/ asynchronous execution is that we may end up interfering w/ another Thread at the wrong time. For example, by modifying its state when it's busy doing the same!
All Processing libraries expect the actual action to happen under the "Animation" Thread.
That's why accessing other threads from there is safest. O:-)
My advise is, rather than dealing w/ OscP5 under any foreign Thread, just flag that the action happened.
Then have an
if ()
block inside sketch's draw() to check thatboolean
flag, reset that flag, and execute the task. *-:)Thanks a lot for that explanation. I already suspected something like that. Maybe it's a good hint that you gave me about instantiating new OSC messages. I'll take a look. However, always having to send my OSC messages from within
draw()
isn't exactly satisfying, though I understand that's the concept behind processing and makes working with it easy for non (java) programmers. I'll investigate further...Of course we can always create a separate function for it and call it from within draw(). ;;)
@Stefan=== i tried your code (some errors in it, i had to import also netP5 && start the sensor in setup) && i have seen that you cannot send osc inside the sensor handler, probably for the excellent reasons given by @GoToLoop; so i created a method called in draw() and everything works fine;
@GoToLoop ===
if you instantiate the oscmessage only in set up each time you calll the method it adds the new values to its array which becomes quickly very memory expansive...
i dont know if it could be useful or useless to declare this method (in draw) as synchronized: i have tried the twos but seen no difference. Can you tell me? Thanks in advance.
But after quickly perusing its docs, I've found it's got a clear() method: :-bd
http://www.Sojamo.de/libraries/oscp5/reference/oscP5/OscMessage.html#clear()
synchronized
is an advanced Java keyword feature. A very big topic! :-SBut aFaIK, unless OscMessage's add() method is
synchronized
as well, placing them inside somesynchronized ()
block is 100% useless and just make them a lil' slower! :-&However, if by some miracle they happen to be
synchronized ()
, we have to use its instance reference as mutex for it.@GoToLoop===
right; using clear() (or clearArguments() rather) is probably a good solution && the best one if you want to save till a certain number of values (for reuse or...) from the oscMess; as for synchronized, looking to oscP5 source confirms that there is no "miracle"... So, as you say, it's useless in this kind of case! ;) Thanks!