In my opinion, this is so difficult as to be not really worth the effort.
I did try just now with a SynthDef. There are so many special cases – it’s just very painful, and not readable… time spent making that work really well would be time not spent making music. I’d personally advise against it.
EDIT: Partially working sketch.
(
var printControl = { |ugen, stream(Post)|
stream << "Control.names("
<< ugen.channels.collect(_.name).asCompileString
<< ")."
<< ugen.methodSelectorForRate
<< "("
<< ugen.values.asCompileString
<< ")"
};
var ugenName = { |ugen| ugen.class.name.asString.toLower };
var printOutputProxy = { |ugen, ugens, stream(Post)|
var src = ugen.source;
var name = ugenName.(src);
var list = ugens[name];
var srcIndex = list.asArray.indexOf(src);
if(srcIndex.isNil) {
Error("Unknown proxy source" ++ src).throw;
};
stream << name << srcIndex << "[" << ugen.outputIndex << "]";
};
var printUGen = { |ugen, ugens, stream(Post)|
stream << ugen.class.name << "." << ugen.methodSelectorForRate;
if(ugen.inputs.size > 0) {
stream << "(";
ugen.inputs.do { |in, i|
var name, j;
if(i > 0) { stream << ", " };
case
{ in.isKindOf(OutputProxy) } {
printOutputProxy.(in, ugens, stream);
}
{ in.isUGen } {
name = ugenName.(in);
j = ugens[name].asArray.indexOf(in);
if(j.isNil) {
ugen.inspect;
Error("Unknown input" ++ in).throw;
};
stream << name << j;
}
{
stream << in;
};
};
stream << ")";
};
};
f = { |def, stream(Post)|
var ugens = Dictionary.new;
stream << "SynthDef('" << def.name << "', {\n";
def.children.do { |ugen|
var class = ugenName.(ugen);
var count = ugens[class].size;
stream << "\tvar " << class << count << " = ";
if(ugen.isKindOf(Control)) {
printControl.(ugen, stream);
} {
printUGen.(ugen, ugens, stream);
};
ugens[class] = ugens[class].add(ugen);
stream << ";\n";
};
stream << "})"
};
);
(
d = SynthDef(\test, { |out, gate = 1, freq = 440, amp = 0.1|
var eg = EnvGen.kr(Env.adsr, gate, doneAction: 2);
var osc = SinOsc.ar(freq);
Out.ar(out, (osc * eg * amp).dup);
}).add;
)
f.(d)
SynthDef('test', {
var control0 = Control.names([ 'out', 'gate', 'freq', 'amp' ]).kr([ 0.0, 1, 440, 0.1 ]);
var envgen0 = EnvGen.kr(control0[1], 1.0, 0.0, 1.0, 2, 0.0, 3, 2, -99, 1.0, 0.01, 5, -4.0, 0.5, 0.3, 5, -4.0, 0.0, 1.0, 5, -4.0);
var sinosc0 = SinOsc.ar(control0[2], 0.0);
var binaryopugen0 = BinaryOpUGen.ar(sinosc0, envgen0);
var binaryopugen1 = BinaryOpUGen.ar(binaryopugen0, control0[3]);
var out0 = Out.ar(control0[0], binaryopugen1, binaryopugen1);
})
But EnvGen is really a special case – that won’t work as shown. Oh and *OpUGens are also special cases (needs the operator
) which I didn’t do because I ran out of time. Anyway maybe this illustrates what you’re up against…
hjh