HelpBrowser: path box becomes a more conventional search box
[supercollider.git] / SCClassLibrary / JITLib / ProxySpace / ProxySynthDef.sc
blobf5209b2347671211cb4123412bcc27294909b1e8
1 ProxySynthDef : SynthDef {
3         var <>rate, <>numChannels;
4         var <>canReleaseSynth, <>canFreeSynth;
5         classvar <>sampleAccurate=false;
8         *new { arg name, func, rates, prependArgs, makeFadeEnv=true, channelOffset=0,
9                         chanConstraint, rateConstraint;
10                 var def, rate, numChannels, output, isScalar, envgen, canFree, hasOwnGate;
11                 var hasGateArg=false, hasOutArg=false;
12                 def = super.new(name, {
13                         var  out, outCtl;
15                         // build the controls from args
16                         output = SynthDef.wrap(func, rates, prependArgs);
17                         output = output.asUGenInput;
19                         // determine rate and numChannels of ugen func
20                         rate = output.rate;
21                         isScalar = rate === 'scalar';
22                         numChannels = output.numChannels;
23                         // check for out key. this is used by internal control.
24                         func.def.argNames.do { arg name;
25                                 if(name === \out) { hasOutArg = true };
26                                 if(name === \gate) { hasGateArg = true };
27                         };
29                         if(isScalar.not and: hasOutArg)
30                         {
31                                 "out argument is provided internally!".error; // avoid overriding generated out
32                                 ^nil
33                         };
35                         //detect inner gates
36                         canFree = UGen.buildSynthDef.children.canFreeSynth;
37                         hasOwnGate = UGen.buildSynthDef.hasGateControl;
38                         makeFadeEnv = if(hasOwnGate && canFree.not) {
39                                                         "warning: gate does not free synth!".inform; false
40                                                 } {
41                                                         makeFadeEnv and: { (isScalar || canFree).not };
42                                                 };
44                         hasOwnGate = canFree && hasOwnGate; //only counts when it can actually free synth.
45                         if(hasOwnGate.not && hasGateArg) {
46                                 "supplied gate overrides inner gate.".error;
47                                 ^nil
48                         };
51                         //"gate detection:".postln;
52                         //[\makeFadeEnv, makeFadeEnv, \canFree, canFree, \hasOwnGate, hasOwnGate].debug;
54                         // constrain the output to the right number of channels if supplied
55                         // if control rate, no channel wrapping is applied
56                         // and wrap it in a fade envelope
57                         envgen = if(makeFadeEnv) {
58                                                 EnvGate(1, nil, nil, 2, if(rate === 'audio') { 'sin' } { 'lin' })
59                                         } { 1.0 };
61                         if(chanConstraint.notNil
62                                 and: { chanConstraint < numChannels }
63                                 and: { isScalar.not },
64                                 {
65                                         if(rate === 'audio') {
66                                                 postln(
67                                                 "wrapped channels from" + numChannels
68                                                 + "to" + chanConstraint + "channels");
69                                                 output = NumChannels.ar(output, chanConstraint, true);
70                                                 numChannels = chanConstraint;
71                                         } {
72                                                 postln("kept first" + chanConstraint + "channels from"
73                                                 + numChannels + "channel input");
74                                                 output = output.keep(chanConstraint);
75                                                 numChannels = chanConstraint;
76                                         }
78                                 });
79                         output = output * envgen;
81                         //"passed in rate: % output rate: %\n".postf(rateConstraint, rate);
83                         if(isScalar, {
84                                         output
85                                 }, {
86                                         // rate adaption. \scalar proxy means neutral
87                                         if(rateConstraint != \scalar and: { rateConstraint !== rate }) {
88                                                 if(rate === 'audio') {
89                                                         output = A2K.kr(output);
90                                                         rate = 'control';
91                                                         "adopted proxy input to control rate".postln;
92                                                 } {
93                                                         if(rateConstraint === 'audio') {
94                                                                 output = K2A.ar(output);
95                                                                 rate = 'audio';
96                                                                 "adopted proxy input to audio rate".postln;
97                                                         }
98                                                 }
99                                         };
100                                         outCtl = Control.names(\out).ir(0) + channelOffset;
101                                         if(rate === \audio and: { sampleAccurate }) { OffsetOut } { Out }                                               .multiNewList([rate, outCtl]++output)
102                         })
103                 });
105                 // set the synthDefs instvars, so they can be used later
107                 def.rate = rate;
108                 def.numChannels = numChannels;
109                 def.canReleaseSynth = makeFadeEnv || hasOwnGate;
110                 def.canFreeSynth = def.canReleaseSynth || canFree;
111                 //[\defcanReleaseSynth, def.canReleaseSynth, \defcanFreeSynth, def.canFreeSynth].debug;
112                 ^def
113         }