Last active
November 18, 2015 16:48
-
-
Save Sciss/b67db2085d40cd05c08c to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| /*--- | |
| Adapted from: Designing Sound in SuperCollider | |
| Source: https://en.wikibooks.org/wiki/Designing_Sound_in_SuperCollider | |
| */ | |
| /*--- | |
| 24. Pedestrians | |
| */ | |
| play { | |
| SinOsc.ar(2500) * 0.2 * LFPulse.ar(5) | |
| } | |
| /*--- | |
| 25. Phone Tones | |
| */ | |
| // 25.2 CCITT dialing tone | |
| play { | |
| Pan2.ar(Mix(SinOsc.ar(Seq(350, 440)))) * 0.2 | |
| } | |
| // 25.3: Filter to approximate the transmission medium | |
| val bus = Bus.audio(s) | |
| val filter = play { | |
| val in = In.ar("in".kr(bus.index)).clip2(0.9) | |
| val f1 = BPF.ar(in, 2000, 1.0/12) | |
| val f2 = BPF.ar(f1 * 0.5, 400, 1.0/3) + (f1.clip2(0.4) * 0.15) | |
| HPF.ar(HPF.ar(f2, 90), 90) * 100 | |
| } | |
| // 25.4: The filter applied to the dialing tone | |
| val source = play(target = filter, addAction = addBefore) { | |
| val onoff = MouseX.kr > 0.2 | |
| val sig = Mix(SinOsc.ar(Seq(350, 440))) * onoff * 0.2 | |
| Out.ar("out".kr(bus.index), sig) | |
| } | |
| source.free() | |
| // 25.5a: Ringing tone | |
| val source = play(target = filter, addAction = addBefore) { | |
| val onoff = LFPulse.ar(1.0/6, width = 1.0/3) | |
| val sig = Mix(SinOsc.ar(Seq(480, 440))) * onoff * 0.2 | |
| Out.ar("out".kr(bus.index), sig) | |
| } | |
| source.free() | |
| // 25.5b: Busy tone | |
| val source = play(target = filter, addAction = addBefore) { | |
| val onoff = LPF.ar(LFPulse.ar(2), 100) | |
| val sig = Mix(SinOsc.ar(Seq(480, 620))) * onoff * 0.2 | |
| Out.ar("out".kr(bus.index), sig) | |
| } | |
| source.free() | |
| // 25.6: Pulse dialing, before DTMF | |
| val source = play(target = filter, addAction = addBefore) { | |
| val n = "number".kr | |
| val number = Select.kr(n < 0.5, Seq[GE](n, 10)) // zero is represented by 10 clicks! | |
| val t_trig = "t_trig".tr | |
| number.poll(t_trig) | |
| val onoff = Trig1.ar(t_trig, number * 0.1) | |
| val trigs = Impulse.ar(10) * onoff | |
| val son = Trig1.ar(trigs, 0.04) | |
| son | |
| } | |
| source.set("t_trig" -> 1, "number" -> util.Random.nextInt(10)) | |
| source.free(); filter.free(); bus.free() | |
| /*--- | |
| Practicals: Nature | |
| 34. Fire | |
| */ | |
| // 34.3: simplest random hissing sound | |
| play { | |
| WhiteNoise.ar(LFNoise2.kr(1)) | |
| } | |
| // 34.4: square it | |
| play { | |
| WhiteNoise.ar(LFNoise2.kr(1).squared) | |
| } | |
| // 34.5: more | |
| play { | |
| HPF.ar(WhiteNoise.ar, 1000) * LFNoise2.kr(1).squared.squared | |
| } | |
| // 34.6: a simple single crackle | |
| play { | |
| WhiteNoise.ar * Line.ar(1, 0, 0.02, doneAction = freeSelf) | |
| } | |
| // 34.7: many crackles | |
| play { | |
| WhiteNoise.ar * EnvGen.ar(Env.perc(0, 0.02, curve = Curve.parametric(0)), Dust.kr(1)) | |
| } | |
| // 34.8: more variation | |
| play { | |
| val trigs = Dust.kr(1) | |
| val durScale = TRand.kr(1, 1.5, trigs) // vary duration between default 20ms and 30ms | |
| val resFreq = TExpRand.kr(100, 1000, trigs) // different resonant frequency for each one | |
| val son = WhiteNoise.ar * EnvGen.ar(Env.perc(0, 0.02, curve = Curve.parametric(0)), | |
| gate = trigs, timeScale = durScale) | |
| son + BPF.ar(son, resFreq, 20) | |
| } | |
| // 34.9: woof | |
| play { | |
| LPF.ar(WhiteNoise.ar, 30) * 100 | |
| } | |
| // 34.10: woosh | |
| play { | |
| BPF.ar(WhiteNoise.ar, 30, 0.2) * 20 | |
| } | |
| // 34.11: shape | |
| play { | |
| LeakDC.ar(LeakDC.ar(BPF.ar(WhiteNoise.ar, 30, 0.2) * 50).clip2(0.9)) * 0.5 | |
| } | |
| // 34.12: putting it all together | |
| def fireGen = { | |
| // A common noise source | |
| val noise = WhiteNoise.ar | |
| // Hissing | |
| val hissing = HPF.ar(noise, 1000) * LFNoise2.kr(1).squared.squared | |
| // Crackle | |
| val trigs = Dust.kr(1) | |
| val durScale = TRand.kr(1, 1.5, trigs) // vary duration between default 20ms and 30ms | |
| val resFreq = TExpRand.kr(100, 1000, trigs) // different resonant frequency for each one | |
| val crack1 = noise * EnvGen.ar(Env.perc(0, 0.02, curve = Curve.lin), trigs, timeScale = durScale) | |
| val crackles = crack1 + BPF.ar(crack1, resFreq, 20) | |
| // Flame | |
| val lapping = LeakDC.ar(LeakDC.ar(BPF.ar(noise, 30, 0.2) * 50).clip2(0.9)) * 0.5 | |
| // Combine them: | |
| Mix(Seq(crackles * 0.1, hissing * 0.3, lapping * 0.6)) * 3 | |
| } | |
| play { fireGen } | |
| // 34.13: poly | |
| play { | |
| BPF.ar(fireGen, 600, 1/0.2) + | |
| BPF.ar(fireGen, 1200, 1/0.6) + | |
| BPF.ar(fireGen, 2600, 1/0.4) + | |
| HPF.ar(fireGen, 1000) | |
| } | |
| /*--- | |
| 35. Bubbles | |
| */ | |
| // 35.5: producing a repeating but random-seeming pattern of triggers | |
| val sdBubbleTrigs = SynthDef("bubbletrigs") { | |
| val out = "out".kr | |
| val probability = "probability".kr(0.5) | |
| // These two lines create a loop of zeroes | |
| // with some ones (i.e. triggers) placed at prime-number locations | |
| val sz = 200 | |
| val buf = LocalBuf(sz) | |
| val a = Seq.tabulate(sz)(i => | |
| if (Set(29, 37, 47, 67, 89, 113, 157, 197).contains(i)) 1 else 0 | |
| ) | |
| SetBuf(buf, a) | |
| // playbuf by default will use the server's rate, but we want one item every 15ms | |
| val pb = PlayBuf.kr(1, buf, 0.015.reciprocal / ControlRate.ir, loop = 1) | |
| // Randomly discard half of them, to remove too much obvious looping | |
| val trigs = CoinGate.kr(probability, pb) | |
| // Let's poll to watch the events appearing | |
| trigs.poll(trigs) // XXX TODO -- no triggers? | |
| Out.kr(out, trigs) | |
| } | |
| val x = sdBubbleTrigs.play() | |
| x.free() | |
| // 35.8: sound of a bubble | |
| val sdBubbleBub = SynthDef("bubblebub") { | |
| val out = "out".kr | |
| val t_trig = "t_trig".tr | |
| val attack = "attack".kr(0.01) | |
| val decay = "decay".kr(0.08) | |
| val pitchCurveLen = "pitchCurveLen".kr(0.1) | |
| val freq = "freq".kr(1000) | |
| val doneAction = "doneAction".kr(0) | |
| val amp0 = "amp".kr(0.1) | |
| val amp = amp0 * EnvGen.ar(Env.perc(attack, decay), t_trig, doneAction = doneAction) | |
| import Env.{Segment => Seg} | |
| val pchEnv = Env(1, List(Seg(0.003, 1), Seg(1, 2.718, Curve.exp))) | |
| val pitch = freq * EnvGen.ar(pchEnv, t_trig, timeScale = pitchCurveLen) | |
| val son = SinOsc.ar(pitch) | |
| // high-pass to remove any lowpitched artifacts, scale amplitude | |
| val sig = HPF.ar(son, 500) * amp * 10 | |
| Out.ar(out, sig) | |
| } | |
| val x = sdBubbleBub.play() | |
| x.set("t_trig" -> 1) | |
| /*--- | |
| 36. Running water | |
| */ | |
| // 36.3: random-frequency sines | |
| play { | |
| SinOsc.ar(LFNoise0.kr(170).linlin(-1, 1, 800, 2400)) * 0.3 | |
| } | |
| // 36.4: rising pitches | |
| def rising() = { | |
| val trigs = Dust.kr(170) | |
| val freq = | |
| // Generally choose from a varied base freq | |
| TExpRand.kr(800, 2000, trigs) + | |
| // Wobbly variation | |
| LFNoise2.kr(20) * 300 + | |
| // General tendency for upward rise | |
| EnvGen.kr(Env.perc(level = 17), trigs) | |
| SinOsc.ar(freq) * 0.3 | |
| } | |
| play(rising()) | |
| // hmmm, let's try combining a few of these in parallel. | |
| // do we sound like a river yet? | |
| play { | |
| Mix.fill(6)(rising()) / 6 | |
| } | |
| /*--- | |
| 38. Rain | |
| */ | |
| // 38.1: Fluid sphere impact | |
| def dropletOnHard = { | |
| val dur = "dur".kr(0.0005) | |
| import Env.{Segment => S} | |
| import Curve.{parametric => par} | |
| Env(0, List((1, dur/2, par(-4)), (0, dur/2, par(+4)))) | |
| } | |
| // 38.3: obtaining a Gaussian noise distribution | |
| play { | |
| val sig: GE = Seq.fill(2)(Mix.fill(12)(WhiteNoise.ar)) | |
| sig / 24 | |
| } | |
| play { | |
| val amount = MouseX.kr(0,1) // move mouse left/right to change amount | |
| val n1 = WhiteNoise.ar.abs * amount + (1-amount) | |
| val n2 = WhiteNoise.ar(2 * math.Pi) | |
| val gaussian = (n1.log * -2).sqrt * n2.cos | |
| (Seq(gaussian, gaussian): GE) * 0.5 | |
| } | |
| // 38.4: raindrop pressure on solid ground | |
| play { | |
| val noise = Mix.fill(12)(WhiteNoise.ar) | |
| val gaus = LPF.ar(BPF.ar(noise, 50, 1/0.4), 500) | |
| // | |
| val sin = SinOsc.ar(gaus.linlin(-1, 1, 40, 80)) * gaus.squared * 10 | |
| val clip = (sin - 0.35).max(0) | |
| val osc = Mix.fold(clip, 2)(HPF.ar(_, 500)) | |
| Seq(osc, osc) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment