|
|
FluidProxyUgen : UGen {
|
|
|
|
|
|
var <>pluginname;
|
|
|
|
|
|
*kr { |pluginname...args|
|
|
|
^this.new1('control', pluginname,*args)
|
|
|
}
|
|
|
|
|
|
init { |pluginname...args|
|
|
|
this.pluginname = pluginname;
|
|
|
inputs = args;
|
|
|
pluginname
|
|
|
.asSymbol
|
|
|
.asClass
|
|
|
.superclasses
|
|
|
.indexOf(FluidRTDataClient) ??{inputs= inputs ++ [Done.none,0]};
|
|
|
rate = 'control';
|
|
|
}
|
|
|
|
|
|
name{
|
|
|
^pluginname.asString;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
FluidManipulationClient {
|
|
|
|
|
|
classvar clock;
|
|
|
|
|
|
var <server;
|
|
|
var <synth,<>ugen;
|
|
|
var id;
|
|
|
var defName, def;
|
|
|
var onSynthFree, keepAlive;
|
|
|
var aliveThread;
|
|
|
var postit;
|
|
|
|
|
|
*initClass {
|
|
|
clock = TempoClock.new;
|
|
|
clock.permanent = true;
|
|
|
}
|
|
|
|
|
|
*prServerString{ |s|
|
|
|
var ascii = s.ascii;
|
|
|
^[ascii.size].addAll(ascii)
|
|
|
}
|
|
|
|
|
|
*newFromDesc { arg rate, numOutputs, inputs, specialIndex;
|
|
|
^FluidProxyUgen.newFromDesc(rate, numOutputs, inputs, specialIndex)
|
|
|
}
|
|
|
|
|
|
*new{ |server,objectID...args|
|
|
|
server = server ? Server.default;
|
|
|
if(server.serverRunning.not,{
|
|
|
(this.asString + "– server not running").error; ^nil
|
|
|
});
|
|
|
^super.newCopyArgs(server ?? {Server.default});//.baseinit(objectID,*args)
|
|
|
}
|
|
|
|
|
|
makeDef { |defName,objectID,args|
|
|
|
var initialVals = [];
|
|
|
args!? { if(args.size > 0) {initialVals = args.unlace(2)[1].flatten}};
|
|
|
^SynthDef(defName,{
|
|
|
var ugen = FluidProxyUgen.kr(this.class.name, *(initialVals ++ objectID));
|
|
|
this.ugen = ugen;
|
|
|
ugen
|
|
|
});
|
|
|
}
|
|
|
|
|
|
updateSynthControls {}
|
|
|
|
|
|
baseinit { |objectID...args|
|
|
|
var makeFirstSynth,synthMsg,synthArgs;
|
|
|
id = UniqueID.next;
|
|
|
postit = {|x| x.postln;};
|
|
|
keepAlive = true;
|
|
|
defName = (this.class.name.asString ++ id).asSymbol;
|
|
|
def = this.makeDef(defName,objectID,args);
|
|
|
synth = Synth.basicNew(def.name, server);
|
|
|
synthMsg = synth.newMsg(RootNode(server),args);
|
|
|
def.doSend(server,synthMsg);
|
|
|
|
|
|
onSynthFree = {
|
|
|
synth = nil;
|
|
|
if(keepAlive){
|
|
|
synth = Synth(defName,target: RootNode(server));
|
|
|
synth.onFree{clock.sched(0,onSynthFree)};
|
|
|
this.updateSynthControls;
|
|
|
}
|
|
|
};
|
|
|
CmdPeriod.add({synth = nil});
|
|
|
synth.onFree{clock.sched(0,onSynthFree)};
|
|
|
}
|
|
|
|
|
|
free{
|
|
|
keepAlive = false;
|
|
|
if(server.serverRunning){server.sendMsg("/cmd","free"++this.class.name,id)};
|
|
|
synth.tryPerform(\free);
|
|
|
^nil
|
|
|
}
|
|
|
|
|
|
cols {|action|
|
|
|
action ?? {action = postit};
|
|
|
this.prSendMsg(\cols,[],action,[numbers(FluidMessageResponse,_,1,_)]);
|
|
|
}
|
|
|
|
|
|
read{|filename, action|
|
|
|
this.prSendMsg(\read,[filename.asString],action);
|
|
|
}
|
|
|
|
|
|
write{|filename, action|
|
|
|
this.prSendMsg(\write,[filename.asString],action);
|
|
|
}
|
|
|
|
|
|
size {|action|
|
|
|
action ?? {action = postit};
|
|
|
this.prSendMsg(\size,[],action,[numbers(FluidMessageResponse,_,1,_)]);
|
|
|
}
|
|
|
|
|
|
prSendMsg { |msg, args, action,parser|
|
|
|
if(this.server.serverRunning.not,{(this.asString + "– server not running").error; ^nil});
|
|
|
forkIfNeeded{
|
|
|
synth ?? {onSynthFree.value; server.sync};
|
|
|
OSCFunc(
|
|
|
{ |msg|
|
|
|
defer{
|
|
|
var result;
|
|
|
result = FluidMessageResponse.collectArgs(parser,msg.drop(3));
|
|
|
if(action.notNil){action.value(result)}{action.value};
|
|
|
}
|
|
|
},'/'++msg, server.addr, nil,[synth.nodeID]).oneShot;
|
|
|
server.listSendMsg(['/u_cmd', synth.nodeID, ugen.synthIndex, msg].addAll(args));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
FluidDataClient : FluidManipulationClient {
|
|
|
|
|
|
var synthControls;
|
|
|
|
|
|
var <id;
|
|
|
var parameters;
|
|
|
var parameterDefaults;
|
|
|
|
|
|
*new {|server|
|
|
|
^this.new1(server,#[])
|
|
|
}
|
|
|
|
|
|
*new1{ |server, params|
|
|
|
var uid = UniqueID.next;
|
|
|
^super.new(server, uid, *params) !? { |inst| inst.init(uid, params) }
|
|
|
}
|
|
|
|
|
|
init { |uid, params|
|
|
|
id = uid;
|
|
|
params = params ?? {[]};
|
|
|
if(params.size > 0 and: synthControls.isNil) {synthControls = params.unlace[0]};
|
|
|
parameters = ().putPairs(params);
|
|
|
parameterDefaults = parameters.copy;
|
|
|
this.makePropertyMethods;
|
|
|
this.baseinit(uid,*params);
|
|
|
}
|
|
|
|
|
|
makePropertyMethods{
|
|
|
if (parameters.keys.size > 0) {
|
|
|
parameters.keys.do{|c,i|
|
|
|
this.addUniqueMethod(c,{ parameters.at(c) });
|
|
|
this.addUniqueMethod((c++\_).asSymbol,{|responder,x|
|
|
|
//if we have a default or initial value set, then fall back to
|
|
|
//this if val is nil. Otherwise, fallback even furter to -1 as
|
|
|
// a best guess
|
|
|
x = x ?? { parameterDefaults !? { parameterDefaults[c] } ?? {-1} };
|
|
|
parameters.put(c, x.asUGenInput);
|
|
|
synth !? { if(synth.isRunning){ synth.set(c,x); } };
|
|
|
responder
|
|
|
});
|
|
|
}
|
|
|
};
|
|
|
}
|
|
|
|
|
|
|
|
|
makeDef {|defName,uid,args|
|
|
|
var defControls = synthControls;
|
|
|
var ugenControls = [this.class.name] ++ synthControls ++ uid;
|
|
|
|
|
|
var f = (
|
|
|
"{ |dataClient|"
|
|
|
" SynthDef("++defName.asCompileString++", { |" ++ defControls.join(",") ++ "|"
|
|
|
" var ugen = FluidProxyUgen.kr(" ++ ugenControls.join(",") ++ ");"
|
|
|
" dataClient.ugen = ugen;"
|
|
|
" ugen"
|
|
|
" })"
|
|
|
"}"
|
|
|
);
|
|
|
var res = f.interpret.value(this);
|
|
|
^res
|
|
|
}
|
|
|
|
|
|
updateSynthControls{
|
|
|
synth !? { synth.set(*parameters.asKeyValuePairs); };
|
|
|
}
|
|
|
}
|
|
|
|
|
|
FluidRTDataClient : FluidDataClient
|
|
|
{
|
|
|
|
|
|
|
|
|
*new1{|server, params|
|
|
|
params = params ?? {[]};
|
|
|
^super.new1(server,params)
|
|
|
}
|
|
|
|
|
|
|
|
|
init { |uid, params|
|
|
|
id = uid;
|
|
|
params = params ?? {[]};
|
|
|
if(params.size > 0) {synthControls = params.unlace[0]}{synthControls=[]};
|
|
|
params = params ++ [\inBus,Bus.control,\outBus,Bus.control,\inBuffer,-1,\outBuffer,-1];
|
|
|
parameters = ().putPairs(params);
|
|
|
parameterDefaults = parameters.copy;
|
|
|
this.makePropertyMethods;
|
|
|
this.baseinit(uid,*params);
|
|
|
}
|
|
|
|
|
|
makeDef {|defName,uid,args|
|
|
|
var defControls = [\inBus, \outBus] ++ synthControls ++ [\inBuffer,\outBuffer];
|
|
|
var ugenControls = [this.class.name,"T2A.ar(In.kr(inBus))"] ++ synthControls ++ [\inBuffer,\outBuffer,uid];
|
|
|
var f = (
|
|
|
"{ |dataClient|"
|
|
|
" SynthDef("++defName.asCompileString++", { |" ++ defControls.join(",") ++ "|"
|
|
|
" var ugen = FluidProxyUgen.kr(" ++ ugenControls.join(",") ++ ");"
|
|
|
" dataClient.ugen = ugen;"
|
|
|
" Out.kr(outBus,ugen);"
|
|
|
" })"
|
|
|
"}"
|
|
|
);
|
|
|
var res = f.interpret.value(this);
|
|
|
|
|
|
^res
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
FluidServerCache {
|
|
|
|
|
|
var cache;
|
|
|
|
|
|
*new{ ^super.new.init }
|
|
|
|
|
|
init{
|
|
|
cache = IdentityDictionary.new;
|
|
|
}
|
|
|
|
|
|
do { |server, func|
|
|
|
cache[server]!?{cache[server].do{|x|func.value(x)}}
|
|
|
}
|
|
|
|
|
|
at { |server,id|
|
|
|
^cache[server].tryPerform(\at,id)
|
|
|
}
|
|
|
|
|
|
includesKey{|server,key|
|
|
|
^cache[server].tryPerform(\includesKey,key)
|
|
|
}
|
|
|
|
|
|
put {|server,id,x|
|
|
|
cache[server][id] = x;
|
|
|
}
|
|
|
|
|
|
remove { |server,id|
|
|
|
cache[server]!? {cache[server].removeAt(id)};
|
|
|
}
|
|
|
|
|
|
initCache {|server|
|
|
|
cache[server] ?? {
|
|
|
cache[server] = IdentityDictionary.new;
|
|
|
NotificationCenter.register(server,\newAllocators,this,
|
|
|
{
|
|
|
this.clearCache(server);
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
clearCache { |server|
|
|
|
cache[server] !? { cache.removeAt(server) };
|
|
|
}
|
|
|
|
|
|
}
|