In this little example, the .xset and .set at the level of sub-index don’t have the same behaviour. The xset is retriggering the Ndef’s primary index. Is it logic ?
~flute = Buffer.read(s, "/path/to/some/longwavefile.wav");
(
Ndef(\flute).play;
Ndef(\flute).fadeTime=1;
Ndef(\flute,{ |bufnum = 0, amp=1, pan=0|
var sig;
// sig = PlayBuf.ar(1, bufnum, BufRateScale.ir(bufnum),LastValue.kr(bufnum)-bufnum,0,1);//, doneAction: 2);
sig = PlayBuf.ar(1, bufnum, BufRateScale.ir(bufnum),bufnum,0,1);//, doneAction: 2);
sig * amp;
});
Ndef(\flute).set(\bufnum,~flute.bufnum);
Ndef(\flute).set(\wet1,0);
Ndef(\flute)[1]=\filter -> { |in| Select.ar(in.ceil, [in.abs * \amount.kr(1), in]) }
)
// activate the filter while reading the buffer. No transition. --> OK
Ndef(\flute).set(\wet1,1);
// activate the filter while reading the buffer. With transition. --> KO, the buffer gets re-read from start.
Ndef(\flute).xset(\wet1,1);
// deactivate the filter
Ndef(\flute).set(\wet1,0);
Why is it so at a filter level ?
[EDIT]
Modifying the filter’s function at [1] DOES NOT retrigger the synth at [0].
So it seems unlogical that a .xset(\wet1, xyz) does.
Haven’t look at this in detail, but my understanding is that xset creates two synths and cross-fades between them. Probably what happens is that the entire “chain” inside the Ndef, meaning all sources array, get duplicated in this process, which is why your base signal gets restarted. I guess Ndef would have to be “smarter” to avoid this and figure out which control belongs two which source in the array and only duplicate that one for the xfade.
I think the simple workaround is to separate your filter to a separate Ndef and use external signal routing.
Indeed. The whole chain is being duplicated. From my point of view this is a mistake.
I’ve solved this this way:
(
~xset={
|ndef,param,value,dur|
var from, v,to;
var e;
var levels=10;
dur=dur?ndef.fadeTime;
e=Env.pairs([[0,0],[dur,1]],\sine).asStream;
from=ndef.get(param);
to=value;
{
(levels+1).do({
var r=e.next;
var v=((to-from)*r)+from;
ndef.set(param,v);
(dur/levels).wait;
})}.fork
};
)
with the simple usage :
~xset.(Ndef(\flute),\wet1,1,4);
I think I’m going to move this as a custom extension of the NodeProxy class.
+NodeProxy {
/**
* Fluid XSET, that doesn't duplicate the whole ndef but just smoothly change the desired parameters
* LVR: 11/12/21
* Parameters are:
* - a suite of key, value. See NodeProxy set for more info.
* - on optianal duration representing the fadeTime. If ommitted, then the Ndef.fadeTime will be used.
**/
xfset { | ... args|
var ndef, dur;
var values;
var e;
var levels=10;
// ndef=args.removeAt(0);
ndef=this;
if ((args.size.odd),
{
dur=args.removeAt(args.size-1)
},
{
dur=ndef.fadeTime
}
);
values=args.reshape((args.size/2).asInteger,2);
// values.postln;
values=values.collect({|a| a.insert(1,ndef.get(a[0])?0)});
// values.postln;
e=Env.pairs([[0,0],[dur,1]],\sine).asStream;
{
(levels+1).do({
var r=e.next;
var v=values.collect({|a| [a[0],((a[2]-a[1])*r)+a[1]]});
// v.postln;
v.do({|a| ndef.set(a[0].asSymbol,a[1])});
(dur/levels).wait;
})}.fork
}
}
In the obscurely name JITLibExtensions. Part of JITlib comes with SC, but the more “experimental” part, which includes that class, is only shipped as quark.
Actually it does manage the transitions !!
However, the developers and I don’t have apparently the same use cases. So I submitted a modification of the quarks to take more cases into account.