Hello,
I have been trying to recreate a sort of oscillator from a SVF filter model which relies on single sample feedback. Trying the thing out first using DynGen, I can get some sound out with the following code:
(
DynGenDef(\myosc, "
@init
md1 = 0;
mc2 = 0;
p_md1 = 0;
p_mc2 = 0;
@sample
p_md1 = wrap(md1, -1, 1);
p_mc2 = wrap(mc2, -1, 1);
md1 = _a1 != 0 ? p_md1 + _a2 - (0.1 * p_mc2) : p_md1;
mc2 = p_mc2 * (_a4 + 1) + (0.49 * _a3 * p_md1);
out0 = p_md1;
out1 = p_mc2;
").send;
)
(
u = SynthDef(\unstable, {
| in1, in2, range2, in3, range3, in4, range4, clock_mod, bus_in, bus_out |
// 1
var oscn2_in1 = MyChange2.ar(
LFPulse.ar(
1000 / Ramp.kr(Ramp.kr(in1.linlin(0, 127, 0, 1000), 0.002).linlin(0, 1000, 1, 0.05), 0.02), width: 0.5
)
);
// 8
var cmod = Ramp.kr(Ramp.kr(clock_mod.linlin(0, 127, 0, 1), 0.002), 0.02);
// 9
var osc = In.ar(bus_in, 2);
// 2 - 3
var pow2 = (10 ** range2);
var oscn2_in2 = Ramp.kr(Ramp.kr(in2.linlin(0, 127, 0, 1000), 0.002).linlin(0, 1000, -1 / pow2, 1 / pow2), 0.02) + (osc * cmod);
// 4 - 5
var pow3 = (10 ** range3);
var oscn2_in3 = Ramp.kr(in3.linlin(0, 127, 0, 1000), 0.002).linlin(0, 1000, -1 / pow3, 1 / pow3);
// 6 - 7
var pow4 = (10 ** range4);
var oscn2_in4 = Ramp.kr(in4.linlin(0, 127, 0, 1000), 0.002).linlin(0, 1000, -1 / pow4, 1 / pow4);
var osc_sig = DynGen.ar(2, \myosc, params: [
a1: oscn2_in1,
a2: oscn2_in2,
a3: oscn2_in3,
a4: oscn2_in4,
]);
osc_sig.poll;
Out.ar(bus_out, osc_sig);
});
)
(
~uns1 = NodeProxy.audio(s, 2);
~uns1.source = u;
Spec.add(\in1, ControlSpec( 0, 127, \lin, 1 ));
Spec.add(\in2, ControlSpec( 0, 127, \lin, 1 ));
Spec.add(\range2, ControlSpec( 0, 3, \lin, 1 ));
Spec.add(\in3, ControlSpec( 0, 127, \lin, 1 ));
Spec.add(\range3, ControlSpec( 0, 3, \lin, 1 ));
Spec.add(\in4, ControlSpec( 0, 127, \lin, 1 ));
Spec.add(\range4, ControlSpec( 0, 3, \lin, 1 ));
Spec.add(\clock_mod, ControlSpec( 0, 127, \lin, 1 ));
~uns1.setn(
\in1, 0,
\in2, 0,
\range2, 3,
\in3, 0,
\range3, 3,
\in4, 0,
\range4, 3,
\clock_mod, 0);
~uns1.gui;
)
Then with Fb1, however the values are all zeroes:
(
if (s.options.blockSize != 64) {
s.options.blockSize = 64;
s.quit.reboot;
}
)
(
u = SynthDef(\unstable, {
// 1
var oscn2_in1 = MyChange2.ar(
LFPulse.ar(
1000 / Ramp.kr(Ramp.kr(\in1.kr.linlin(0, 127, 0, 1000), 0.002).linlin(0, 1000, 1, 0.05), 0.02), width: 0.5
)
);
// 8
var cmod = Ramp.ar(Ramp.ar(\clock_mod.ar.linlin(0, 127, 0, 1), 0.002), 0.02);
// 9
var osc = In.ar(\bus_in.kr, 1);
// 2 - 3
var pow2 = (10 ** \range2.ar);
var oscn2_in2 = Ramp.ar(Ramp.ar(\in2.ar.linlin(0, 127, 0, 1000), 0.002).linlin(0, 1000, -1 / pow2, 1 / pow2), 0.02) + (osc * cmod);
// 4 - 5
var pow3 = (10 ** \range3.ar);
var oscn2_in3 = Ramp.ar(\in3.ar.linlin(0, 127, 0, 1000), 0.002).linlin(0, 1000, -1 / pow3, 1 / pow3);
// 6 - 7
var pow4 = (10 ** \range4.ar);
var oscn2_in4 = Ramp.ar(\in4.ar.linlin(0, 127, 0, 1000), 0.002).linlin(0, 1000, -1 / pow4, 1 / pow4);
var osc_sig = Fb1({ |in, out|
var md1, mc2, p_md1, p_mc2;
var a1, a2, a3, a4;
#a1, a2, a3, a4 = in[0];
p_md1 = out[1][2].clip(-1, 1);
p_mc2 = out[1][3].clip(-1, 1);
md1 = if(a1 != 0, p_md1 + a2 - (0.1 * p_mc2), p_md1).sanitize;
mc2 = (p_mc2 * (a4 + 1) + (0.49 * a3 * p_md1)).sanitize;
[p_md1, p_mc2, md1, mc2]
}, in: [oscn2_in1, oscn2_in2, oscn2_in3, oscn2_in4], outSize: 4);
osc_sig.poll;
Out.ar(\bus_out.kr, osc_sig);
});
)
(
~uns1 = NodeProxy.audio(s, 2);
~uns1.source = u;
Spec.add(\in1, ControlSpec( 0, 127, \lin, 1 ));
Spec.add(\in2, ControlSpec( 0, 127, \lin, 1 ));
Spec.add(\range2, ControlSpec( 0, 3, \lin, 1 ));
Spec.add(\in3, ControlSpec( 0, 127, \lin, 1 ));
Spec.add(\range3, ControlSpec( 0, 3, \lin, 1 ));
Spec.add(\in4, ControlSpec( 0, 127, \lin, 1 ));
Spec.add(\range4, ControlSpec( 0, 3, \lin, 1 ));
Spec.add(\clock_mod, ControlSpec( 0, 127, \lin, 1 ));
~uns1.setn(
\in1, 0,
\in2, 0,
\range2, 3,
\in3, 0,
\range3, 3,
\in4, 0,
\range4, 3,
\clock_mod, 0);
~uns1.gui;
)
The equations are quite close in both ways of doing, and I do think I picked the right out values (out[1] to get the previously computed values)
I am thinking that in the first example with DynGen, it is possible to pass control rate inputs to the audio rate DynGen UGen, while with audio rate Fb1, the inputs are required to be audio rate as well, and said inputs behave diffrently in that case.
Using control rate Fb1 does not result in something audible, as expected.
Other examples of Fb1 generating sound by themselves do not seem to involve audio rate controls as inputs to set the oscillator parameters.
(
x = {
var sig = Fb1({ |in, out|
out[1] * 2 + (out[2] * 3) % 1.01
},
outSize: 2,
outInit: [[3, 1], [2, 5]],
outDepth: 3
).tanh * 0.2;
LPF.ar(sig, 2000)
}.play
)
Could someone perhaps shed a light on the cause behind this?
Thanks.