i was messing around a bit and would like to share this one, i think it sounds pretty sharp
(
~numPartials = 10;
~bufAmps = Buffer.alloc(s, ~numPartials);
SynthDef(\additive, {
arg shapeAmount=0.3, time=1, freq=150;
var gainEnv = \gainEnv.ar(Env.newClear(8).asArray);
var fltEnv = \fltEnv.ar(Env.newClear(8).asArray);
var iEnv = \iEnv.ar(Env.newClear(8).asArray);
var k = 2 * shapeAmount / (1 - shapeAmount);
var numPartials = ~numPartials;
var bufAmps = ~bufAmps;
var trg = \gt.kr(1);
var sig, mod;
iEnv = EnvGen.kr(iEnv, trg, timeScale:time, doneAction:Done.none);
fltEnv = EnvGen.kr(fltEnv, trg, timeScale:time, doneAction:Done.none);
gainEnv = EnvGen.kr(gainEnv, trg, doneAction:Done.freeSelf);
mod = SinOsc.ar(freq * \mRatio.kr(1), mul: iEnv);
BufWr.ar(
LFGauss.ar(
duration: SampleDur.ir * numPartials * \factor.kr(1).reciprocal,
width: gainEnv * LFNoise2.kr(1).linexp(-1, 1, \widthMin.kr(0.1, 0.5), \widthMax.kr(1.0, 0.5)),
iphase: \phase.kr(0, 0.5).mod(4pi)
),
bufnum: bufAmps,
phase: Phasor.ar(
end: numPartials
)
);
sig = Array.fill(numPartials, {
arg i;
SinOsc.ar(
freq: ((i * 2) + 1) * freq * \cRatio.kr(1, 0.5),
phase: mod.wrap(0, 4pi),
mul: Index.ar(bufAmps, i)
) / numPartials
}).sum;
sig = ((1 + k) * sig / (1 + (k * sig.abs)));
sig = (sig * 2).tanh;
sig = HPF.ar(sig, 75);
sig = MoogFF.ar(sig, fltEnv * \fltFreq.kr(7500), 0);
sig = sig * gainEnv;
sig = Pan2.ar(sig, \pan.kr(0), \amp.kr(0.25));
sig = LeakDC.ar(sig);
OffsetOut.ar(\out.kr(0), sig);
}).add;
SynthDef(\combL, {
arg in=0, out=0, mix=(-0.5), decay=1, amp=1, delHz=0.55, delStereoRatio=0.9, delMin=0.001, delMax=0.4;
var sig, comb;
sig = In.ar(in, 2);
delHz = delHz * [1,delStereoRatio];
comb = CombL.ar(
sig,
delMax,
LFPar.kr(delHz,[0,pi/2]).exprange(delMin,delMax),
decay,
);
sig = XFade2.ar(sig, comb, mix) * amp;
Out.ar(out, sig);
}).add;
)
(
// assist data-sharing in pbindfx creation
// pbindfx is wrapped in a private environment (Penvir)
// arguments are just pdef names
~pbindFx = {|srcName ... fxNames|
// add private environment, shared between source and fxs
Penvir(Event.new(parent:currentEnvironment),
PbindFx(
// source: record latest event in ~src
*[Pdef(srcName).collect(~src=_)]
// add all fx: they can access source event saved in ~src
++ fxNames.collect(Pdef(_))
)
)
};
~utils = ();
~utils.hasEnv = {
// calc this event's duration in seconds
var durSeconds = ~sustain.value / thisThread.clock.tempo;
// find all parameters ending in env or Env
var envKeys = currentEnvironment.keys.select{|k|"[eE]nv$".matchRegexp(k.asString)};
envKeys.do{|param|
var value = currentEnvironment[param];
if (value.isArray.not) { value = [value] };
value = value.collect {|v|
// pass rests along...
if (v.isRest) { v } {
// convert non-env values to a continuous, fixed value env
if (v.isKindOf(Env).not) { v = Env([v, v], [1]) }
};
// stretch env's duration
v.duration = durSeconds;
};
currentEnvironment[param] = value;
};
};
Event.addParentType(\hasEnv,(
finish: ~utils[\hasEnv]
));
t = TempoClock.new(60/60).permanent_(true);
)
(
Pdef(\additive,
Pbind(
\type, \hasEnv,
\instrument, \additive,
\dur, (Pseq((0..25).linexp(0, 25, 1, 75), inf).reciprocal).trace,
\midinote, Pdup(26, Pseq([60 + [0, 4, 7, 11]], inf))
+ Pseq([Pdup(25, Pseq([0.25])), Pseq([0.1667])], inf),
\factor, Pdup(26, Pseq([3,1],inf)),
\phase, 1,
\widthMin, 0.1,
\widthMax, 0.5,
\atk, 0.0001,
\rel, 1,
\gainEnv, Pfunc{|e|
Env.perc(e.atk, e.rel, curve: -8.0);
},
\sustain, Pfunc { |ev| ev[\gainEnv].duration },
//Phase Modulation
\mRatio, 1.5,
\cRatio, 1,
\index, 1,
\iScale, 2,
\iAtk, 0.001,
\iRel, 0.35,
\time, Pfunc { |ev| ev.use { ~sustain.value } / thisThread.clock.tempo },
\iEnv, Pfunc{ |e|
var cAtk = exprand(2,6);
var cRel = exprand(-2,-6);
Env([e.index, e.index * e.iScale, e.index], [e.iAtk, e.iRel], [cAtk, cRel])
},
\fAtk, 0.001,
\fSus, 0.15,
\fRel, 0.25,
\fltFreq, 7500,
\fltEnv, Pfunc{|e|
var cAtk = exprand(2,6);
var cRel = exprand(-2,-6);
Env([0,1,1,0],[e.fAtk, e.fSus, e.fRel],[cAtk,0,cRel])
},
\pan, 0,
\amp, 0.30,
\out, 0,
\finish, ~utils[\hasEnv],
\cleanupDelay, Pkey(\sustain),
\fxOrder, [1]
)
);
Pdef(\additive_comb,
Pbind(
\fx, \combL,
\mix, 0.5,
\amp, 1,
\delStereoRatio, 0.9,
\delHz, 0.1,
\delMin, Pfunc { (~src.dur == 1).if { 0.35 }{ 0.15 } },
\delMax, Pkey(\delMin) + 0.01,
\decay, Pfunc { (~src.dur == 1).if { 2 }{ 0.5 } },
\cleanupDelay, Pkey(\decay)
));
Pdef(\additive_fx, ~pbindFx.(\additive, \additive_comb));
)
Pdef(\additive_fx).play(t, quant:1);