// title: In-between, longing // author: jpdrecourt // description: // This is the full code of the piece "In-between, longing" posted here for reference. For a brief explanation of some of the features of the code, please check my [blog post](http://drecourt.com/writings/the-code-of-in-between-longing/). // You can also listen to the piece on [Bandcamp](https://jpdrecourt.bandcamp.com/album/in-between-longing-seed-0262). // Unfortunately, the sound files are copyrighted, so I can't share them here. // Feel free to reach out through my [website](http://drecourt.com/about/) if you have any questions. // code: ( s.options.memSize_(2**18); s.reboot; s.waitForBoot { Buffer.freeAll(s); Pdef.clear; s.freeAll; q.clear; s.sync; m = ProxySpace.new; // Mixer // Dictionaries v = (); // Variables f = (); // Functions p = (); // Patterns b = (); // Busses c = (); // Buffers g = (); // Groups i = (); // Synth (instruments) t = TempoClock.default; s.sync; // Various setup v[\seed] = 262; // Random seed v[\debug] = false; // Debugging messages v[\mixerOn] = false; // Visual mixer v[\record] = true; // Recording the output // Piece version thisThread.randSeed = v[\seed]; // Tempo variation t.tempo = 1; t.sched(0, {|beat| t.tempo = (60 + (12*sin((beat/200)*(2*pi))))/60; 1;}); v[\partDur] = 41; // Silence management v[\silenceProb] = 0.2; //////////////////////////////////////////////////////////// // SynthDefs //// Routing synth SynthDef(\route2, {|in = 0, out = 0| Out.ar(out, In.ar(in, 2)); }).add; //// Playing mono buffer SynthDef(\bufRdPan, {|out = 0, bufnum = 0, pan = 0.0, amp = 1.0, start = 0.0, end = 1.0, fade = 0.001, rate = 1.0| var sig, bStart, bEnd, env; bStart = start*BufFrames.ir(bufnum); bEnd = end*BufFrames.ir(bufnum); sig = BufRd.ar(1, bufnum, Phasor.ar(0, BufRateScale.ir(bufnum)*rate, bStart, bEnd, bStart), 0.0); env = Env([0.0, 1.0, 1.0, 0.0], [fade, (BufDur.ir(bufnum)*(end - start)/rate) - (2.0*fade), fade]).ar(Done.freeSelf); env = env*amp; sig = Pan2.ar(sig, pan); Out.ar(out, sig*env); }).add; //// Playing a mono buffer with a loop in the middle SynthDef(\bufRdPanInnerLoop, {|out = 0, bufnum = 0, pan = 0.0, amp = 1.0, lStart = 0.5, lWidth = 0.05, nLoop = 12| var sig, envGen; envGen = EnvGen.ar( Env([0, lStart, lStart + lWidth, lStart, lStart + lWidth, 1]*BufFrames.ir(bufnum), [lStart, lWidth, lWidth, lWidth, 1 - lStart - lWidth]*BufDur.ir(bufnum), releaseNode: 4, loopNode: 2, curve: 0 ), gate: Trig.ar(1, (lStart + (((2 * nLoop) + 1) * lWidth))*BufDur.ir(bufnum)), doneAction: Done.freeSelf ); sig = BufRd.ar(1, bufnum, envGen, 0); Out.ar(out, Pan2.ar(sig, pan, amp)); }).add; //// Playing an expanding or contracting loop SynthDef(\bufRdPanExpandLoop, {|out = 0, bufnum = 0, pan = 0.0 ,amp = 1.0, len = 2.0, sus = 1.0, t_trig = 1, dir = 1, minWidth = 0.2, initPos = 0.2| var sig, startPos, endPos, phase, fade, env; fade = (len - sus)/2.0; startPos = Env( levels: [(1 + dir), (1 + dir), (1 - dir)] / 2.0 * (initPos * (1 - (minWidth/2.0))), times: [fade, sus] ).kr() * BufFrames.kr(bufnum); endPos = Env( levels: ([(1 + dir), (1 + dir), (1 - dir)] / 2.0 * ((initPos * (1 + (minWidth/2.0)))- 1)) + 1, times: [fade, sus] ).kr() * BufFrames.kr(bufnum); phase = Phasor.ar(0, BufRateScale.kr(bufnum), startPos, endPos); env = Env( levels: [0, 1, 1, 0], times: [fade, sus, fade], curve: \sin ).kr(Done.freeSelf); sig = BufRd.ar(1, bufnum, phase)*env*amp; sig = Median.ar(7, sig); sig = Pan2.ar(sig, pan); Out.ar(out, sig); }).add; // FX generator f[\makeFx] = {|name, func| SynthDef(name, {|out = 0, amp = 1.0, wet = 1.0| var sig = In.ar(out, 2); sig = ((1 - wet)*sig) + (wet*SynthDef.wrap(func, prependArgs: [sig])); ReplaceOut.ar(out, sig*amp); }).add; }; f[\makeFx].(\companderFx, {|sig, thresh = 0.1, slope = 0.5, clamp = 0.02, relax = 0.4| sig = CompanderD.ar(sig, sig, thresh: thresh, slopeAbove: slope, clampTime: clamp, relaxTime: relax ); sig }); //// Masterchain FX f[\makeFx].(\masterChainFx, {|sig, thresh = 0.1, slope = 0.5, clamp = 0.02, relax = 0.4, hpfFreq = 50, gainDb = 0| sig = HPF.ar(sig, hpfFreq); sig = CompanderD.ar(sig, sig, thresh: thresh, slopeAbove: slope, clampTime: clamp, relaxTime: relax ); sig = sig*gainDb.dbamp; sig = Limiter.ar(sig, -0.7.dbamp, 0.006); sig }); //// EQ FX, hardcoded, easier but naughty ;) f[\makeFx].(\eqFx, {|sig| sig = BPeakEQ.ar(sig, freq: 2300, rq:1/1.1, db: 0.5); sig = BHiShelf.ar(sig, freq: 7910, db: 1.6, rs: 1.0); sig }); //// Haas FX f[\makeFx].(\haasFx, {|sig, delay = 0.020, gate = 1| Env([1, 1, 0], [0.1, 0.1], \lin, 1).kr(gate: gate, doneAction: Done.freeSelf); sig[1] = DelayN.ar(sig[1], 0.1, delay); sig }); //// Distorsion f[\makeFx].(\softclipFx, {|sig, preAmp = 1.0, postAmp = 1.0| var oldSig = sig; sig = (sig * preAmp).softclip; sig = Balance.ar(sig, oldSig); sig * postAmp; }); //// LFO panning with triangular wave f[\makeFx].(\triPanner, {|sig ,freq = 1.0, iphase = 0.0, lo = -1.0, hi = 1.0| sig = Balance2.ar(sig[0], sig[1], LFTri.kr(freq, iphase).range(lo, hi)); sig }); // Dust trigger for stutter SynthDef(\varyDust, {|out = 0, trigLow = 0.2, trigHigh = 0.6, trigChangeF = 0.5| var trig = Dust.kr(LFNoise0.kr(trigChangeF).range(trigLow, trigHigh)); Out.kr(out, trig); }).add; // Invert the phase of one channel Fx f[\makeFx].(\chPhaseInvertFx , {|sig| var sigLPF = LPF.ar(sig, 300); sig = sig - sigLPF; sig[1] = 0 - sig[1]; sig = sig + ((sigLPF[0] + sigLPF[1])/2); }); // Wavetable reader with bell type sound SynthDef(\wavetableBell, {|out = 0, freq = 200, t_trig = 1, firstBufnum, lastBufnum, release = 0.5, amp = 0.8, pan = 0, attack = 0.01, rq = 1.0, curve = -4| var env, sig, theBuf; env = Env.perc(attackTime: attack, releaseTime: release, curve: curve).kr(gate: t_trig); theBuf = Env([0, 0.9999], [release + attack]).kr(gate:t_trig).linlin(0, 1, firstBufnum, lastBufnum); sig = VOsc.ar(theBuf, freq); sig = BPF.ar(sig, freq, rq, 1/rq.sqrt); Out.ar(out, Pan2.ar(sig, pan, amp*env)); Env([1, 1], [release + attack]*1.2).kr(gate: t_trig, doneAction: Done.freeSelf); } ).add; // Bad radio Fx f[\makeFx].(\badRadioFx, {|sig, freq = 1100, staticWet = 0.4, noise = 0.05, rq = 0.6| var hum, dustNoise, staticNoise, humFreq, numHarms, dcSig; // Radio static (inspired by http://sccode.org/1-4Wu) numHarms = 7; humFreq = 100; hum = Array.fill(numHarms, {|i| SinOsc.ar( (i+1) * humFreq, 0, 1/numHarms)}); hum = hum.sum; dustNoise = Dust2.ar(LFNoise1.ar(0.5).range(1000,15000)); // Dust or Dust2 ? staticNoise = hum * dustNoise * LFNoise1.ar(1).range(0.8, 1.2); // Add DC parasites dcSig = Dust2.ar(LFNoise1.ar(5).exprange(500, 2000))*noise*Env([0, 1, 0], [0, 3], \exp, releaseNode: 1).kr(gate: Trig.kr(DetectSilence.kr(A2K.kr(sig[0]), -30.dbamp), 0.001)); // Add the static noise (Convolution) sig = SelectX.ar(staticWet, [sig, Convolution.ar(sig + dcSig, staticNoise)]); // Speaker effect sig = BPF.ar(sig, freq, rq, 1/(rq.sqrt)); sig = (sig*2).distort*0.5; sig }); // Random delay on the right channel Fx f[\makeFx].(\rndDelayRightFx, {|sig, changeFreq = 0.5| var time, lastTime, delayedTime, slope; time = LFNoise0.kr(changeFreq, 2.5, 2.5); lastTime = LastValue.kr(time); delayedTime = DelayN.kr(time, 0.03, 0.03); sig[1] = SelectX.ar(EnvGen.kr(Env([0, 0, 0, 1], [0.02, 0.02, 0.02], \sine), Changed.kr(time)), [DelayN.ar(sig[1], 5, lastTime), DelayN.ar(sig[1], 5, delayedTime)]); sig }); // Switch left and right channel randomly Fx f[\makeFx].(\switchLRFx, {|sig, switchFreq = 0.1| sig = SelectX.ar(Lag3.kr(LFClipNoise.kr(switchFreq)).linlin(-1, 1, 0, 1), [[sig[0], sig[1]], [sig[1], sig[0]]]); sig }); // Stutter Fx f[\makeFx].(\stutterFx, {|sig, bufLen = 20, trigIn, maxLen = 0.25| var rBuf, start, stop, trig, phase, stutterDur, d; // Create the buffer rBuf = LocalBuf(s.sampleRate*bufLen, 2).clear; // Record the incoming sound BufWr.ar(sig, rBuf, Phasor.ar(1, BufRateScale.ir(rBuf), 0.0, BufFrames.ir(rBuf))); // Trigger the buffer repetition trig = In.kr(trigIn); d = Dwhite(0.0, 1.0); // Extract from the buffer start = Demand.kr(trig, 0, d); stop = (start + ((Demand.kr(trig, 0, d))*maxLen)).min(1.0); stutterDur = BufDur.ir(rBuf)*(stop - start); // Read the buffer phase = Env( levels: [0, start*BufFrames.ir(rBuf), stop*BufFrames.ir(rBuf)], times: [0, stutterDur]).ar(gate: trig); sig = BufRd.ar(2, rBuf, phase); sig = sig*Env([0, 0, 1, 1, 0], [0, 0.001, inf, 0.001], releaseNode: 3).kr(gate: Trig.kr(trig, stutterDur)); // Scramble sig = SelectX.ar(Env([1, 1, 0], [inf, 0.1], releaseNode: 1).kr(gate: Trig.kr(trig, LFNoise0.kr(0.1).range(0.0, 2.0))), [sig, DelayC.ar(sig, 1.0, LFNoise0.ar(8).range(0.0, 1.0))]); sig }); // Convolution reverb with mono IR, and Haas delay to give a sense of space f[\makeFx].(\convRevFx8192, {|sig, irSpectrum, mul, haas| // Convolution reverb with mono sig = PartConv.ar(sig, 8192, irSpectrum, mul); sig[1] = DelayN.ar(sig[1], haas, haas); sig }); // Changing Echo Fx f[\makeFx].(\changingEchoFx, {|sig, send = 0.4, slope = 1.0, time = 10, decay = 5.0, gate = 1| var mul; mul = (Line.kr(0, send, time)*slope) + ((1 - slope)/2*send); sig = AllpassN.ar(sig*mul, 0.2, 0.2, decay, 1.0, sig); sig = sig*Env([1, 1, 0], [1, decay*1.5], \lin, 1).kr(gate: gate, doneAction: Done.freeSelf); sig }); // Band Pass filter Fx f[\makeFx].(\bpfFx, {|sig, gate = 1, freq = 850, rq = 2| sig = BPF.ar(sig, freq, rq, 1/rq.sqrt); sig = sig*Env([1, 1, 0], [1, 4], \lin, 1).kr(gate: gate, doneAction: Done.freeSelf); sig }); s.sync; // High pass filter Fx f[\makeFx].(\hpfFx, {|sig, gate = 1, freq = 1000| sig = HPF.ar(sig, freq); sig = sig*Env([1, 1, 0], [1, 4], \lin, 1).kr(gate: gate, doneAction: Done.freeSelf); sig }); // Guts Fx f[\makeFx].(\gutsFx, {|sig, freq = 150, rq = 0.1| sig = Mix.ar(Array.fill(7, {|i| CombL.ar(sig, 0.2, LFNoise1.kr(0.1*((LFTri.kr(0.01, 0, 4.9, 5)*i) + 1), 0.08, 0.1)/((i + 1)), 2)*0.5 })); 4.do({ sig = AllpassN.ar(sig, 0.1, [LFNoise1.kr(0.1.rand, 0.04, 0.05), LFNoise1.kr(0.1.rand, 0.04, 0.05)], 5) }); sig = BPF.ar(sig, freq, rq); sig }); // MultiDelay Fx f[\makeFx].(\multiDelayFx, {|sig, combDelay = 1.7, allpassDelay = 2.5, decayTime = 5.0| var n, harm, amps, ring; sig = CombN.ar(AllpassN.ar(sig, allpassDelay, allpassDelay, decayTime, ), combDelay, combDelay, decayTime); sig }); // Wash Reverb Fx f[\makeFx].(\washReverbFx, { |sig, gate = 1.0| // From 17_Delays_reverbs var z, y; z = DelayN.ar(HPF.ar(sig, 300), 0.1); // 7 length modulated comb delays in parallel : y = Mix.ar(Array.fill(7,{ CombL.ar(z, 0.1, LFNoise1.kr(0.1.rand, 0.04, 0.05), 15) })); // two parallel chains of 4 allpass delays (8 total) : 4.do({ y = AllpassN.ar(y, 0.050, [0.050.rand, 0.050.rand], 1) }); sig = y; sig }); // High shelf FX f[\makeFx].(\highShelfFx, {|sig, freq = 1200, rs = 1.0, db = 0.0| sig = BHiShelf.ar(sig, freq, rs, db); sig }); // Phaser f[\makeFx].(\phaserFx, {|sig, delay = 0.2, decay = 1.0| var theDelay = delay + SinOsc.kr([4, 5], [0, pi/2], 0.05*delay); sig = AllpassN(sig, delay, delay, decay) - sig; sig }); // Theta wave distortion f[\makeFx].(\thetaDistortFx, {|sig, freq = 6.0, preAmp = 0.5| var oldSig, control = SinOsc.ar(freq, 0.0, preAmp); oldSig = sig; sig = Compander.ar(sig, control, 0.9, 1.0, 0.0, 0.001, 0.001); sig = Balance.ar(sig, oldSig); sig }); // Simple envelope out on bus SynthDef(\simpleEnv, {|out = 0, startVal = 0.0, endVal = 1.0, dur = 10.0, curve = \sin| Out.kr(out, Env([startVal, endVal], [dur], curve).kr(Done.freeSelf)); }).add; // Setup a convolution reverb f[\convSetup] = {|ir, channel, amp, synth = \convRevFx8192| Synth(synth, [\out, b[channel], \irSpectrum, c[\IR][ir][\buffer], \mul, c[\IR][ir][\mul], \haas, c[\IR][ir][\haas], \amp, amp ], g[channel], \addToTail) }; // Mouse XY router SynthDef(\mouseXY, {|outX, minX =0, maxX = 1, warpX = 0, outY, minY = 0, maxY = 0, warpY = 0| Out.kr(outX, Poll(MouseButton.kr, MouseX.kr(minX, maxX, warpX))); Out.kr(outY, Poll(MouseButton.kr, MouseY.kr(minY, maxY, warpY))); }).add; b[\mouseX] = Bus.control(s, 1); b[\mouseY] = Bus.control(s, 1); //////////////////////////////////////////////////////////// ////// cKey: Key for a channel (adds extra zero for channels 0-9) f[\cKey] = {|i| ("c" ++ i.asString.padLeft(2, "0")).asSymbol }; //////////////////////////////////////////////////////////// // Basic mixer // Convention: // Send effects: m[\c00] to m[\c09] (max 9) // Channels: m[\c10] to m[\c99] (max 90) v[\nChannels] = 15; v[\nSends] = 4; b[\master] = 0; b[\send] = (); s.sync; // Channels v[\nChannels].do { |i| var ch = f[\cKey].(i + 10); var chWrapper = (ch ++ "Wrap").asSymbol; b[ch] = Bus.audio(s, 2); b[chWrapper] = Bus.audio(s, 2); g[chWrapper] = Group.new; // Send the bus to the master bus Synth.tail(g[chWrapper], \route2, [\in, b[chWrapper], \out, b[\master]]); s.sync; m[ch].play(out: b[chWrapper], numChannels: 2, group: g[chWrapper], addAction: \addToHead); // Create the channel and play on its private bus // Group where to insert the instrument m[ch].source_({|pan = 0.0, width = 1.0| var thewidth = width.min(1 - pan.abs); var sig = In.ar(b[ch], 2); Splay.ar(sig, thewidth, 1, pan); }); s.sync; g[ch] = Group.new(g[chWrapper], \addToHead); }; Spec.add(\width, ControlSpec(0.0, 1.0, default: 1.0)); // Sends v[\nSends].do { |i| var snd = f[\cKey].(i); var sndWrapper = (snd ++ "Fx").asSymbol; b[snd] = Bus.audio(s, 2); g[sndWrapper] = Group.new; // Send the bus to the master bus Synth.tail(g[sndWrapper], \route2, [\in, b[snd], \out, b[\master]]); // Group where the FX should be inserted g[snd] = Group.new(g[sndWrapper], \addToHead); s.sync; // Create the channel and play it before the FX group m[snd].play(b[snd], 2, group: g[sndWrapper], addAction: \addToHead); s.sync; // Capture each channel post fader v[\nChannels].do { |j| var ch = f[\cKey].(j + 10); var chWrapper = (ch ++ "Wrap").asSymbol; var mix = (\mix ++ (j + 10)).asSymbol; m[snd][j + 10] = \mix -> {In.ar(b[chWrapper], 2)}; m[snd].set(mix, 0.0); // Adds a proper slider for the ProxyMixer Spec.add(mix, ControlSpec(0, 6.dbamp, \amp, 0, 1.0)); }; }; Spec.add(\amp, ControlSpec(0, 6.dbamp, \amp, 0, 1.0)); // Master chain s.sync; i[\masterChain] = (); i[\masterChain][\compLim] = Synth.tail(s, \masterChainFx, [\out, b[\master], \thresh, 0.075, \gainDb, 12.5]); i[\masterChain][\eq] = Synth.before(i[\masterChain][\compLim], \eqFx, [\out, b[\master]]); // Visual mixer s.sync; v[\mixerOn].if { v[\mixer] = ProxyMixer(m); ProxyMeter.addMixer(v[\mixer]); CmdPeriod.doOnce({ v[\mixer].close }); }; //////////////////////////////////////////////////////////// // Variables and functions init //// Paths v[\path] = (); if(thisProcess.platform.name == \windows, {v[\path][\root] = PathName.new(thisProcess.nowExecutingPath).parentPath}, {v[\path][\root] = PathName.new("~").fullPath} ); v[\path][\data] = v[\path][\root] +/+ "Data Files"; v[\path][\IR] = v[\path][\data] +/+ "IR"; v[\path][\IRData] = v[\path][\IR] +/+ "IRData.txt"; v[\path][\groupSequence] = v[\path][\data] +/+ "8_groups_sequence.txt"; v[\path][\media] = v[\path][\root] +/+ "Media Files"; //// Load IRs c[\IR] = (); TabFileReader.read(v[\path][\IRData], true).do {|row| var name = row[0].asSymbol; c[\IR][name] = (); c[\IR][name][\buffer] = Buffer.read(s, v[\path][\IR] +/+ row[1]); c[\IR][name][\fftSize] = row[2].asInteger; c[\IR][name][\mul] = row[3].asFloat; c[\IR][name][\haas] = row[4].asFloat; }; //// Soundfiles list v[\soundFiles] = (); PathName(v[\path][\media]).folders.do { |folder| (folder.folderName.asSymbol === \story).if { // Story file list update later v[\soundFiles][\story] = (); } { // Other folders treated as one v[\soundFiles][folder.folderName.asSymbol] = SoundFile.collect( folder.fullPath +/+ "*.flac"); } }; //// Remember Wavetable v[\soundFiles][\rememberWT] = (); PathName(v[\path][\media] +/+ \remember).folders.do { |folder| v[\soundFiles][\rememberWT][folder.folderName.asSymbol] = SoundFile.collect( folder.fullPath +/+ "*.wavetable"); }; //// Garbage collection v[\garbageDelta] = 20; //// Recording v[\record].if { s.record(v[\path][\root] +/+ 'Recordings' +/+ 'In_Between-Longing-' ++ v[\seed].asString.padLeft(4, "0") ++ ".aif", b[\master], 2, duration:70*60); }; //// Functions ////// rndBufs : Select randomly (with repetition) a given number of files ////// in the soundFileList (created with SoundFile.collect) and create buffers ////// Returns the buffers f[\rndBufs] = { |soundFileList, nFiles = 1| var bufferArray, isLoaded; isLoaded = Array.fill(nFiles, false); bufferArray = Array.fill(nFiles, {|i| var buffer; buffer = Buffer.read(s, soundFileList.choose.path, action: {isLoaded[i] = true}); }); bufferArray }; ////// bufInfo : Returns a string with the buffer number and the file name w/o path f[\bufInfo] = {|b| "" ++ b.bufnum ++ " -> " ++ PathName(b.path).fileName }; //////toGarbage: Schedules a buffer for freeing f[\toGarbage] = {|buffer, delta = (v[\garbageDelta])| // postln("Scheduling for freeing: " ++ f[\bufInfo].(buffer)); AppClock.sched(delta, { // postln("Freeing: " ++ f[\bufInfo].(buffer)); buffer.free; }); }; ////// bufDur: Returns the buffer duration or zero (useful if the buffer is late) f[\bufDur] = {|buf| var bufDur = 0; try {bufDur = buf.duration}; bufDur }; ////// Trace the buffer number f[\bufDebug] = {|pattern| Pchain(Pbind(\callback, {postln(try {"Playing: " ++ f[\bufInfo].(~bufnum)}{postln(~instrument)})}), pattern) }; ////// Resetting a part using the f[\partReset] function f[\resetPart] = {|part, delta| TempoClock.sched(delta,{ f[(part ++ \Reset).asSymbol].(); nil }); }; s.sync; //////////////////////////////////////////////////////////// // MasterChain effects //// Theta distorsion i[\masterChain][\thetaDistort] = Synth.before(i[\masterChain][\compLim],\thetaDistortFx, [\out, b[\master]]); b[\masterThetaFreq] = Bus.control(s, 1).value_(4.0); b[\masterThetaPreAmp] = Bus.control(s, 1).value_(0.0); i[\masterChain][\thetaDistort].map(\freq, b[\masterThetaFreq]); i[\masterChain][\thetaDistort].map(\preAmp, b[\masterThetaPreAmp]); //////////////////////////////////////////////////////////// // Send effects //// c00: Stutter radio i[\c00] = (); b[\varyDust] = Bus.control(s); i[\c00][\varyDust] = Synth(\varyDust, [\out, b[\varyDust], \trigHigh, 0.55], g[\c00]); i[\c00][\stutterFx] = Synth(\stutterFx, [\trigIn, b[\varyDust], \out, b[\c00]], g[\c00], \addToTail); i[\c00][\badRadioFx] = Synth(\badRadioFx, [\out, b[\c00], \amp, 3.dbamp], g[\c00], \addToTail); //// c01: Convolution reverb 1 b[\c01Amp] = Bus.control(s, 1).value_(1.0); //// c02: Convolution reverb 2 b[\c02Amp] = Bus.control(s, 1).value_(0.0); //// c03: Wash reverb i[\c03] = (); i[\c03][\washReverb] = Synth(\washReverbFx, [\out, b[\c03], \amp, 1.0], g[\c03]); //////////////////////////////////////////////////////////// // Story c[\story] = (); v[\storyRhythms] = [ Pseq([5, 4, 2, 1, 4, 6], inf)*Pwhite(0.9, 1.1), Pn(Pgeom(1, 1.23, 7)*2), Pn(Pgeom(4, 0.9, 7)*1.5) ]; //// Story effects i[\c10] = (); i[\c10][\rndDelayRight] = Synth(\rndDelayRightFx, [\out, b[\c10], \wet, 1, \amp, 1], g[\c10], \addToTail); i[\c10][\switchLR] = Synth(\switchLRFx, [\out, b[\c10], \amp, 1.0], g[\c10], \addToTail); //// Story data v[\storyGroups] = Array.with( nil, [\Corridor, \Walls, \Creating, \Brightday, \Inbetween, \Stable], // G1 [\Six, \Talked, \Hair, \Eyes, \Boys], // G2 [\Moment, \Walking, \Side, \Was, \Other], // G3 [\Alone, \Close, \Friend, \Name, \Knew], // G4 [\Following, \Ahead, \Sure, \Facing, \Longing], // G5 [\Smocks, \Painted, \Bricks, \Brise, \Casting], // G6 [\Roofs, \Stone, \Tarmac, \Intimacy], // G7 [\Incredible, \Wanting, \Someone, \Away, \Stay, \Anywhere, \Lost] // G8 ); //// Initialize patterns v[\storyGroups].do {|group, iGroup| group.notNil.if { v[\storyGroups][iGroup].do{|item, iItem| // Creates the patterns with an empty buffer array // The array will be filled at initialisation c[\story][item.asSymbol] = []; v[\soundFiles][\story][item] = SoundFile.collect(v[\path][\media] +/+ "story" +/+ "G" ++ iGroup ++ "-" ++ item ++ "-*.flac"); p[(\story ++ item).asSymbol] = Pbind( \instrument, \bufRdPan, \bufnum, Pfuncn {c[\story][item].choose}, \amp, 0.4, ); }; }; }; //// FSM for each group p[\storyG1] = Pfsm([ #[0, 2, 4, 5], p[(\story ++ v[\storyGroups][1][0]).asSymbol], #[1, 2, 3, 4, 5], p[(\story ++ v[\storyGroups][1][1]).asSymbol], #[2, 4,5], p[(\story ++ v[\storyGroups][1][2]).asSymbol], #[1, 3], p[(\story ++ v[\storyGroups][1][3]).asSymbol], #[0, 1, 2], p[(\story ++ v[\storyGroups][1][4]).asSymbol], #[0, 1, 2, 5], p[(\story ++ v[\storyGroups][1][5]).asSymbol], #[0, 2, 4], nil, nil ]); p[\storyG2] = Pfsm([ #[0, 1], p[(\story ++ v[\storyGroups][2][0]).asSymbol], #[1, 4], p[(\story ++ v[\storyGroups][2][1]).asSymbol], #[0, 2, 3, 4], p[(\story ++ v[\storyGroups][2][2]).asSymbol], #[3, 4], p[(\story ++ v[\storyGroups][2][3]).asSymbol], #[2, 4], p[(\story ++ v[\storyGroups][2][4]).asSymbol], #[0, 1, 2, 3], nil, nil ]); p[\storyG3] = Pfsm([ #[0, 1], p[(\story ++ v[\storyGroups][3][0]).asSymbol], #[1, 2, 3], p[(\story ++ v[\storyGroups][3][1]).asSymbol], #[0, 2, 3], p[(\story ++ v[\storyGroups][3][2]).asSymbol], #[0, 1, 3, 4], p[(\story ++ v[\storyGroups][3][3]).asSymbol], #[2, 4], p[(\story ++ v[\storyGroups][3][4]).asSymbol], #[0, 1, 3], nil, nil ]); p[\storyG4] = Pfsm([ #[0, 1, 3, 4], p[(\story ++ v[\storyGroups][4][0]).asSymbol], #[1, 3, 4], p[(\story ++ v[\storyGroups][4][1]).asSymbol], #[2, 3, 4], p[(\story ++ v[\storyGroups][4][2]).asSymbol], #[1, 3, 4], p[(\story ++ v[\storyGroups][4][3]).asSymbol], #[0, 1, 2, 4], p[(\story ++ v[\storyGroups][4][4]).asSymbol], #[1, 3], nil, nil ]); p[\storyG5] = Pfsm([ #[0, 1, 2, 3, 4], p[(\story ++ v[\storyGroups][5][0]).asSymbol], #[1, 2, 3, 4], p[(\story ++ v[\storyGroups][5][1]).asSymbol], #[0, 2, 3, 4], p[(\story ++ v[\storyGroups][5][2]).asSymbol], #[0, 1, 3, 4], p[(\story ++ v[\storyGroups][5][3]).asSymbol], #[0, 1, 2, 4], p[(\story ++ v[\storyGroups][5][4]).asSymbol], #[0, 1, 2, 3], nil, nil ]); p[\storyG6] = Pfsm([ #[0, 1, 2], p[(\story ++ v[\storyGroups][6][0]).asSymbol], #[1, 2, 4], p[(\story ++ v[\storyGroups][6][1]).asSymbol], #[0, 2], p[(\story ++ v[\storyGroups][6][2]).asSymbol], #[1, 3, 4], p[(\story ++ v[\storyGroups][6][3]).asSymbol], #[1, 2, 4], p[(\story ++ v[\storyGroups][6][4]).asSymbol], #[0, 1, 2, 3], nil, nil ]); p[\storyG7] = Pfsm([ #[0, 1, 2, 3], p[(\story ++ v[\storyGroups][7][0]).asSymbol], #[1, 2, 3], p[(\story ++ v[\storyGroups][7][1]).asSymbol], #[0, 2, 3], p[(\story ++ v[\storyGroups][7][2]).asSymbol], #[0, 1, 3], p[(\story ++ v[\storyGroups][7][3]).asSymbol], #[0, 1, 2], nil, nil ]); p[\storyG8] = Pfsm([ #[0, 1, 2, 3, 6], p[(\story ++ v[\storyGroups][8][0]).asSymbol], #[1, 2, 4, 5, 6], p[(\story ++ v[\storyGroups][8][1]).asSymbol], #[0, 2, 3, 4, 5, 6], p[(\story ++ v[\storyGroups][8][2]).asSymbol], #[0, 1, 3, 4, 6], p[(\story ++ v[\storyGroups][8][3]).asSymbol], #[0, 1, 2, 4, 6], p[(\story ++ v[\storyGroups][8][4]).asSymbol], #[0, 5, 6], p[(\story ++ v[\storyGroups][8][5]).asSymbol], #[0, 3, 4, 6], p[(\story ++ v[\storyGroups][8][6]).asSymbol], #[0], nil, nil ]); //// Load group sequence and start at a random place v[\groupSequence] = File.readAllString(v[\path][\groupSequence]); v[\iGroup] = v[\groupSequence].size.rand; f[\storyReset] = { // Clean old buffers v[\storyGroups][v[\groupSequence][v[\iGroup]].digit].do {|item| c[\story][item].do {|buf| f[\toGarbage].(buf); }; }; // Choose the rhythm v[\storyRhythm] = v[\storyRhythms].choose; // Change the frequencies i[\c10][\rndDelayRight].set(\changeFreq, 0.8.rand); i[\c10][\switchLR].set(\switchFreq, 0.8.rand); // Prepare new buffers v[\iGroup] = (v[\iGroup] + 1)% v[\groupSequence].size; v[\storyGroups][v[\groupSequence][v[\iGroup]].digit].do {|item| c[\story][item] = f[\rndBufs].(v[\soundFiles][\story][item], 3) }; // Return nothing nil }; //// First initialisation f[\storyReset].(); //// Init story pattern p[\storyTold] = Plazy { p[(\storyG ++ v[\groupSequence][v[\iGroup]]).asSymbol] <> Pbind(\delta, v[\storyRhythm]); }; //// Story pattern p[\story] = p[\storyTold]; p[\story] = (p[\story] <> (group: g[\c10], out: b[\c10])); v[\debug].if {p[\story] = f[\bufDebug].(p[\story])}; //////////////////////////////////////////////////////////// // Ands //// Ands variations v[\andsPanVars] = Array.with( (Pgeom(1, 0.95) - 1) * Pseq([-1, 1], inf), // Expanding Pgeom(1, 0.95) * Pseq([-1, 1], inf), // Concentrating ); v[\shortAndsVars] = Array.with ( { // Expand/Contract Pseq([ Event.silent(4.0), Pbind( \instrument, \bufRdPan, \bufnum, Pseq([Pfuncn {c[\ands][\short].choose}], {20 + 20.rand}), \delta, Pfunc {0.1.rand}, \rate, Pseq([ Pn(1, 10), 25 - Pgeom(15, 0,9) ]), \pan, Plazy {v[\andsPan]}, \amp, Pseq([Pn(0.4, 10), Pn(0.2)]), )], inf)},{ // Bursts var pat; pat = Pbind( \instrument, \bufRdPan, \bufnum, Pstutter(4, Pfunc {c[\ands][\short].choose}), \delta, Pseq([1, 0.1, 0.5, Pfuncn {(4.0 + 4.0.rand)}], inf), \amp, Pseq([0.2, 0.25, 0.32, 0.4], inf), \pan, Pn(Pstutter(4, Pwhite(-1.0, 1.0, 1)) * Pgeom(1, 0.5, 4)) ); pat = Ptpar([0.0, pat, {4.0.rand}, pat]); pat} ); //// Ands Init c[\ands] = (); f[\andsReset] = { // Clean old buffers c[\ands].do {|bufs| bufs.do {|buf| f[\toGarbage].(buf); }; }; // Variations v[\andsPan] = v[\andsPanVars].choose; v[\shortAnds] = v[\shortAndsVars].choose; // Select new buffers c[\ands][\long] = f[\rndBufs].(v[\soundFiles][\andLong], 1); c[\ands][\short] = f[\rndBufs].(v[\soundFiles][\andVowel], 5); // Return nothing nil }; f[\andsReset].(); //// Ands Patterns p[\longAnds] = Pbind( \instrument, \bufRdPanInnerLoop, \bufnum, Pfunc {c[\ands][\long].choose}, \delta, 6, \nLoop, Pstutter(inf, Pfuncn {2 + 7.rand}), \lWidth, Pstutter(inf, Pfuncn {0.2.rand + 0.01}), \lStart, Pstutter(inf, Pfuncn {0.5.rand + 0.1}), \amp, 0.4, ); p[\shortAnds] = Plazy ({v[\shortAnds].()}); p[\ands] = Ppar([p[\longAnds], p[\shortAnds]]); p[\ands] = p[\ands] <> (group: g[\c11], out: b[\c11]); v[\debug].if {p[\ands] = f[\bufDebug].(p[\ands])}; //////////////////////////////////////////////////////////// // Colours //// Colours init c[\colours] = (); i[\colours] = (); i[\colours][\triPanner] = Synth(\triPanner, [\freq, 0.1, \amp, 1.0, \out, b[\c12]], g[\c12]); f[\coloursReset] = { // Clean old buffers c[\colours].do {|bufs| bufs.do {|buf| f[\toGarbage].(buf); }; }; // Variants v[\shadowsLen] = 10 + 10.0.rand; i[\colours][\triPanner].set(\freq, 1/rrand(5.0, 20.0)); v[\nReds] = rrand(5, 10); v[\nBW] = 3 + 5.rand; v[\shadowsDelta] = 7.0 + 2.0.rand; v[\shadowsExpand] = 1.0 + 0.1.rand2; // Select new buffers [\black, \red, \white, \shadows, \brightWhisper, \darkWhisper, \shadeWhisper].do { |item| c[\colours][item] = f[\rndBufs].(v[\soundFiles][item], 3); }; // Return nothing nil }; f[\coloursReset].(); //// Colours patterns ////// Whispered spirals p[\coloursWhisperedSpirals] = Pbind( \instrument, \bufRdPanExpandLoop, \len, Pfunc {v[\shadowsLen] + 2.5.rand2}, \sus, Pkey(\len)/2, \amp, 0.1, \initPos, 0.4, \minWidth, 0.4, \bufnum, Prand([ Pfuncn {c[\colours][\brightWhisper].choose}, Pfuncn {c[\colours][\darkWhisper].choose}, Pfuncn {c[\colours][\shadeWhisper].choose}, ], inf), \dir, Pgeom(1, -1, inf), \delta, (Pkey(\sus) + Pkey(\len))/2, ); p[\coloursWhisperedSpirals] = p[\coloursWhisperedSpirals] <> (group: g[\c12], out: b[\c12]); ////// BWR p[\coloursBWR] = Pseq([Event.silent(1.0), Pbind(\instrument, \bufRdPan, \bufnum, Pfin({v[\nBW]}, Prand([ Pfuncn({c[\colours][\black].choose}), Pfuncn({c[\colours][\white].choose}),], inf)), \pan, Pfunc {1.0.rand2}, \delta, Pfunc {2 + 2.0.rand}, \amp, 0.4, ), Pbind(\instrument, \bufRdPan, \bufnum, Pfunc({c[\colours][\red].choose}), \panValue, Pstutter({v[\nReds]}, Pfunc({1.0.rand2})), \pan, Pcollect({|item| item + 0.1.rand2}, Pkey(\panValue)), \delta, Pn(Pfuncn({0.1.rand}), {v[\nReds]}), \amp, 0.25, ), Event.silent(3.0) ], inf); p[\coloursBWR] = p[\coloursBWR] <> (group: g[\c13], out: b[\c13]); ////// Shadows i[\colours][\haas] = Synth(\haasFx, [\amp, 1.0, out: b[\c14]], g[\c14]); p[\coloursShadows] = Pseq([Plazy {Event.silent(v[\shadowsDelta])}, Pbind( \instrument, \bufRdPan, \bufnum, Pfunc {c[\colours][\shadows].choose}, \delta, Pfunc {v[\shadowsDelta]}, \amp, 0.45, \action, Pn(Plazy { v[\shadowsDelta] = v[\shadowsDelta]*v[\shadowsExpand]; })) ]); p[\coloursShadows] = p[\coloursShadows] <> (group: g[\c14], out: b[\c14]); ////// Colours together p[\colours] = Ppar([ p[\coloursBWR], p[\coloursShadows], p[\coloursWhisperedSpirals], ]); v[\debug].if {p[\colours] = f[\bufDebug].(p[\colours])}; //////////////////////////////////////////////////////////// // Intimacy //// Intimacy init c[\intimacy] = (); f[\intimacyReset] = { // Clean old buffers c[\intimacy].do {|bufs| bufs.do {|buf| f[\toGarbage].(buf); }; }; // Select new buffers [\intimacy, \close].do { |item| c[\intimacy][item] = f[\rndBufs].(v[\soundFiles][item], 3); }; // Return nothing nil }; f[\intimacyReset].(); //// Intimacy patterns p[\closeWiden] = Pbind( \instrument, \bufRdPan, \bufnum, Pfunc {c[\intimacy][\close].choose}, \start, Pseg([0, 0, 0], [6, 2]), \end, Pseg([0.1, 1, 1], [6, 2]), \pan, Pseg([1, 0, 0], [6, 2])*Pseq([1, -1], inf), \delta, (Pkey(\end) - Pkey(\start))*1.2, \amp, 0.4, ); p[\closeWiden] = Pfxb(p[\closeWiden], \changingEchoFx, \slope, -1.0, \time, 12, \send, 0.6, \amp, 1.0 ); p[\closeNarrow] = Pbind( \instrument, \bufRdPan, \bufnum, Pfunc {c[\intimacy][\close].choose}, \start, Pseg([0, 0.2, 0.2], [6, 5]), \end, Pseg([1, 0.5, 0.3], [6, 5]), \pan, Pseg([0, 1, 1], [6, 5])*Pseq([1, -1], inf), \delta, (Pkey(\end) - Pkey(\start))*1.1, \amp, 0.4 ); p[\closeNarrow] = Pfxb(p[\closeNarrow], \changingEchoFx, \slope, -1.0, \time, 12, \send, 0.6, \amp, 1.0 ); p[\oneIntimacy] = Pbind( \instrument, \bufRdPan, \bufnum, Pfuncn {c[\intimacy][\intimacy].choose}, \delta, 1.5, \amp, 0.8 ); p[\oneIntimacy] = Pfxb(p[\oneIntimacy], \bpfFx, \amp, 1.5, \rq, 1, \freq, 900); p[\intimacy] = Pseq([Prand([p[\closeWiden], p[\closeNarrow]]), Plazy {Event.silent(3.0.rand)}, p[\oneIntimacy], Plazy {Event.silent(5.0.rand)}], inf); p[\intimacy] = p[\intimacy] <> (group: g[\c15], out: b[\c15]); v[\debug].if {p[\intimacy] = f[\bufDebug].(p[\intimacy])}; //////////////////////////////////////////////////////////// // Incredible //// Incredible Init c[\incredible] = (); v[\partIncredibleVars] = Array.with( Pn(Pbind( \instrument, \bufRdPan, \bufnum, Pfuncn {c[\incredible][\incredible].choose}, \start, Pfuncn {0.7.rand}, \end, Pcollect({|item| rrand(item + 0.1, 1.0)}, Pkey(\start)), \fade, 0.01, \delta, Pfuncn {0.4.rand}, \pan, Pfuncn {1.0.rand2}, \amp, Pfuncn {rrand(0.2, 0.5)}, ), {rrand(20, 30)}), Ppar(Pseq([ Plazy {Event.silent(4.0.rand)}, Pbind( \instrument, \bufRdPan, \bufnum, Pstutter(inf, Pfuncn {c[\incredible][\incredible].choose}), \start, Pseries(0, 0.01, 90), \end, Pkey(\start) + 0.1, \pan, Pgeom(0.1, -1.024, 90), // \pan, Pwhite(-1.0, 1.0), \delta, Pgeom({0.2 + 0.1.rand}, 0.98), \amp, Prand([ 0.0, 0.6], inf), \fade, 0.0005, \rate, Pgeom(1, 1.0007, inf) )])!4); ); f[\incredibleReset] = { // Clean old buffers c[\incredible].do {|bufs| bufs.do {|buf| f[\toGarbage].(buf); }; }; // Select variant v[\partIncredible] = v[\partIncredibleVars].choose; // Select new buffers [\incredible].do { |item| c[\incredible][item] = f[\rndBufs].(v[\soundFiles][item], 3); }; // Return nothing nil }; f[\incredibleReset].(); //// Incredible patterns p[\partIncredible] = Pfxb(Plazy {v[\partIncredible]}, \hpfFx, \freq, 165, \amp, 1.0); p[\oneIncredible] = Pseq([Event.silent(1.0), Pbind( \instrument, \bufRdPan, \bufnum, Pfuncn {c[\incredible][\incredible].choose}, \delta, 1, \amp, 0.70, ) ]); p[\oneIncredible] = Pfxb(p[\oneIncredible], \haasFx, \delay, {rrand(0.01, 0.025)}, \amp, 1.0); p[\incredible] = Pseq([p[\oneIncredible], Plazy {Event.silent(3.0.rand)}, p[\partIncredible], Plazy {Event.silent(5.0.rand)}], inf); p[\incredible] = p[\incredible] <> (group: g[\c16], out: b[\c16]); v[\debug].if {p[\incredible] = f[\bufDebug].(p[\incredible])}; //////////////////////////////////////////////////////////// // I remember //// Remember Init c[\remember] = (); f[\rememberReset] = { // Clean old buffers c[\remember].do {|bufs| bufs.do {|buf| f[\toGarbage].(buf); }; }; // Change the scrambling and the number of repetitions v[\rememberSpliceLen] = rrand(0.08, 0.12); v[\startSeq] = (0, v[\rememberSpliceLen]..1).scramble.stutter(1 + 3.rand); // Select new buffers [\remember].do { |item| c[\remember][item] = f[\rndBufs].(v[\soundFiles][item], 1); }; // Return nothing nil }; f[\rememberReset].(); s.sync; //// Chasing effect i[\remember] = (); i[\remember][\multiDelay] = Synth(\multiDelayFx, [\out, b[\c17], \wet, 0.3, \amp,1.5], g[\c17]); // Pan goes left to right and back to centre v[\pan] = Array.series((v[\startSeq].size*0.5).floor, -1, (1/(v[\startSeq].size*0.5).floor)*2) ++ Array.series((v[\startSeq].size*0.5).ceil, 1, -1/(v[\startSeq].size*0.5).ceil); //// Remember parameters p[\leftFaster] = Pbind( \instrument, \bufRdPan, \bufnum, Pfunc {c[\remember][\remember].choose}, \start, Pseq(v[\startSeq]), \end, Pkey(\start) + v[\rememberSpliceLen], \amp, 0.4, \delta, 0.4 * 2 * v[\rememberSpliceLen] * Pgeom(3, 0.96), \pan, Pseq(v[\pan]) ); p[\leftSlower] = Pbindf(p[\leftFaster], \delta, 0.4 * v[\rememberSpliceLen] * Pgeom(0.4, 1.08)); p[\rightSlower] = Pbindf(p[\leftSlower], \pan, 0 - Pseq(v[\pan])); p[\rightFaster]= Pbindf(p[\leftFaster], \pan, 0 - Pseq(v[\pan])); p[\remember] = Pseq([ Pseq([ Plazy {Event.silent(3.0.rand)}, Prand([p[\leftSlower], p[\rightSlower], p[\leftFaster], p[\rightFaster]]) ], 2), Plazy {Event.silent(3.0.rand)} ], inf); p[\remember] = p[\remember] <> (group: g[\c17], out: b[\c17]); v[\debug].if {p[\remember] = f[\bufDebug].(p[\remember])}; //////////////////////////////////////////////////////////// // Silence p[\silence] = Event.silent(inf); //////////////////////////////////////////////////////////// // Clarity //// Clarity init v[\octaScale] = Scale.new(#[0, 2, 3, 5, 6, 8, 9, 11], name: "octatonic"); f[\shepardDegrees] = {|x| ((((0, 9..63) + x)%72) - 32).sort}; c[\clarity] = []; f[\clarityReset] = { // Clean old buffers c[\clarity].do {|buf| f[\toGarbage].(buf); }; // Load a set of wavetables v[\rememberWTs] = v[\soundFiles][\rememberWT].choose; c[\clarity] = Buffer.allocConsecutive(v[\rememberWTs].size, s, 2048, 1, {|buf, i| buf.readMsg(v[\rememberWTs][i].path); }); // Return nothing nil }; //// First clarity init f[\clarityReset].(); //// Clarity pattern i[\clarity] = (); i[\clarity][\phaser] = Synth(\phaserFx, [\out, b[\c18], \delay, 0.01, \decay, 0.3, \amp, 1.0], g[\c18], \addToTail); i[\clarity][\hpf] = Synth(\hpfFx, [\out, b[\c18], \amp, 1.0, \freq, 110], g[\c18], \addToTail); p[\clarity] = Pbind( \instrument, \wavetableBell, \scale, v[\octaScale], \degree, Pcollect(f[\shepardDegrees], Pseq((0..71).rotate(72.rand), inf)), \attack, v[\partDur]/5*Pwhite(1.0, 1.3), \release, v[\partDur]/3*Pwhite(1.0, 1.3), \firstBufnum, c[\clarity].first.bufnum + 1, \lastBufnum, c[\clarity].last.bufnum - 1, \delta, (3*v[\partDur]/7)*Prand([1, 2, 5], inf), \pan, 0, \amp, 0.1/([4, 3, 2, 1, 2, 3, 4, 5]**2), \rq, 1, ); p[\clarity] = p[\clarity] <> (group: g[\c18], out: b[\c18]); v[\debug].if {p[\clarity] = p[\clarity].trace(\firstBufnum, prefix: "Clarity: ")}; //////////////////////////////////////////////////////////// // Consonants c[\consonants] = (); i[\consonants] = (); f[\consonantsReset] = { // Clean old buffers c[\consonants].do {|bufs| bufs.do {|buf| f[\toGarbage].(buf); }; }; // Select new buffers [\aggg, \ffff, \kkkk, \shhh, \ssss, \tttt].do { |item| c[\consonants][item] = f[\rndBufs].(v[\soundFiles][item], 3); }; // Return nothing nil }; f[\consonantsReset].(); p[\consonantsTypes] = (); p[\consonantsTypes][\repeatPan] = Pfin({7 + 11.rand}, Pbind( \instrument, \bufRdPan, \bufnum, Pfunc {c[\consonants][\aggg].choose}, \delta, Pfunc {0.4.rand}, \amp, Pfunc {0.3 + 0.3.rand}, \pan, Pfunc {1.0.rand2} )); v[\insectPan] = Pbrown(-1.0, 1.0).asStream; p[\consonantsTypes][\insect] = Pfxb(Pfin({19 + 17.rand}, Pbind( \instrument, \bufRdPan, \bufnum, Pfunc {(c[\consonants][\ffff] ++ c[\consonants][\ssss]).choose}, \delta, Pfunc {0.15.rand}, \amp, 0.25, \pan, Pfunc {v[\insectPan].next}, )), \hpfFx, \freq, 1500, \amp, 1.0); p[\consonantsTypes][\pour] = Pfxb(Pfin({(25 + 10.rand)}, Pbind( \instrument, \bufRdPan, \bufnum, Pfunc {(c[\consonants][\kkkk] ++ c[\consonants][\tttt]).choose}, \delta, Pgeom(0.035, 1.07), \pan, Pstutter(inf, Pwhite(-0.5, 0.5, 1)) + Pwhite(-0.05, 0.05), \amp, 0.5, \rate, Pgeom(1.05, 0.997), )), \hpfFx, \freq, 1500, \amp, 1.0); p[\consonantsTypes][\shhh] = Pfxb(Pbind( \instrument, \bufRdPan, \bufnum, Pfuncn({c[\consonants][\shhh].choose}, 5), \delta, Pwhite(1.3, 1.7), \amp, Prand([0, 0.3, 0.4], 5), \pan, Prand([Pseries(-0.5, 0.19, 5), Pseries(0.5, -0.19, 5)]), \fade, 0.01, ), \bpfFx, \freq, 2100, \amp, 1.0); p[\consonants] = Plazy { Pseq([ Plazy {Event.silent(rrand(10.0, 20.0))}, p[\consonantsTypes].choose, ]); }; p[\consonants] = p[\consonants] <> (group: g[\c22], out: b[\c22]); v[\debug].if {p[\consonants] = f[\bufDebug].(p[\consonants])}; //////////////////////////////////////////////////////////// // Waves and breath layer //// Waves init c[\waves] = (); f[\wavesReset] = { // Clean old buffers c[\waves].do {|bufs| bufs.do {|buf| f[\toGarbage].(buf); }; }; // Select new buffers [\wave, \inhale, \exhale].do { |item| c[\waves][item] = f[\rndBufs].(v[\soundFiles][item], 3); }; // Return nothing nil }; f[\wavesReset].(); i[\waves] = (); i[\waves][\guts] = Synth(\gutsFx, [\out, b[\c23], \freq, 140, \rq, 0.30, \amp, 2.0, \wet, 0.98, ], g[\c23], \addToTail); //// Wave patterns p[\waves] = Pbind( \instrument, \bufRdPan, \bufnum, Pfuncn {c[\waves][\wave].choose}, \pan, Pwhite(-0.5, 0.5), \delta, Pwhite(4.0, 6.0), \amp, Pwhite(0.2, 0.3), \rate, Pwhite(0.8, 1.2), ); p[\waves] = Pseq([Pn(p[\waves], 5), Plazy {Event.silent(rrand(10.0, 30.0))}]); p[\waves] = p[\waves] <> (group: g[\c23], out: b[\c23]); v[\debug].if {p[\waves] = f[\bufDebug].(p[\waves])}; //// Breath pattern i[\breath] = (); i[\breath][\softclip] = Synth(\softclipFx, [\out, b[\c24], \preAmp, 90], g[\c24]); i[\breath][\highShelf] = Synth(\highShelfFx, [\out, b[\c24], \freq, 2400, \rs, 1.0, \db, -4.0], g[\c24], \addToTail); i[\breath][\chPhaseInvert] = Synth(\chPhaseInvertFx, [\out, b[\c24]], g[\c24], \addToTail); v[\breathInhaleTime] = Pbrown(2.0, 6.0).asStream; v[\breathExhaleTime] = Pbrown(5.0, 7.0).asStream; p[\breathInhale] = Pbind( \instrument, \bufRdPan, \bufnum, Pfuncn {c[\waves][\inhale].choose}, \amp, 0.7, \delta, Pwrand([Pfuncn {v[\breathInhaleTime].next}, Pwhite(2.0, 5.0, 1)], [10, 1].normalizeSum), \rate, Pwhite(0.8, 1.2), ); p[\breathExhale] = Pbind( \instrument, \bufRdPan, \bufnum, Pfuncn {c[\waves][\exhale].choose}, \amp, 0.7, \delta, Pfuncn {v[\breathExhaleTime].next}, \rate, Pwhite(0.8, 1.2), ); p[\breaths] = Pseq([p[\breathInhale], p[\breathExhale]], 6); p[\breaths] = p[\breaths] <> (group: g[\c24], out: b[\c24]); v[\debug].if {p[\breaths] = f[\bufDebug].(p[\breaths])}; //////////////////////////////////////////////////////////// // Mixing //// Fx ////// c00: Bad radio m[\c00].set( 'mix10', 1.0, 'mix11', 1.0, 'mix12', 1.0, 'mix13', 1.0, 'mix14', 1.0, 'mix15', 1.0, 'mix16', 1.0, 'mix17', 1.0, ); ////// c01: Reverb 1 m[\c01].set( 'mix10', 0.10, 'mix11', 0.06, 'mix12', 0.12, 'mix13', 0.06, 'mix14', 0.06, 'mix15', 0.06, 'mix16', 0.06, 'mix17', 0.06, 'mix18', 0.06, 'mix22', 0.10, 'mix23', 0.15, 'mix24', 0.15, ); ////// c02: Reverb 2 m[\c02].set( 'mix10', 0.10, 'mix11', 0.06, 'mix12', 0.12, 'mix13', 0.06, 'mix14', 0.06, 'mix15', 0.06, 'mix16', 0.06, 'mix17', 0.06, 'mix18', 0.06, 'mix22', 0.10, 'mix23', 0.15, 'mix24', 0.15, ); ////// c03: Wash reverb m[\c03].set( 'mix18', 0.68 ); //// Channels ////// c10: Story m[\c10].set('width', 0.4); m[\c10].vol = 0.86; ////// c11: Ands m[\c11].vol = 0.53; ////// c12: Colours Whispered spirals m[\c12].vol = 0.65; ////// c13: Colours BWR m[\c13].vol = 0.86; ////// c14: Colours Shadows m[\c14].vol = 0.75; ////// c15: Intimacy m[\c15].vol = 0.79; ////// c16: Incredible m[\c16].vol = 0.47; ////// c17: Remember m[\c17].vol = 0.58; ////// c18: Clarity m[\c18].vol = 0.025; m[\c18].set('pan', -0.13); ////// c22: Consonants m[\c22].vol = 0.14; ////// c23: Waves m[\c23].vol = 0.24; ////// c24: Breath m[\c24].vol = 0.09; m[\c24].set('pan', -0.11); s.sync; //////////////////////////////////////////////////////////// // Flavours //// Different reverbs v[\reverbChange] = 61; ///// Reverb change p[\switchReverb] = Pbind( \amp, Rest(), \ir, Pseq([\UEMT, \Tower, \Tight, \Arundel, \Underwater, \Demon].rotate(6.rand), inf), \target, Pseq([\c01, \c02], inf), \delta, Pseq([Pfuncn {v[\reverbChange]/2}, Pfunc {v[\reverbChange]}]), \callback, { // postln("Reverb " ++ ~ir ++ " to " ++ ~target); i[~target].free; i[~target] = f[\convSetup].(~ir, ~target, 0.0); i[~target].map(\amp, b[(~target ++ \Amp).asSymbol]); }, ); ////// Reverb 1 p[\c01] = Pbind( \instrument, \simpleEnv, \out, b[\c01Amp], \startVal, Pseq([1, 0], inf), \endVal, Pseq([0, 1], inf), \delta, Pfunc {v[\reverbChange]}, ); ////// Reverb 2 p[\c02] = Pbind( \instrument, \simpleEnv, \out, b[\c02Amp], \startVal, Pseq([0, 1], inf), \endVal, Pseq([1, 0], inf), \delta, Pfunc {v[\reverbChange]}, ); ////// Pattern Ptpar([ 0.0, p[\switchReverb], v[\reverbChange], p[\c01], v[\reverbChange], p[\c02], ]).play; //// Theta wave distortion { var env, trig; trig = Impulse.kr(LFNoise0.kr(0.1).range(1/73, 1/67), 1.0.rand); env = Env([0, 1, 1, 0], [3, 0.01, 5], \sine, releaseNode: 2).kr(gate: Trig.kr(trig, dur: LFNoise0.kr(0.1).range(3, 10))); Out.kr(b[\masterThetaFreq], LFNoise1.kr(1).range(3, 7)); Out.kr(b[\masterThetaPreAmp], 0.5 + (1.6*env)); }.play; //////////////////////////////////////////////////////////// // Orchestration v[\debug].if {"Starting".postln}; // Consonants Pseq([p[\consonants], Pfuncn {f[\consonantsReset].(); 1}], inf).play; // Waves Pseq([p[\waves], Pfuncn {f[\wavesReset].(); 1}], inf).play; // Breath Pseq([p[\breaths], Pfuncn {f[\breathsReset].(); 1}], inf).play; // Clarity p[\clarity].play; // Sequence v[\resetPart] = nil; p[\sequence] = Pbind( \amp, Rest(), \delta, v[\partDur], \part, Prout({ var parts = [[\story], [\ands, \incredible, \remember, \colours, \intimacy].rotate(5.rand)]; loop { parts[0][0].yield; parts[0] = parts[0].rotate; parts = parts.rotate; v[\silenceProb].coin.if { \silence.yield} } }), \callback, { v[\debug].if {~part.postln}; (v[\resetPart].notNil).if { f[\resetPart].(v[\resetPart], v[\partDur]/2); }; v[\resetPart] = ~part; v[\debug].if {("Tempo: " ++ t.tempo).postln}; Pfindur({v[\partDur]}, Pseq([Event.silent(2), p[~part]])).play; } ); p[\sequence].play(quant: #[0, 0, 0.5]); });