thanks for your help. its working with MidiSynth(\m1).put(210, \granular_reverb).set(...)
but im not able to get a 100% wet signal. will open another thread.
sorry for interrupting.
based on the code above, i think you would need to change your in
arg
arg in=0
with something like
var in = In.ar(\out.kr, 2);
And then for your output if youāre using Out or ReplaceOut use this insteadā¦
XOut.ar(\out.kr, \mix.kr(1), sig.tanh)
Iām not 100% certain but I think this would work, at least this is how I understand JitLib handles the plumbingā¦
Before I forget about this thread, Iām going to add a ātable of contentsā here for the several ways to skin this cat that have been discussed above. This will be a bit biased, I admit.
-
If you only need to change the names of an already complied SynthDef, then you can do this quite safely by changing its
.allControlNames
, possibly usingdeepCopy
too if you need several instances each with different control names. This is discussed in post #9 asmakeSDclones
. This techinque alone isnāt too useful for Ndef / NodeProxy roles (like\filer ->
), but you can plug the resulting SynthDefs directly into NodeProxysources
slots. -
The previous technique can be adapted to NodeProxy roles by writing custom roles that essentially intercept the the
ProxySynthDef
object returned by.buildForProxy
. This method has been discussed in post #20 under the names\mixM
.\filterM
, and\filterInM
where a āmass generatorā of such roles was given that can essentially take an existing role and add the automatic renaming functionality to it, producing a new role automagically.
The two related techniques above donāt require any extensions to the SC class library.
-
If you need to combine several functions that produce SynthDef code into one SynthDef that doesnāt have control name conflicts, then the most general method is to install a mangler that intercepts the ControlNames as they get emitted to the SynthDef graph as it is being compiled. While this method does require some SC extensions, it does buy you the ability to
SynthDef.wrap
the same function multiple times in the same SynthDef e.g. with suffixed argument names for each invocation. Extension code for this method has been provided in post #13. To emphasize again: in difference to the technique used at the previous two points, this one produces a single resulting SynthDef, possibly from many instances of the same synth function. Although (in hindsight) a bit overkill for NodeProxy roles, this technique can also be used for them, as shown (as another application, if you will) in the 2nd part of post #14 as\mixN
and\filterN
. (Not much creativity with names, I admit.) -
Related to technique 3, you can also mangle the names in the function text code, but this approach is a little more brittle, because it might not find the control names to replace if they donāt show up in the function text directly, because e.g. they are obtained by calling yet another function. This technique has been discussed in post #2.
-
If youāre willing to restrict yourself to using NamedControls invoked in
\sym.kr
style, a technique requiring simpler extensions is to alter / extend those Symbol methods a bit to do the mangling, e.g. to lookup some suffix from an environment and useinEnvir
to evaluate the function in the right environment to get the suffix. This has been discussed in posts #10 and #12. A variation on this that essentially turns your SynthDef function in a macro of sorts, is to write~foo.kr
instead of\foo.kr
and again to useinEnvir
style evaluation for the replacement. The last approach requires no extensions whatsoever, but it does require one to change their source code.
I think I didnāt miss any major ideas / approaches discussed above in this summary. If I did, I apologize in advance. And please let me know if thatās the case so I can include the missing bits in this summary (while I can still edit it, that is).
Thank you for all your replies ! I learned a lot. Finally I used the @Avid_Reader solution, very neat!
I can now use fx in any Ndef, I integrated the code in my Param quark. I made a video to show how to build a sequencer GUI, then I use the Ndef fx at minute 8:40
Thanks for the vote of confidence. I havenāt watched your full video, so can you spoil it for the impatient me with respect to which of the above solutions youāve used, so I can consider packaging it as a quark maybe?
For Ndef slots controls renaming Iāve added a feature to support some shared controls, in the meantime, for my own need. The syntax is a little odd, but it exploits the fact that array building has higher precedence in the sclang parser than ->
, so you donāt have type many extra parentheses to force right-associativity. E.g. use case:
~filt = { |sig| Ringz.ar(sig, (\cutoff.kr(1) * 1000) + \lofreq.kr(100), 0.9, 0.5);};
~a = Ndef(\node) { LFSaw.ar(200, 0, 0.05) }; // sets ~a[0]
~a[1] = \filterM -> [~filt, \cutoff]; // only \lofreq will be numbered
~a[2] = \filterM -> [~filt, \cutoff]; // ibid
~a.edit;
\cutoff
is shared contorls for both slots as Ndef normally does, but \lofreq
is not. Basically, you supply an array whose first element is the ndef function, but the subsequent elements of this are are names of controls that are supposed to be (kept) shared. You can still use non-arrays as arguments, it will just make every control of that slot unique in that case, as in the previous versions of this role generator.
~a[3] = \filterM -> ~filt; // this one gets its separate cutoff too
~a.controlNames do: _.postln
/*
ControlName P 1 wet1 control 1.0
ControlName P 4 cutoff control 1
ControlName P 5 lofreq1 control 100
ControlName P 1 wet2 control 1.0
ControlName P 5 lofreq2 control 100
ControlName P 1 wet3 control 1.0
ControlName P 4 cutoff3 control 1
ControlName P 5 lofreq3 control 100
*/
For the curious: a syntax alternative would have been to addUniqueMethod the function so you could have written something like \filterM -> ~filt.common(\cutoff)
because .
also has higher precedence, but that approach ran into some SC bug with testing for the presence of addUnique-d methods later.)
So, if anybody needs this, hereās version of those Ndef roles that supports those (partially) shared controls, with the array syntax.:
(~massPostmaglerInstaller = { arg newRolesSuffix = "M"; // so \mixM etc.
var targetRoles = #[\mix, \filter, \filterIn];
var defaultSkipNames = #["out", "i_out", "gate", "fadeTime"];
var specificSkipNames = (mix: ["mix"], filter: ["wet"], filterIn: ["wet"]);
var postmangler = { arg name, index, role, extraSkipNames;
var skipNames = defaultSkipNames ++ (specificSkipNames[role] +++ index);
skipNames = skipNames ++ (extraSkipNames.collect {|n| n.asString});
name = name.asString;
extraSkipNames.postln;
skipNames.postln;
if(skipNames.indexOfEqual(name).isNil) {
name = name.asString ++ index;
("Renamed::" + name).postln;
} {
("Skipped::" + name).postln;
};
name.asSymbol
};
var wrapperGen = { arg roleName, roleBuildFunc; // curried targets
{ arg func, proxy, channelOffset = 0, index;
var psd;
func = func.asArray;
psd = roleBuildFunc.value(func[0], proxy, channelOffset, index);
psd.allControlNames.do { arg cno;
cno.name = postmangler.value(cno.name, index, roleName, func[1..]) };
psd.allControlNames.do(_.postln);
psd
}
};
targetRoles.collect { arg roleName;
var origBuildFunc = AbstractPlayControl.buildMethods[roleName];
var newBuildFunc = wrapperGen.value(roleName, origBuildFunc);
var newRoleName = (roleName.asString ++ newRolesSuffix).asSymbol;
AbstractPlayControl.buildMethods.put(newRoleName, newBuildFunc);
(newRoleName.asString + "installed").postln;
[newRoleName, newBuildFunc] // ret val somewhat irrelevant
}
};
~massPostmaglerInstaller.()
)
In this case donāt watch the video, I donāt show any internal code, the goal is to show how to create a complex GUI sequencer with FX with only a few lines of high level code
I used the renaming of controlNames, thatās the most easiest, quickest, cleanest solution =) Then I use Ndef(xx)[n] = \cloned_synthname
where the synthdef have a In.ar and XOut.ar using the \out argument like you instructed
cloneSynthDefWithIndexedArguments: { arg self;
var sdc;
var synthDef;
var suffix = self.index;
var synthDesc;
synthDesc = SynthDesc(self.synthName);
if(synthDesc.notNil) {
synthDef = synthDesc.def;
sdc = synthDef.deepCopy;
sdc.name = synthDef.name.asString ++ suffix; // no eff without asString!
sdc.allControlNames.do { arg cno;
if(not(self.excludedArgs.includes(cno.name))) {
cno.name = (cno.name.asString ++ suffix);
} {
// ("Skipped renaming" + cno.name + "in" + sdc).postln
}
};
sdc // return whole sd clone to be collect-ed
} {
Log(\Param).debug("InsertFx.cloneSynthDefWithIndexedArguments: no synthDef: %", self.synthName);
nil
}
},
Ok, but beware that if you In.ar(\out.ir)
in a Ndef presently it has some odd effects like it will play immediately on bus 0. See e.g. this. Unless youāre also [re]numbering \out
to \outX
, which Iām guessing you might be doing, since you didnāt add exception for āoutā in your code.
Thanks I didnāt know this bug. This is not causing real problems for me for the moment because the Ndef is used as a mixer so it produce no sounds on its own ^^
But I have one question, I thought that I must use the name \out else Ndef will not know which control name to set out bus, no ? Or with a numbered suffix, Ndef will also recognize it ?