While it is technically possible to allocate buffers in the SynthDef ugenGraphFunc - and each R “module type” (ie. MultiOsc) just end up as a SynthDef as @21echoes correctly noted - this isn’t the right approach here. Buffers allocated in a SynthDef ugenGraphFunc would be shared between Synths based on that SynthDef.
SC Example
s.boot;
(
SynthDef('test', {
var buf1, buf2;
buf1 = Buffer.alloc(s, 1234);
buf1.bufnum.poll(trig: 1, label: 'buf1_bufnum');
buf2 = Buffer.alloc(s, 1234);
buf2.bufnum.poll(trig: 1, label: 'buf2_bufnum');
}).add;
)
a=Synth('test');
a.free;
b=Synth('test'); // compare polled buf1_bufnum/buf2_bufnum printouts - these synths use the same pair of buffers ...
b.free;
c=Synth('test'); d=Synth('test'); // ... even if they're running at the same time
The handling of the ugenGraphFunc passed to a SynthDef is one of SuperCollider’s many quirks. Given how dynamic the language is, as a newcomer one believes the ugenGraphFunc is evaluated for every Synth that is created from a SynthDef. But, it is in fact evaluated at SynthDef creation time and language semantics are very different in it.
The “Static versus Dynamic Elements” section in the docs for SynthDef elaborates on this:
… A def’s UGen graph function (and the SC code within it) is evaluated only when the def is created. Thus ‘if’ statements, etc. will have no further effect at the time the def is used to create a Synth, and it is important to understand that a UGen graph function should not be designed in the same way as functions in the language, where multiple evaluations can yield different results. It will be evaluated once and only once .
This is weird and you learn it by experience. 
Anyway, @okyeron if you get it to work in R your delay line would be shared between multiple “module instances” (= what you get when you invoke engine.new("MyOsc", "MultiOsc") = a Synth based on the MultiOsc’s SynthDef), which I do not think you want (two delay modules would write into and read from one and the same buffer). Also, as noted above the life cycle of the buffer would be suboptimal - a really long buffer would always be present and take up memory, regardless if whether you use the module or not, and it wouldn’t be deallocated in a proper way.
To solve this we’d have to have a way in R - which essentially is a very regulated/constrained way of creating SynthDefs in order to standardize modules and make them interconnected - to specify custom buffers. Ie:
Idea
(
name: 'LongDelay',
description: " ... description ... ",
inputs: [
// .. input metadata ...
],
outputs: [
// .. output metadata ...
],
params: [
// .. params metadata ...
],
custom_buffers: [
'DelayLine' -> (
NumFrames: 120 * 44100,
NumChannels: 1
),
],
ugenGraphFunc: {
|
in_In,
in_DelayTimeModulation,
out_Out,
param_DelayTime,
param_DelayTimeModulation,
visual_DelayTime,
bufnum_DelayLine
|
var sig_In = In.ar(in_In);
var sig_DelayTimeModulation = In.ar(in_DelayTimeModulation);
var buffer = Buffer.alloc(numFrames: 48000*60, numChannels: 1);
var delayTimeSpec = ControlSpec(0.1, 5000, 'exp', 0, 300, "ms");
var delayTimeMs = delayTimeSpec.map(
delayTimeSpec.unmap(param_DelayTime) + (sig_DelayTimeModulation * param_DelayTimeModulation)
);
var delayed = BufDelayC.ar(buf: bufnum_DelayLine, in: sig_In, delaytime: delayTimeSec);
Out.ar(out_Out, delayed);
Out.kr(visual_DelayTime, delayTimeMs);
}
)
This needs a bit of non-trivial frameworky stuff, but I’ve done something similar for upcoming sample support so I might be able to reuse it in some way.