[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [sc-dev] More OSCresponder issues
There is an improved version of OSCresponderNode which is simpler and
much faster. (posted on this list earlier).
James wrote that it would be better to do a primitive and a tree
class as it was in SC2, but I'm not sure exactly how to best go about
this.
Before doing improvements on OSCresponderNode as it is now,
I think it would be better to spend the time making sure the improved version
works reliably in all situations. I've tested it, but it would be
good to give it another try.
this was th code:
_____________
OSCresponder {
classvar <>all, <>forward, localhost="127.0.0.1";
var <addr, <cmdName, <>action, <signature;
*new { arg addr, cmdName, action;
^super.newCopyArgs(addr, cmdName.asSymbol, action).init;
}
init { signature = this.class.makeSignature(addr, cmdName) }
*initClass {
all = IdentityDictionary.new;
}
*removeAll { all.makeEmpty }
*makeSignature { arg addr, cmdName;
^if(addr.notNil) {
(cmdName.asString + addr.port +
(addr.hostname ? localhost))
} {
cmdName
}.asSymbol
}
*respond { arg time, addr, msg;
var cmdName, signature;
#cmdName = msg;
signature = this.makeSignature(addr, cmdName);
//if(cmdName.asSymbol != 'status.reply') { signature };
// note: object.do(func) evaluates the function with obj as arg
// responder without addr (addr is nil)
all[cmdName.asSymbol].do { |item| item.value(time,
msg, addr) };
// responder at command name
all[signature].do { |item| item.value(time, msg, addr) };
// possible other usages
forward.value(time, msg, addr);
^true // I don't know what this is for
}
*add { arg responder; responder.add }
*remove { arg responder; responder.remove }
*removeAddr { arg addr;
all = all.reject { arg item;
item.addr == addr
};
}
value { arg time, msg, addr;
action.value(time, this, msg, addr);
}
add { all.put(signature, this) } // override in osc
responder node class.
remove {
var resp;
resp = all[signature];
if(resp.isSequenceableCollection) {
resp.remove(this);
if(resp.isEmpty) { all.removeAt(signature) };
} {
all.removeAt(signature);
}
}
removeWhenDone {
var func;
func = action;
action = { arg time, responder, msg, addr;
func.value(time, responder, msg, addr);
this.remove;
}
}
== { arg that;
^that respondsTo: #[\cmdName, \addr]
and: { cmdName == that.cmdName and: { addr ==
that.addr }}
}
hash {
^addr.hash bitXor: cmdName.hash
}
}
OSCresponderNode : OSCresponder {
add {
var resp;
resp = all[signature];
if(resp.isNil) { all[signature] = this } {
if(resp.isSequenceableCollection) {
all[signature] =
all[signature].add(this)
} {
all[signature] = [all[signature], this]
}
}
}
}
OSCpathResponder : OSCresponderNode {
classvar <>cmdPathIndices;
var <>path;
*initClass {
cmdPathIndices = IdentityDictionary.new;
cmdPathIndices.put('/b_set', #[1,2]);
cmdPathIndices.put('/b_setn', #[1,2]);
cmdPathIndices.put('/c_set', #[1]);
cmdPathIndices.put('/c_setn', #[1]);
cmdPathIndices.put('/n_set', #[1,2]);
cmdPathIndices.put('/n_setn', #[1,2]);
cmdPathIndices.put('/tr', #[1,2]);
cmdPathIndices.put('/n_end', #[1]);
cmdPathIndices.put('/c_end', #[1]); //
dummy OSC command
}
*new { arg addr, cmdPath, action;
cmdPath = cmdPath.asArray;
^super.newCopyArgs(addr,
cmdPath[0]).action_(action).path_(cmdPath).init;
}
action_ { arg func;
action = { arg time, responder, msg, addr;
if(this.matchPath(msg)) {
func.value(time, responder, msg, addr);
}
}
}
matchPath { arg msg;
cmdPathIndices[cmdName.asSymbol].do { arg i;
if(msg[i].notNil and: {
path[i].notNil } and: {msg[i] != path[i]}) { ^false }
};
^true
}
}
--
/*
Okay a further couple of things:
When OSCMultiResponder calls value on its nodes, it doesn't call
value directly on them, but rather bypasses them and goes to their
actions:
value { arg time, msg;
nodes.do({ arg node; node.action.value(time, node, msg) });
}
When doing this it doesn't pass the addr arg for some reason. Is this correct?
Also, I think there's a potential problem with the way in which
OSCresponders become nodes in an OSCmultiresponder when you add an
OSCresponderNode with the same command. If one calls remove on that
OSCresponder, then it will call remove on the set, and because of the
way == is defined this will remove the enclosing OSCMultiResponder,
which is not the desired behaviour. Am I correct here?
To be honest, I've never understood the point of having a responder
class which removes all other responders to the same message when
added. Especially given that this could obliterate something
automatically added that a class is depending on. Having this adds a
lot of complication to the responder system, and saves the user very
little work. Am I missing something?
Should we consider simplifying the system to just have
OSCresponderNodes and make removing old ones the responsibility of
the user if needed?
S.
*/
--
.