[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.
*/

--








.