{
   "is_private" : null,
   "id" : "1-58B",
   "code" : "(\r\n//sample creation using the PadSynth algorith described at http://wiki.linuxmusicians.com/doku.php?id=zynaddsubfx_manual#padsynth_algorithm\r\n//based on code from Donald Craig http://new-supercollider-mailing-lists-forums-use-these.2681727.n2.nabble.com/Epic-Pads-td7487382.html#a7492701\r\ns.waitForBoot({\r\n\tvar table, re, im, tab, fftsize, result, pars, freqs, amps, bandwidth, partials, note;\r\n\tvar samplerate = s.sampleRate;\r\n\tvar sgroup;\r\n\tvar fxgroup1,fxgroup2;\r\n\tvar reverbbus,chorusbus;\r\n\tvar reverb, chorus;\r\n\tvar prepareSingleBuffer, prepareAllBuffers;\r\n\tvar spectrum, xvals;\r\n\r\n\ts.freeAll;\r\n\ts.freeAllBuffers;\r\n\ts.sync;\r\n\r\n\tsgroup = Group.new;\r\n\tfxgroup1 = Group.after(sgroup);\r\n\tfxgroup2 = Group.after(fxgroup1);\r\n\treverbbus = Bus.audio(s, 1);\r\n\tchorusbus = Bus.audio(s, 1);\r\n\r\n\t~buffers = [];\r\n\r\n\tSynthDef(\\padfilterenv, {\r\n\t\t| out=0, referencefreq=130, amp=0.5, freq=440, buffer=1, gate=1, attack=0.1, decay=0.2, sustain=0.6, release=2, filtercutoff=10000, filterresonance=1.0, filterattack=0.01, filterdecay=0.2, filtersustain=0.8, filterrelease=2, filtergain=1.0, glissando=0 |\r\n\t\tvar env = EnvGen.ar(Env.adsr(attack, decay, sustain, release), gate, doneAction:Done.freeSelf);\r\n\t\tvar env2 = EnvGen.ar(Env.adsr(filterattack, filterdecay, filtersustain, filterrelease), gate, doneAction:Done.none);\r\n\t\tvar frequency = VarLag.ar(freq, glissando, warp:\\exponential);\r\n\t\tvar sig = env*PlayBuf.ar(1, buffer, rate:((frequency.cpsmidi)-(referencefreq.cpsmidi)).midiratio, loop:1);\r\n\t\tsig = RLPF.ar(sig, env2*filtercutoff, rq:filterresonance, mul:filtergain);\r\n\t\tOut.ar(out, amp*sig);\r\n\t}, rates:[nil, nil, nil, \\ar, nil, nil, nil, nil, nil, nil, nil]).add;\r\n\r\n\tSynthDef(\\reverb, {\r\n\t\t| out=0, inbus, mix=0.5, room=1.0 |\r\n\t\tvar insig = FreeVerb.ar(In.ar(inbus, 1),mix,room);\r\n\t\tOut.ar(out, insig!2);\r\n\t}).add;\r\n\r\n\tSynthDef(\\chorus, {\r\n\t\t| outbus=0, inbus, predelay=0.08, speed=0.05, depth=0.1, ph_diff=0.5 |\r\n\t\tvar in, sig, modulators, numDelays = 12;\r\n\t\tin = In.ar(inbus, 1) * numDelays.reciprocal;\r\n\t\tmodulators = Array.fill(numDelays, { |i|\r\n\t\t\tLFPar.kr(speed * rrand(0.94, 1.06), ph_diff * i, depth, predelay);\r\n\t\t});\r\n\t\tsig = DelayC.ar(in, 0.5, modulators);\r\n\t\tsig = sig.sum; //Mix(sig);\r\n\t\tOut.ar(outbus, sig!2); // output in stereo\r\n\t}).add;\r\n\r\n\ts.sync;\r\n\r\n\t// calculate single wavetable\r\n\tprepareSingleBuffer = {\r\n\t\t| partials /* flat list of [partial idx, partial amplitude, partial idx, partial amplitude, ...]. Partials often are integers (or close to) */,\r\n\t\t  min_length, /* min length of generated wave table in seconds */\r\n\t\t  spread /* band width used to generate new partials around the existing partials */,\r\n\t\t  reference_note /* note for which this spectrum is being generated */|\r\n\r\n\t\tvar fftsize = (min_length*s.sampleRate).nextPowerOfTwo;\r\n\t\tvar pars = (partials.size/2);\r\n\t\tvar bandwidth = (1+spread);\r\n\t\tvar note = reference_note;\r\n\t\tvar\ttable = Signal.newClear(fftsize);\r\n\t\tvar tab = Signal.fftCosTable(fftsize);\r\n\t\tvar re = Signal.newClear(fftsize);\r\n\t\tvar im = Signal.newClear(fftsize);\r\n\t\tvar freqs = Array.newClear(pars);\r\n\t\tvar amps = Array.newClear(pars);\r\n\t\tvar buffer;\r\n\t\tvar deinterlaced;\r\n\t\tfftsize.do({ |i|\r\n\t\t\tre[i] = 0.0;\r\n\t\t\tim[i] = 0.0;\r\n\t\t\ttable[i] = 0.0;\r\n\t\t});\r\n\r\n\t\t// partials are specified in a flat list containing\r\n\t\t// each time partial number followed by corresponding partial volume.\r\n\t\t// first deinterlace this flat list into a list of frequencies and a list of amplitudes\r\n\t\tdeinterlaced = partials.unlace;\r\n\t\tfreqs = deinterlaced[0]*(note.midicps);\r\n\t\tamps = deinterlaced[1];\r\n\r\n\t\t// next we're going to generate extra (smeared) partials. This helps in adding life and warmth to the sounds.\r\n\t\t// if you specify spread == 0, no extra partials will be added\r\n\t\tpars.do({ |i|\r\n\t\t\tvar freq, lo, hi,amp;\r\n\t\t\tfreq = freqs[i];\r\n\t\t\tamp = amps[i];\r\n\t\t\tlo = ((freq/bandwidth)*(fftsize/samplerate)).round; // partial at frequency freq will be smeared over frequencies lo to hi\r\n\t\t\thi = ((freq*bandwidth)*(fftsize/samplerate)).round;\r\n\t\t\t// generate extra partials between frequencies lo = freq/(1+spread) and hi = freq*(1+spread)\r\n\t\t\t(hi-lo+1).do({ |j|\r\n\t\t\t\tvar mag, phase, val;\r\n\t\t\t\tvar index = j.linlin(0, hi-lo, lo, hi);\r\n\t\t\t\t// only fill up lower half of spectrum:\r\n\t\t\t\t// right half later is derived from this left half to ensure a real-valued inverse fourier transform\r\n\t\t\t\tif(index < (fftsize/2), {\r\n\t\t\t\t\tif ((hi == lo), {\r\n\t\t\t\t\t\tmag = amp;\r\n\t\t\t\t\t\ttable[index] = table[index] + mag; // add it to the result table\r\n\t\t\t\t\t}, /* else */ {\r\n\t\t\t\t\t\tval = j.linlin(0, hi-lo, -1, 1);\r\n\t\t\t\t\t\tmag = exp(val*val*10.0.neg) * amp; // generates a bell-shaped curve for val in [-1,1] with y-values between [-amp, amp]\r\n\t\t\t\t\t\ttable[index] = table[index] + mag; // add it to the result table to create a \"smeared\" partial\r\n\t\t\t\t\t});\r\n\t\t\t\t\tphase = rrand(-pi, pi); // set random phase\r\n\t\t\t\t\tre[index] = re[index] + (cos(phase)*mag);\r\n\t\t\t\t\tim[index] = im[index] + (sin(phase)*mag);\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\t// at this point, table contains the sum of all the specified + extra generated partials\r\n\r\n\t\t// calculate right half of spectrum to get a real-valued inverse FFT\r\n\t\t// right half must be the mirrored complex conjugate (i.e. make imaginary part negative) of the left half\r\n\t\t(fftsize/2-1).do({\r\n\t\t\t| i |\r\n\t\t\tre[i+(fftsize/2)] = re[(fftsize/2)-i];\r\n\t\t\tim[i+(fftsize/2)] = im[(fftsize/2)-i].neg;\r\n\t\t});\r\n\r\n\t\t// inverse fourier transformation: resulting imaginary part should be (very close to) all zeros\r\n\t\tre = ifft(re, im, tab);\r\n\r\n\t\t// re.real.normalize scales the result so it falls between 0 and 1.\r\n\t\t// Next, make sure to normalize the maximum volume to -3dB.\r\n\t\tresult = re.real.normalize * ((-3).dbamp);\r\n\r\n\t\t// load the result in a buffer\r\n\t\tbuffer = Buffer.loadCollection(s, result);\r\n\r\n\t\t// and return the buffer as result of the function\r\n\t\tbuffer;\r\n\t};\r\n\r\n\t// calculate 2 wavetables per octave\r\n\tprepareAllBuffers = {\r\n\t\t| partials = #[ 1.01, 0.1722,  2.00, 0.0056,  2.99, 0.1609,  3.99, 0.0333,  5.00, 0.1157,\r\n\t\t\t5.99, 0.1149,  6.98, 0.0079, 7.98, 0.0620,  8.99, 0.0601,  9.99, 0.0104,\r\n\t\t\t10.98, 0.0134, 11.97, 0.0122, 12.99, 0.0058, 13.98, 0.0110, 14.98, 0.0029,\r\n\t\t\t15.97, 0.0045, 16.98, 0.0023, 17.98, 0.0010, 18.97, 0.0016, 19.96, 0.0021,\r\n\t\t\t20.96, 0.0008, 21.97, 0.0021, 22.96, 0.0001, 23.96, 0.0012, 24.95, 0.0003,\r\n\t\t\t25.97, 0.0002, 26.96, 0.0003, 27.95, 0.0002, 30.96, 0.0002, 32.94, 0.0002,\r\n\t\t\t34.96, 0.0001, 35.95, 0.0002, 37.93, 0.0001 ],\r\n\t\t  min_length=5,\r\n\t\t  spread = 0.1 |\r\n\t\tvar buffers = [];\r\n\t\tvar maxOctaves = 8;\r\n\t\t// prepare two wavetables per octave\r\n\t\t(0,1..8).do({\r\n\t\t\t| octave |\r\n\t\t\tvar reference_note_1 = (octave*12);\r\n\t\t\tvar reference_note_2 = (octave*12) + 6;\r\n\t\t\tbuffers = buffers.add(prepareSingleBuffer.value(partials, min_length, spread, reference_note_1));\r\n\t\t\tbuffers = buffers.add(prepareSingleBuffer.value(partials, min_length, spread, reference_note_2));\r\n\t\t});\r\n\r\n\t\tbuffers;\r\n\t};\r\n\r\n\t// calculate a desired spectrum (note: envelopes and filters/resonators/fx are just as important in determining overall experience)\r\n\txvals = (1,2..33).as(Array);\r\n\tspectrum = Signal.newClear(33).waveFill({\r\n\t\t| x, old, idx |\r\n\t\tvar lookup;\r\n\t\tlookup = [ 14.2, 8.8, 7.3, 8, 5.7, 7, 6.8, 5.8, 8.7, 6.9, 3.2, 2.1, 4, 3, 1.8, 1.1, 2.5, 1.5]; // cello-esque if attack 0.3, no filter env, small reverb\r\n\t\tif ((idx < lookup.size), {lookup[idx]}, {0});\r\n\r\n\t}, start:1, end:0).as(Array);\r\n\tspectrum = [xvals, spectrum].lace;\r\n\r\n\t// prepare the wavetables using inverse FFT\r\n\t~buffers = prepareAllBuffers.value(spectrum,\r\n\t\t5 /* minimum length of buffer in seconds */,\r\n\t\t0.03 /* spread of partials during detuning */);\r\n\r\n\ts.sync;\r\n\r\n\t// start the fx synths\r\n\treverb = Synth(\\reverb, [\r\n\t\t\\out, 0,\r\n\t\t\\inbus, reverbbus,\r\n\t\t\\mix, 0.1,\r\n\t\t\\room, 0.5,\r\n\t],\r\n\ttarget:fxgroup2);\r\n\r\n\tchorus = Synth(\\chorus, [\r\n\t\t\\out, reverbbus,\r\n\t\t\\inbus, chorusbus\r\n\t],\r\n\ttarget:fxgroup1);\r\n\r\n\t// create a composition\r\n\t// Pbind a new synth for each note.\r\n\tp = Pbind(\r\n\t\t\\instrument, \\padfilterenv,\r\n\t\t\\out, reverbbus,\r\n\t\t\\mynote, Pseq([Pseq((40,41..72), 1), Prand((48,49..72), 100)], inf),\r\n\t\t\\myreference, (Pkey(\\mynote)-(Pkey(\\mynote)%6)),\r\n\t\t\\referencefreq, Pkey(\\myreference).midicps,\r\n\t\t\\freq, Pkey(\\mynote).midicps,\r\n\t\t\\dur, Pseq([Pseq([0.5], 72-24), Prand((0.1,0.2..1.0), 100)], inf),\r\n\t\t\\amp, 0.7,\r\n\t\t\\buffer, Pfunc({ |ev| ~buffers[(ev[\\myreference]/6).round(1)].bufnum; }),\r\n\t\t\\attack, 0.3,\r\n\t\t\\decay, 0.1,\r\n\t\t\\sustain, 0.9,\r\n\t\t\\release, 1.0,\r\n\t\t\\filtergain, 0.3,\r\n\t\t\\filtercutoff, 1000,\r\n\t\t\\filterattack, 0.01,\r\n\t\t\\filterdecay, 0.1,\r\n\t\t\\filtersustain, 1.0,\r\n\t\t\\filterrelease, 0.3,\r\n\t\t\\filterresonance, 1.0,\r\n\t\t\\glissando, 0,\r\n\t\t\\vibratofreq, 3.0,\r\n\t\t\\vibratodepth, 0.015,\r\n\t\t\\group, sgroup);\r\n\r\n\t// Pmono creates only one synth, and updates its parameters. This allows e.g. for glissando's.\r\n\tq = Pmono(\r\n\t\t\\padfilterenv,\r\n\t\t\\out, reverbbus,\r\n\t\t\\mynote, Pseq([40, 52], inf),\r\n\t\t\\myreference, (Pkey(\\mynote)-(Pkey(\\mynote)%6)),\r\n\t\t\\referencefreq, Pkey(\\myreference).midicps,\r\n\t\t\\freq, Pkey(\\mynote).midicps,\r\n\t\t\\dur, Pseq([2], inf),\r\n\t\t\\amp, 0.7,\r\n\t\t\\buffer, Pfunc({ |ev| ~buffers[(ev[\\myreference]/6).round(1)].bufnum; }),\r\n\t\t\\attack, 0.3,\r\n\t\t\\decay, 0.1,\r\n\t\t\\sustain, 0.9,\r\n\t\t\\release, 1.0,\r\n\t\t\\filtergain, 0.3,\r\n\t\t\\filtercutoff, 1000,\r\n\t\t\\filterattack, 0.01,\r\n\t\t\\filterdecay, 0.1,\r\n\t\t\\filtersustain, 1.0,\r\n\t\t\\filterrelease, 0.3,\r\n\t\t\\filterresonance, 1.0,\r\n\t\t\\glissando, 0.5,\r\n\t\t\\vibratofreq, 3.0,\r\n\t\t\\vibratodepth, 0.015,\r\n\t\t\\group, sgroup);\r\n\r\n\tc = Ppar([p,q], inf);\r\n\tc.play;\r\n\r\n});\r\n)",
   "labels" : [
      "pattern",
      "pad",
      "padsynth"
   ],
   "ancestor_list" : [],
   "description" : "An implementation of Paul Nasca Octavian's excellent PadSynth algorithm in supercollider, driven from patterns. This code is accompanied by a blog article http://technogems.blogspot.be/2018/01/baking-sound-in-supercollider.html",
   "name" : "supercollider implementation of padsynth algorithm.",
   "author" : "56228375"
}
