Last active
December 30, 2022 02:39
-
-
Save madskjeldgaard/fefd3e62360d3bafe59eb67d198ce484 to your computer and use it in GitHub Desktop.
Sketch for a supercollider based cloud generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Sketch for a cloud generator | |
By Mads Kjeldgaard, 2020 | |
*/ | |
( | |
~numChannels = 2; | |
s.options.numOutputBusChannels_(~numChannels); | |
~filePath = "~/lee.flac"; | |
s.waitForBoot{ | |
fork{ | |
// b = Buffer.read(s, "~/testsound/harmonica1.wav".asAbsolutePath).normalize; | |
b = Buffer.read(s, ~filePath.asAbsolutePath).normalize; | |
s.sync; "Done loading buffer".postln; | |
} | |
} | |
) | |
( | |
Ndef(\cloud, {|gdur=0.1, buffer, density=1.0, rate=0.95, shape=0.5, ratespread=0.0, pos=0.25, posspread=0.0, rand=1.0, overlap=0.0, amp=0.5| | |
var cloud; | |
var numGrains=4; | |
var numBufChans=2; | |
// Normalize params | |
density = density.linexp(0.0,1.0,0.0001,100.0); | |
rate = rate.linexp(0.0,1.0,0.01,10.0); | |
cloud = Array.fill(numGrains, {|gNum| | |
var coef=gNum+1/numGrains; | |
// Add tiny difference to each grain generator | |
var weight = Rand(0.9999,1.0); | |
var finalgdur = gdur * weight * overlap.linlin(0.0,1.0,1.0,4.0); | |
// Deterministic | |
var imp = Impulse.ar(density, phase: coef); | |
// Random impulses | |
var dust = Dust2.ar(density); | |
// Crossfade between them | |
var trig = XFade2.ar(imp, dust, rand.linlin(0.0,1.0,-1.0,1.0)); | |
// Grain envelope | |
// Soft envelope | |
var sineenv = EnvGen.ar( | |
Env.sine, | |
trig, | |
timeScale: finalgdur | |
); | |
// Hard envelope | |
var clickenv = EnvGen.ar( | |
Env([0,1,1,0], [0,1,0]), | |
trig, | |
timeScale: finalgdur | |
); | |
// Faded | |
var env = XFade2.ar(sineenv, clickenv, shape.linlin(0.0,1.0,-1.0,1.0)); | |
// Calculate position in buffer | |
var position = (weight * pos + (posspread * coef)).wrap(0.0,1.0) * BufFrames.ir(buffer); | |
// Calculate playback rate | |
var playbackrate = weight * rate * BufRateScale.ir(buffer); | |
var sig = PlayBuf.ar( | |
numBufChans, | |
buffer, | |
ratespread * (gNum + 1) + 1 * playbackrate, | |
trig, | |
position, | |
loop: 0.0, | |
doneAction: 0 | |
); | |
LeakDC.ar(env * sig) | |
}); | |
// Normalize sound levels a bit | |
cloud = cloud / numGrains; | |
cloud = cloud * amp; | |
Splay.ar(cloud.flatten) | |
}).set(\buffer, b, \wet1, 0.35).play; | |
Ndef(\cloud)[1] = \filter -> {|in, verbtime=10, room=5| | |
JPverb.ar(in, verbtime, 0, room); | |
}; | |
) | |
// Gui | |
( | |
Spec.add(\pos, ControlSpec( minVal: 0.0, maxVal: 1.0, warp: \lin, step: 0.0, default: 0.5)); | |
Spec.add(\density, ControlSpec( minVal: 0.0, maxVal: 1.0, warp: \lin, step: 0.0, default: 0.5)); | |
Spec.add(\rate, ControlSpec( minVal: 0.0, maxVal: 1.0, warp: \lin, step: 0.0, default: 0.5)); | |
Spec.add(\shape, ControlSpec( minVal: 0.0, maxVal: 1.0, warp: \lin, step: 0.0, default: 0.5)); | |
Spec.add(\ratespread, ControlSpec( minVal: 0.0, maxVal: 1.0, warp: \lin, step: 0.0, default: 0.5)); | |
Spec.add(\posspread, ControlSpec( minVal: 0.0, maxVal: 1.0, warp: \lin, step: 0.0, default: 0.5)); | |
Spec.add(\rand, ControlSpec( minVal: 0.0, maxVal: 1.0, warp: \lin, step: 0.0, default: 0.5)); | |
Spec.add(\overlap, ControlSpec( minVal: 0.0, maxVal: 1.0, warp: \lin, step: 0.0, default: 0.5)); | |
Spec.add(\gdur, ControlSpec( minVal: 0.001, maxVal: 1.0, warp: \lin, step: 0.0, default: 0.1)); | |
Spec.add(\wet1, ControlSpec( minVal: 0.0, maxVal: 1.0, warp: \lin, step: 0.0, default: 0.5)); | |
Ndef(\cloud).gui; | |
) | |
// Add some modulation | |
( | |
Ndef(\saw, {|f=0.001| LFSaw.kr(f).unipolar}).copy(\saw2).set(\f, 0.001); | |
Ndef(\sine, {|f=0.0151| SinOsc.kr(f).unipolar}).copy(\sine2).set(\f, 0.093211); | |
Ndef(\cloud).map(\posspread, Ndef(\saw), \stochastic, Ndef(\saw2), \rand, Ndef(\sine), \density, Ndef(\sine2)); | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks @madskjeldgaard for sharing this. Have you considered using live input here as well? I am trying to find a way to implement this with BufWr and BufRd but there are some problems as I'll get somewhere some clicky sounds?
I think this is b/c the start/end parameters of Phasor are not modulateable? Consider this where we start in different positions within the SinOsc, yet we get the same pattern on both channels.
or this, a sine wave riding on top of the end of the envelope
where the highest value should form a barrier like
which is not the case if you look closely enough.