{
   "labels" : [],
   "code" : "(\r\n//original changed to FM\r\n\r\n// CloudGenMini is based on CloudGenerator, a granular synthesis program\r\n// by Curtis Roads and John Alexander.\r\n// This partial miniature version was implemented by Alberto de Campo, 2007.\r\n\r\n\r\n\r\n\r\n\t// figure 8.23 - some granular synthdefs and tests\r\n(\r\n\t// a gabor (approx. gaussian-shaped) grain\r\nSynthDef(\\sinGab, { |out, amp=0.1, freq=440, sustain=0.01, pan|\r\n\tvar snd = FSinOsc.ar(freq);\r\n\tvar env = EnvGen.ar(Env.sine(sustain, amp * AmpComp.ir(freq) * 0.5), doneAction: 2);\r\n\tOffsetOut.ar(out, Pan2.ar(snd * env, pan));\r\n}, \\ir ! 5).add;\r\n\r\n\t\t\t// wider, quasi-gaussian envelope, with a hold time in the middle.\r\nSynthDef(\\sinWide, { |out, amp=0.1, freq=440, sustain=0.01, pan, width=0.5|\r\n\tvar holdT = sustain * width;\r\n\tvar fadeT = 1 - width * sustain * 0.5;\r\n\tvar snd = FSinOsc.ar(freq);\r\n\tvar env = EnvGen.ar(Env([0, 1, 1, 0], [fadeT, holdT, fadeT], \\sin),\r\n\t\tlevelScale: amp * AmpComp.ir(freq) * 0.5,\r\n\t\tdoneAction: 2);\r\n\tOffsetOut.ar(out, Pan2.ar(snd * env, pan));\r\n}, \\ir ! 5).add;\r\n\r\n\t\t\t// a simple percussive envelope\r\nSynthDef(\\sinPerc, { |out, amp=0.1, freq=440, sustain=0.01, pan|\r\n\tvar snd = FSinOsc.ar(freq);\r\n\tvar env = EnvGen.ar(\r\n\t\tEnv.perc(0.1, 0.9, amp * AmpComp.ir(freq) * 0.5),\r\n\t\t\ttimeScale: sustain, doneAction: 2\r\n\t\t);\r\n\tOffsetOut.ar(out, Pan2.ar(snd * env, pan));\r\n}, \\ir ! 5).add;\r\n\r\n\t\t\t// a reversed  percussive envelope\r\nSynthDef(\\sinPercRev, { |out, amp=0.1, freq=440, sustain=0.01, pan|\r\n\tvar snd = FSinOsc.ar(freq);\r\n\tvar env = EnvGen.ar(\r\n\t\tEnv.perc(0.9, 0.1, amp * AmpComp.ir(freq) * 0.5, 4),\r\n\t\t\ttimeScale: sustain, doneAction: 2\r\n\t\t);\r\n\tOffsetOut.ar(out, Pan2.ar(snd * env, pan));\r\n}, \\ir ! 5).add;\r\n\r\nSynthDef(\\noiseGab, { |out, amp=0.2, freq=440, sustain=0.01, pan, rq=0.1|\r\n\tvar snd = BPF.ar(GrayNoise.ar, freq, rq, 3);\r\n\tvar env = EnvGen.ar(Env.sine(sustain, amp * 0.5), doneAction: 2);\r\n\tOffsetOut.ar(out,\r\n\t\tPan2.ar(snd * env, pan, amp)\r\n\t);\r\n}, \\ir ! 6).add;\r\n\r\nSynthDef(\\noiseWide, { |out, amp=0.2, freq=440, sustain=0.01, pan, rq=0.1, width=0.5|\r\n\tvar holdT = sustain * width;\r\n\tvar fadeT = 1 - width * sustain * 0.5;\r\n\tvar snd = BPF.ar(GrayNoise.ar, freq, rq, 3);\r\n\tvar env = EnvGen.ar(Env([0, 1, 1, 0], [fadeT, holdT, fadeT], \\sin),\r\n\t\tlevelScale: amp * 0.5, doneAction: 2);\r\n\tOffsetOut.ar(out,\r\n\t\tPan2.ar(snd * env, pan, amp)\r\n\t);\r\n}, \\ir ! 6).add;\r\n\r\n\t\t// a noise band grain with percussive envelope\r\nSynthDef(\\noisePerc, { |out, amp=0.2, freq=440, sustain=0.01, pan, rq=0.1|\r\n\tvar snd = BPF.ar(GrayNoise.ar, freq, rq, 3);\r\n\tvar env = EnvGen.ar(Env.perc(0.1, 0.9, amp * 0.5), timeScale: sustain, doneAction: 2);\r\n\tOffsetOut.ar(out,\r\n\t\tPan2.ar(snd * env, pan, amp)\r\n\t);\r\n}, \\ir ! 6).add;\r\n\r\nSynthDef(\\noisePrev, { |out, amp=0.2, freq=440, sustain=0.01, pan, rq=0.1|\r\n\tvar snd = BPF.ar(GrayNoise.ar, freq, rq, 3);\r\n\tvar env = EnvGen.ar(\r\n\t    Env.perc(0.9, 0.1, amp * 0.5, 4),\r\n\t\t\ttimeScale: sustain, doneAction: 2\r\n\t\t);\r\n\tOffsetOut.ar(out,\r\n\t\tPan2.ar(snd * env, pan, amp)\r\n\t);\r\n}, \\ir ! 6).add;\r\n\r\n\r\n\r\nSynthDef(\\sqGab, { |out, amp=0.1, freq=440, sustain=0.01, pan|\r\n\tvar snd = Pulse.ar(freq, 0.5);\r\n\tvar env = EnvGen.ar(Env.sine(sustain, amp * 0.5), doneAction: 2);\r\n\tOffsetOut.ar(out, Pan2.ar(snd * env, pan));\r\n}, \\ir ! 5).add;\r\n\r\n\t\t\t// wider, quasi-gaussian envelope, with a hold time in the middle.\r\nSynthDef(\\sqWide, { |out, amp=0.1, freq=440, sustain=0.01, pan, width=0.5|\r\n\tvar holdT = sustain * width;\r\n\tvar fadeT = 1 - width * sustain * 0.5;\r\n\tvar snd = Pulse.ar(freq, 0.5);\r\n\tvar env = EnvGen.ar(Env([0, 1, 1, 0], [fadeT, holdT, fadeT], \\sin),\r\n\t\tlevelScale: amp * 0.5,\r\n\t\tdoneAction: 2);\r\n\tOffsetOut.ar(out, Pan2.ar(snd * env, pan));\r\n}, \\ir ! 5).add;\r\n\r\n\t\t\t// a simple percussive envelope\r\nSynthDef(\\sqPerc, { |out, amp=0.1, freq=440, sustain=0.01, pan|\r\n\tvar snd = Pulse.ar(freq, 0.5);\r\n\tvar env = EnvGen.ar(\r\n\t\tEnv.perc(0.1, 0.9, amp * 0.5),\r\n\t\t\ttimeScale: sustain, doneAction: 2\r\n\t\t);\r\n\tOffsetOut.ar(out, Pan2.ar(snd * env, pan));\r\n}, \\ir ! 5).add;\r\n\r\n\t\t\t// a reversed  percussive envelope\r\nSynthDef(\\sqPercRev, { |out, amp=0.1, freq=440, sustain=0.01, pan|\r\n\tvar snd = Pulse.ar(freq, 0.5);\r\n\tvar env = EnvGen.ar(\r\n\t\tEnv.perc(0.9, 0.1, amp * 0.5, 4),\r\n\t\t\ttimeScale: sustain, doneAction: 2\r\n\t\t);\r\n\tOffsetOut.ar(out, Pan2.ar(snd * env, pan));\r\n}, \\ir ! 5).add;\r\n\r\nSynthDef(\\triGab, { |out, amp=0.1, freq=440, sustain=0.01, pan|\r\n\tvar snd = DPW3Tri.ar(freq);\r\n\tvar env = EnvGen.ar(Env.sine(sustain, amp * 0.5), doneAction: 2);\r\n\tOffsetOut.ar(out, Pan2.ar(snd * env, pan));\r\n}, \\ir ! 5).add;\r\n\r\n\t\t\t// wider, quasi-gaussian envelope, with a hold time in the middle.\r\nSynthDef(\\triWide, { |out, amp=0.1, freq=440, sustain=0.01, pan, width=0.5|\r\n\tvar holdT = sustain * width;\r\n\tvar fadeT = 1 - width * sustain * 0.5;\r\n\tvar snd = DPW3Tri.ar(freq);\r\n\tvar env = EnvGen.ar(Env([0, 1, 1, 0], [fadeT, holdT, fadeT], \\sin),\r\n\t\tlevelScale: amp * 0.5,\r\n\t\tdoneAction: 2);\r\n\tOffsetOut.ar(out, Pan2.ar(snd * env, pan));\r\n}, \\ir ! 5).add;\r\n\r\n\t\t\t// a simple percussive envelope\r\nSynthDef(\\triPerc, { |out, amp=0.1, freq=440, sustain=0.01, pan|\r\n\tvar snd = DPW3Tri.ar(freq);\r\n\tvar env = EnvGen.ar(\r\n\t\tEnv.perc(0.1, 0.9, amp * 0.5),\r\n\t\t\ttimeScale: sustain, doneAction: 2\r\n\t\t);\r\n\tOffsetOut.ar(out, Pan2.ar(snd * env, pan));\r\n}, \\ir ! 5).add;\r\n\r\n\t\t\t// a reversed  percussive envelope\r\nSynthDef(\\triPercRev, { |out, amp=0.1, freq=440, sustain=0.01, pan|\r\n\tvar snd = DPW3Tri.ar(freq);\r\n\tvar env = EnvGen.ar(\r\n\t\tEnv.perc(0.9, 0.1, amp * 0.5, 4),\r\n\t\t\ttimeScale: sustain, doneAction: 2\r\n\t\t);\r\n\tOffsetOut.ar(out, Pan2.ar(snd * env, pan));\r\n}, \\ir ! 5).add;\r\n\r\n/*\r\n\t// tests for the synthdefs:\r\nSynth(\\gab1st);\r\nSynth(\\gabWide);\r\nSynth(\\percSin);\r\nSynth(\\percSinRev);\r\n\r\nSynth(\\percSin, [\\amp, 0.2, \\sustain, 0.1]);\r\nSynth(\\percNoise, [\\amp, 0.2, \\sustain, 0.1]);\r\n\r\nSynth(\\gab1st, [\\out, 0, \\amp, 0.2, \\freq, 2000, \\sustain, 0.05, \\pan, 0.5] );\r\n\r\nSynth(\\sawGab1st, [\\amp, 0.2, \\sustain, 0.1]);\r\nSynth(\\sawGabWide);\r\nSynth(\\sawPerc);\r\nSynth(\\sawPercRev);\r\n*/\r\n);\r\n\r\n\r\n\r\n\r\n\r\n\t// figure 8.24 - global setup and a player Tdef for the cloud.\r\n(\r\nq = q ? ();\r\n\r\n\t// some globals\r\nq.paramRNames = [\\freqRange, \\durRange, \\densRange, \\ampRange, \\panRange];\r\nq.paramNames = [\\freq, \\grDur, \\dens, \\amp, \\pan];\r\nq.syndefNames = [\\sinGab, \\sinWide, \\sinPerc, \\sinPercRev,\r\n\t             \\noiseGab, \\noiseWide, \\noisePerc, \\noisePrev,\r\n                 \\sqGab, \\sqWide, \\sqPerc, \\sqPercRev,\r\n                 \\triGab, \\triWide, \\triPerc, \\triPercRev];\r\n\r\n\t// specs for some parameters\r\nSpec.add(\\xfadeTime, [0.001, 1000, \\exp]);\r\nSpec.add(\\ring, [0.03, 30, \\exp]);\r\nSpec.add(\\grDur, [0.0001, 1, \\exp]);\r\nSpec.add(\\dens, [1, 1000, \\exp]);\r\n\r\n\t// make an empty tdef that plays it,\r\n\t// and put the cloud parameter ranges in the tdef's environment\r\nTdef(\\cloud0)\r\n\t.set(\r\n\t\\synName, \\sinGab,\r\n\t\\vol, 0.25,\r\n\t\\current, (\r\n\t\tfreqRange: [200, 2000],\r\n\t\tampRange: [0.1, 1],\r\n\t\tdurRange: [0.001, 0.01],\r\n\t\tdensRange: [1, 1000],\r\n\t\tpanRange: [-1.0, 1.0]\r\n\t)\r\n);\r\n\r\n\t\t// make the tdef that plays the cloud of sound particles here,\r\n\t\t// based on parameter range settings.\r\nTdef(\\cloud0, { |e|\r\n\r\n\tloop {\r\n\t\ts.sendBundle(s.latency, [\r\n\t\t\t\"/s_new\", e.synName ? \\sinGab,\r\n\t\t\t-1, 0, 0,\r\n\t\t\t\\freq, \texprand(e.current.freqRange[0], e.current.freqRange[1]),\r\n\t\t\t\\amp,\texprand(e.current.ampRange[0], e.current.ampRange[1]) * e.vol,\r\n\t\t\t\\sustain,\texprand(e.current.durRange[0], e.current.durRange[1]),\r\n\t\t\t\\pan, \trrand(e.current.panRange[0], e.current.panRange[1])\r\n\t\t]);\r\n\t\texprand(e.current.densRange[0].reciprocal, e.current.densRange[1].reciprocal).wait;\r\n\t}\r\n}).quant_(0);\r\n);\r\n\r\n\r\n\r\n\r\n/*\r\n\t// figure  8.25\t-  tests for the cloud\r\n\r\nTdef(\\cloud0).play;\r\n\r\n\t// try changing various things from outside the loop.\r\n\t// change its playing settings\r\n\r\nTdef(\\cloud0).envir.current.put('densRange', [ 50, 200 ]); // dense, async\r\nTdef(\\cloud0).envir.current.put('densRange', [ 1, 10 ]);  // sparse, async\r\nTdef(\\cloud0).envir.current.put('densRange', [ 30, 30 ]); // synchronous\r\n\r\n\t// for faster access, call the tdef's envir d\r\nd = Tdef(\\cloud0).envir;\r\nd.current.put('freqRange', [ 800, 1200 ]);\r\nd.current.put('durRange', [ 0.02, 0.02 ]);\r\n\r\nd.current.put('ampRange', [ 0.1, 0.1 ]);\r\n\r\nd.current.put('panRange', [ 1.0, 1.0 ]);\r\nd.current.put('panRange', [ -1.0, 1.0 ]);\r\n\r\nd.current.put('densRange', [ 30, 60 ]);\r\nd.synName = \\percSin;\r\nd.synName = \\gab1st;\r\nd.synName = \\gabWide;\r\nd.synName = \\percSinRev;\r\nd.synName = \\percNoise;\r\nd.synName = \\percSinRev;\r\nd.synName = \\gab1st;\r\nd.current.put('durRange', [ 0.001, 0.08 ]);\r\n\r\n\r\n*/\r\n\r\n\r\n\r\n\r\n\t// figure 8.26 - making random settings, and 8 random presets to switch between\r\n(\r\n\t// make the Tdef's envir a global variable for easier experimenting\r\nd = Tdef(\\cloud0).envir;\r\n\t// a pseudo-method to make random settings, kept in the Tdef's environment\r\n\t\t// randomize could also do limited variation on existing setting.\r\nd.randSet = { |d|\r\n\tvar randSet = ();\r\n\tq.paramRNames.do { |pName, i|\r\n\t\trandSet.put(pName,\r\n\t\t\tq.paramNames[i].asSpec.map([1.0.rand, 1.0.rand].sort)\r\n\t\t);\r\n\t};\r\n\trandSet;\r\n};\r\n\r\n/* \ttest randSet:\r\nd.current = d.randSet;\r\n*/\r\n\r\n// make 8 sets of parameter range settings:\r\nd.setNames = (1..8).collect { |i| (\"set\" ++ i).asSymbol };\r\nd.setNames.do { |key| d[key] = d.randSet; }\r\n\r\n/*\ttest switching to the random presets\r\nd.current = d.set1.copy;\t// copy to avoid writing into a stored setting when it is current.\r\nd.current = d.set3.copy;\r\nd.current = d.set8.copy;\r\n*/\r\n);\r\n\r\n\r\n\r\n\r\n\t// ex. 8.27 - crossfading between different settings with a taskproxy\r\n\r\n(\r\n\t// and some parameters for controlling the fade\r\nd.stopAfterFade = false;\r\nd.xfadeTime = 3;\r\n\r\nd.morphtask = TaskProxy({\r\n\tvar startSet = d[\\current], endSet = d[\\target];\r\n\tvar stepsPerSec = 20;\r\n\tvar numSteps = d.xfadeTime * stepsPerSec;\r\n\tvar blendVal, morphSettings;\r\n\r\n\tif (d.target.notNil) {\r\n\t\t(numSteps).do { |i|\r\n\t\t//\t[\"numSteps\", i].postln;\r\n\t\t\tblendVal = (i + 1) / numSteps;\r\n\t\t\tmorphSettings = endSet.collect({ |val, key|\r\n\t\t\t\t(startSet[key] ? val).blend(val, blendVal)\r\n\t\t\t});\r\n\t\t\td.current_(morphSettings);\r\n\t\t\t(1/stepsPerSec).wait;\r\n\t\t};\r\n\t\td.current_(d.target.copy);\r\n\t\t\"morph done.\".postln;\r\n\t\tif (d.stopAfterFade) { Tdef(\\cloud0).stop; };\r\n\t};\r\n}).quant_(0);\t\t// no quantization so the task starts immediately\r\n\r\n/* test morphing\r\n(\r\nTdef(\\cloud0).play;\r\nd.target = d.set6.copy;\r\nd.morphtask.play;\r\n)\r\nTdef(\\cloud0).stop;\r\n\r\n\t// playing a a finite cloud with tendency mask:\r\n(\r\nTdef(\\cloud0).play;\t\t// begin playing\r\nd.stopAfterFade = true; \t// end cloud when crossfade ends\r\nd.xfadeTime = 10; \t\t\t// set fade time\r\nd.target = d.set8.copy;\t\t// and target\r\nd.morphtask.play;\t\t\t// and start crossfade.\r\n)\r\n*/\r\n\r\n\t// put fading into its own method, with optional stop.\r\nd.fadeTo = { |d, start, end, time, autoStop|\r\n\td.current = d[start] ? d.current;\r\n\td.target = d[end];\r\n\td.xfadeTime = time ? d.xfadeTime;\r\n\tif (autoStop.notNil) { d.stopAfterFade = autoStop };\r\n\td.morphtask.stop.play;\r\n};\r\n\r\n/* \t// tests fadeTo:\r\nTdef(\\cloud0).play;\r\nd.fadeTo(\\current, \\set2, 20);\r\nd.fadeTo(\\current, \\set6, 10);\r\nd.fadeTo(\\current, \\set5, 3, true);\r\n\r\nTdef(\\cloud0).play;\r\nd.fadeTo(\\current, \\set1, 3, false);\r\n*/\r\n);\r\n\r\n\r\n\r\n\t// figure 8.28 is an image, the CloudGenMini GUI //\r\n\r\n\r\n\r\n\r\n\t// figure 8.29 - a lightweight graphical user interface for CloudGenMini\r\n(\r\nq.makeCloudGui = { |q, tdef, posPoint|\r\n\tvar w, ezRangers, fdBox;\r\n\tvar setMinis, skipjack;\r\n\r\n\tposPoint = posPoint ? 400@400;\t// where to put the gui window\r\n\r\n\tw = Window.new(\"CloudGenMiniMetro\",\r\n\t\tRect.fromPoints(posPoint, (posPoint + (400@300)))).front;\r\n\tw.view.decorator_(FlowLayout(w.bounds.copy.moveTo(0, 0)));\r\n\r\n\tw.view.decorator.nextLine;\r\n\r\n\t\t// a just in time - gui for the Tdef\r\n\tz = TdefGui(tdef, parent: w);\r\n\r\n\tfdBox = EZNumber.new(w, 78@18, \\Fade, ControlSpec(0.01, 100.0, \\exp, 0.01, 3, nil),\r\n\t\t{ |nbx| tdef.envir.xfadeTime = nbx.value },\r\n\t\t tdef.envir.xfadeTime, false, 35);\r\n\r\n\t~recordButton = Button(w, 51@19);\r\n    ~recordButton.states_([[\"rec\", Color.black, Color.white],[\"rec\", Color.white, Color.red]]);\r\n    ~recordButton.action = {|view|\r\n\t                        if (view.value==1) {s.record} {s.stopRecording}};\r\n    ~recordButton.value=0;\r\n\r\n\tw.view.decorator.nextLine;\r\n\r\n\r\n\t\t// the range sliders display the current values\r\n\tezRangers = ();\r\n\r\n\tq.paramRNames.do { |name, i|\r\n\t\tezRangers.put(name,\r\n\t\tEZRanger(w, 400@20, name, q.paramNames[i],\r\n\t\t\t{ |sl| tdef.envir.current[name] = sl.value; },\r\n\t\t\ttdef.envir.current[name], labelWidth: 70, numberWidth: 50, unitWidth: 10)\r\n\t\t\t.round_([0.1, 0.00001, 0.0001, 0.0001, 0.01][i])\r\n\t\t);\r\n\t};\r\n\r\n\r\n\r\n\r\n\tButton.new(w, 126@20).states_([[\\randomize]])\r\n\t\t.action_({\r\n\t\t\ttdef.envir.target_(d.randSet);\r\n\t\t\ttdef.envir.morphtask.stop.play;\r\n\t\t});\r\n\r\n\r\n\r\n\tButton.new(w, 126@20).states_([[\\continuous], [\\fadeStops]])\r\n\t\t.value_(tdef.envir.stopAfterFade.binaryValue)\r\n\t\t.action_({ |btn|\r\n\t\t\ttdef.set(\\stopAfterFade, btn.value == 1)\r\n\t\t});\r\n\r\n\tButton.new(w, 126@20).states_([[\\skipWatching], [\\skipWaiting]])\r\n\t\t.action_({ |btn|\r\n\t\t\t[ { skipjack.play }, { skipjack.stop }][btn.value].value\r\n\t\t});\r\n\r\n\tw.view.decorator.nextLine;\r\n\r\n\r\n\r\n\t\t\t// skipjack is a task that survives cmd-period:\r\n\t\t\t// used here for lazy-updating the control views.\r\n\tskipjack = SkipJack({\r\n\t\tq.paramRNames.do { |name| ezRangers[name].value_(tdef.envir.current[name]) };\r\n\t\tfdBox.value_(tdef.envir.xfadeTime);\r\n\r\n\t\t// mark last settings that were used by color?\r\n\t\t// a separate color when changed?\r\n\r\n\t}, 0.5, { w.isClosed }, name: tdef.key);\r\n\r\n\tw.view.decorator.nextLine;\r\n\r\n\t// make a new layoutView for the 8 presets;\r\n\t// put button to switch to that preset,\r\n\t// a button to save current settings to that place,\r\n\t// and a miniview of the settings as a visual reminder in it.\r\n\r\n\t\t// make 8 setButtons\r\n\ttdef.envir.setNames.do { |setname, i|\r\n\t\tvar minisliders, setMinis;\r\n\t\tvar zone = CompositeView.new(w, Rect(0,0,45, 84));\r\n\t\tzone.decorator = FlowLayout(zone.bounds, 0@0, 5@0);\r\n\t\tzone.background_(Color.white);\r\n\r\n\t\tButton.new(zone, Rect(0,0,45,20)).states_([[setname]])\r\n\t\t\t.action_({\r\n\t\t\t\t// just switch: // tdef.envir.current.putAll(d[setname] ? ())\r\n\t\t\t\ttdef.envir.target = tdef.envir[setname];\r\n\t\t\t\ttdef.envir.morphtask.stop.play;\r\n\t\t\t});\r\n\r\n\t\tButton.new(zone, Rect(0,0,45,20))\r\n\t\t\t.states_([[\"save\" ++ (i + 1)]])\r\n\t\t\t.action_({\r\n\t\t\t\td[setname] = tdef.envir.current.copy;\r\n\t\t\t\tsetMinis.value;\r\n\t\t\t});\r\n\r\n\t\tminisliders = q.paramRNames.collect { |paramRname|\r\n\t\t\tRangeSlider.new(zone, 45@8).enabled_(false);\r\n\t\t};\r\n\t\tsetMinis = {\r\n\t\t\tq.paramRNames.do { |paramRname, i|\r\n\t\t\t\tvar paramName = q.paramNames[i];\r\n\t\t\t\tvar myrange = d[setname][paramRname];\r\n\t\t\t\tvar unmapped = paramName.asSpec.unmap(myrange);\r\n\t\t\t\tminisliders[i].lo_(unmapped[0]).hi_(unmapped[1]);\r\n\t\t\t}\r\n\t\t};\r\n\t\tsetMinis.value;\r\n\t};\r\n\r\n/* \tSome extras:\r\n\ta volume slider for simple mixing,\r\n\ta popup menu for switching syndefnames;\r\n\ta button to stop/start the skipjack for refreshing,\r\n\tso one can use numberboxes to enter values.\r\n*/\r\n\r\n\r\n\tEZSlider(w, 225@20, \"vol\", \\amp, { |sl|tdef.set(\\vol, sl.value) },\r\n\t\t0.6, false, 20, 36);\r\n\r\n\tStaticText.new(w, 60@20).string_(\"synthdef:\").align_(\\right);\r\n\tPopUpMenu.new(w, Rect(0,0,95,20))\r\n\t\t.items_([\\sinGab, \\sinWide, \\sinPerc, \\sinPercRev,\r\n\t\t         \\noiseGab, \\noiseWide, \\noisePerc, \\noisePrev,\r\n\t             \\sqGab, \\sqWide, \\sqPerc, \\sqPercRev,\r\n\t             \\triGab, \\triWide, \\triPerc, \\triPercRev])\r\n\t\t.action_({ |pop| tdef.envir.synName = pop.items[pop.value] });\r\n\r\n\r\n};\r\nq.makeCloudGui(Tdef(\\cloud0))\r\n);\r\n\r\n)",
   "is_private" : null,
   "id" : "1-4Sl",
   "author" : "bateslewis",
   "name" : "CloudGenMiniExtraSynthDefs",
   "description" : "original example using PMOsc instead",
   "ancestor_list" : []
}
