[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [sc-dev] new OSCresponder



Here is an implementation of OSCresponder / OSCpathResponder / OSCresponderNode that uses symbol signatures for lookup. (I've added an extension to Main.sc tom amke the testing easier)

When going through more tests I've found two bugs in that version still,
sorry to have bothered you if anyone tried. The benchmarks are correct though, as well as most basic functionality.


I've tested all the helpfiles and gone through the test file again.

I think I'd like to commit the changes.






_____________
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
	}


}
--








.