{
   "description" : "",
   "ancestor_list" : [],
   "author" : "david_morgan",
   "name" : "UI for FM7",
   "id" : "1-5ar",
   "is_private" : null,
   "code" : "/*\r\nRequires:\r\n   sc3-Plugins\r\n   Feedback Quark for fx (comment out if not installed)\r\n   cruciallib Quark\r\n\r\n~fm7_ui function creates a ui and returns a monophonic nodeproxy. \r\n\r\nThere are three code regions to execute.\r\n#1 defines the function\r\n#2 instantiates the ui and nodeproxy and monitors the proxy\r\n#3 adds fx and a pattern\r\n\r\nOnce the ui is loaded you can explore the parameter space\r\nwith the \"Randomize\" button.\r\n\r\nAll of the inputs to the nodeproxy can futher be modulated\r\n\r\nController inputs:\r\n\r\nc0 .. c5: sets the frequency ratio of the controller\r\nc0env .. c5env: sets the amp envelope for the controller\r\nc0amp .. c5amp: sets the level scale of the envelope\r\nc0ts .. c5ts: sets the time scale of the envelope\r\n\r\nModulator inputs:\r\n\r\nm0_0 .. m5_5: sets the modulator level in radians\r\n\r\nAdditional inputs:\r\ntrig: trigger for the envelopes\r\namp: volume\r\npan: -1 to 1\r\n\r\nAmp envelope:\r\natk, decay, sus, susLevel, rel\r\n\r\nEQ inputs:\r\n\r\nlo_freq\r\nlo_db\r\nmid_freq\r\nmid_db\r\nhi_freq\r\nhi_db\r\nwet1: dry/wet level for eq\r\n\r\n*/\r\n\r\n(\r\n/////////////////////////////////////////\r\n// #1\r\n// define the function to build the ui and nodeproxy\r\n~fm7_ui = {\r\n\r\n\tvar foo = Font.setDefault(Font().size_(10));\r\n\t// not sure if all of these are implemented correctly\r\n\tvar algos = {arg num;\r\n\r\n\t\tvar algos = [\r\n\r\n\t\t\t// 0\r\n\t\t\t[0, 2] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[3, 4, 0.15],\r\n\t\t\t\t[4, 5, 0.15],\r\n\t\t\t\t[5, 5, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 1\r\n\t\t\t[0, 2] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[1, 1, 0.15],\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[3, 4, 0.15],\r\n\t\t\t\t[4, 5, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 2\r\n\t\t\t[0, 3] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[1, 2, 0.15],\r\n\t\t\t\t[3, 4, 0.15],\r\n\t\t\t\t[4, 5, 0.15],\r\n\t\t\t\t[5, 5, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 3\r\n\t\t\t[0, 3] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[1, 2, 0.15],\r\n\t\t\t\t[3, 4, 0.15],\r\n\t\t\t\t[4, 5, 0.15],\r\n\t\t\t\t[5, 3, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 4\r\n\t\t\t[0, 2, 4] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[5, 5, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 5\r\n\t\t\t[0, 2, 4] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[5, 4, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 6\r\n\t\t\t[0, 2] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[2, 4, 0.15],\r\n\t\t\t\t[4, 5, 0.15],\r\n\t\t\t\t[5, 5, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 7\r\n\t\t\t[0, 2] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[2, 4, 0.15],\r\n\t\t\t\t[4, 5, 0.15],\r\n\t\t\t\t[3, 3, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 8\r\n\t\t\t[0, 2] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[2, 4, 0.15],\r\n\t\t\t\t[4, 5, 0.15],\r\n\t\t\t\t[1, 1, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 9\r\n\t\t\t[0, 3] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[1, 2, 0.15],\r\n\t\t\t\t[3, 4, 0.15],\r\n\t\t\t\t[3, 5, 0.15],\r\n\t\t\t\t[2, 2, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 10\r\n\t\t\t[0, 3] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[1, 2, 0.15],\r\n\t\t\t\t[3, 4, 0.15],\r\n\t\t\t\t[3, 5, 0.15],\r\n\t\t\t\t[5, 5, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 11\r\n\t\t\t[0, 2] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[1, 2, 0.15],\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[2, 4, 0.15],\r\n\t\t\t\t[2, 5, 0.15],\r\n\t\t\t\t[2, 2, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 12\r\n\t\t\t[0, 2] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[1, 2, 0.15],\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[2, 4, 0.15],\r\n\t\t\t\t[2, 5, 0.15],\r\n\t\t\t\t[5, 5, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 13\r\n\t\t\t[0, 2] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[3, 4, 0.15],\r\n\t\t\t\t[3, 5, 0.15],\r\n\t\t\t\t[5, 5, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 14\r\n\t\t\t[0, 2] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[3, 4, 0.15],\r\n\t\t\t\t[3, 5, 0.15],\r\n\t\t\t\t[1, 1, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 15\r\n\t\t\t[0] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[0, 2, 0.15],\r\n\t\t\t\t[0, 4, 0.15],\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[4, 5, 0.15],\r\n\t\t\t\t[5, 5, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 16\r\n\t\t\t[0] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[0, 2, 0.15],\r\n\t\t\t\t[0, 4, 0.15],\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[4, 5, 0.15],\r\n\t\t\t\t[1, 1, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 17\r\n\t\t\t[0] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[0, 2, 0.15],\r\n\t\t\t\t[0, 3, 0.15],\r\n\t\t\t\t[3, 4, 0.15],\r\n\t\t\t\t[4, 5, 0.15],\r\n\t\t\t\t[2, 2, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 18\r\n\t\t\t[0, 3, 4] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[1, 2, 0.15],\r\n\t\t\t\t[3, 5, 0.15],\r\n\t\t\t\t[4, 5, 0.15],\r\n\t\t\t\t[5, 5, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 19\r\n\t\t\t[0, 1, 3] -> [\r\n\t\t\t\t[0, 2, 0.15],\r\n\t\t\t\t[1, 2, 0.15],\r\n\t\t\t\t[3, 4, 0.15],\r\n\t\t\t\t[3, 5, 0.15],\r\n\t\t\t\t[2, 2, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 20\r\n\t\t\t[0, 1, 3, 4] -> [\r\n\t\t\t\t[0, 2, 0.15],\r\n\t\t\t\t[1, 2, 0.15],\r\n\t\t\t\t[3, 5, 0.15],\r\n\t\t\t\t[4, 5, 0.15],\r\n\t\t\t\t[2, 2, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 21\r\n\t\t\t[0, 2, 3, 4] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[2, 5, 0.15],\r\n\t\t\t\t[3, 5, 0.15],\r\n\t\t\t\t[4, 5, 0.15],\r\n\t\t\t\t[5, 5, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 22\r\n\t\t\t[0, 1, 3, 4] -> [\r\n\t\t\t\t[1, 2, 0.15],\r\n\t\t\t\t[3, 5, 0.15],\r\n\t\t\t\t[4, 5, 0.15],\r\n\t\t\t\t[5, 5, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 23\r\n\t\t\t[0, 1, 2, 3, 4] -> [\r\n\t\t\t\t[2, 5, 0.15],\r\n\t\t\t\t[3, 5, 0.15],\r\n\t\t\t\t[4, 5, 0.15],\r\n\t\t\t\t[5, 5, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 24\r\n\t\t\t[0, 1, 2, 3, 4] -> [\r\n\t\t\t\t[3, 5, 0.15],\r\n\t\t\t\t[4, 5, 0.15],\r\n\t\t\t\t[5, 5, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 25\r\n\t\t\t[0, 1, 3] -> [\r\n\t\t\t\t[1, 2, 0.15],\r\n\t\t\t\t[3, 4, 0.15],\r\n\t\t\t\t[3, 5, 0.15],\r\n\t\t\t\t[5, 5, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 26\r\n\t\t\t[0, 1, 3] -> [\r\n\t\t\t\t[1, 2, 0.15],\r\n\t\t\t\t[3, 4, 0.15],\r\n\t\t\t\t[3, 5, 0.15],\r\n\t\t\t\t[2, 2, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 27\r\n\t\t\t[0, 2, 5] -> [\r\n\t\t\t\t[0, 1, 0.15],\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[3, 4, 0.15],\r\n\t\t\t\t[4, 4, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 28\r\n\t\t\t[0, 1, 2, 4] -> [\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[4, 5, 0.15],\r\n\t\t\t\t[5, 5, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 29\r\n\t\t\t[0, 1, 2, 5] -> [\r\n\t\t\t\t[2, 3, 0.15],\r\n\t\t\t\t[3, 4, 0.15],\r\n\t\t\t\t[4, 4, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 30\r\n\t\t\t[0, 1, 2, 3, 4] -> [\r\n\t\t\t\t[4, 5, 0.15],\r\n\t\t\t\t[5, 5, 0.15]\r\n\t\t\t],\r\n\r\n\t\t\t// 31\r\n\t\t\t[0, 1, 2, 3, 4, 5] -> [\r\n\t\t\t\t[5, 5, 0.15]\r\n\t\t\t]\r\n\t\t];\r\n\r\n\t\talgos[num];\r\n\t};\r\n\r\n\tvar algoPopup, randomizeBtn;\r\n\r\n\tvar defaultAmp = 0.5;\r\n\r\n\tvar defaultAtk = 0.001;\r\n\r\n\tvar defaultSusLevel = 0.7;\r\n\r\n\tvar defaultDecay = 0.05;\r\n\r\n\tvar defaultSus = 0.8541;\r\n\r\n\tvar defaultRel = 0.0949;\r\n\r\n\tvar controllerEnv = Env([0,1,defaultSusLevel,defaultSusLevel,0],[defaultAtk,defaultDecay,defaultSus,defaultRel],\\sin);\r\n\r\n\tvar modEnv = Env([1,1,1,1,1],[0.25,0.25,0.25,0.25],\\lin);\r\n\r\n\tvar node = NodeProxy.audio(s, 2).source_({\r\n\r\n\t\tvar trig = \\trig.tr(0);\r\n\r\n\t\tvar freq = Vibrato.ar(K2A.ar(\\freq.kr(432)),\r\n\t\t\t\\vrate.kr(6),\r\n\t\t\t\\vdepth.kr(0.0),\r\n\t\t\t\\vdelay.kr(0),\r\n\t\t\t\\vonset.kr(0),\r\n\t\t\t\\vrateVar.kr(0.04),\r\n\t\t\t\\vdepthVar.kr(0.1)\r\n\t\t);\r\n\r\n\t\tvar susLevel = \\susLevel.kr(defaultSusLevel);\r\n\t\tvar atk = \\atk.kr(defaultAtk);\r\n\t\tvar decay = \\decay.kr(defaultDecay);\r\n\t\tvar sus = \\sus.kr(defaultSus);\r\n\t\tvar rel = \\rel.kr(defaultRel);\r\n\t\tvar env = Env([0,1,susLevel,susLevel,0],[atk,decay,sus,rel],\\sin).kr(gate:trig);\r\n\r\n\t\tvar ctrls = Array.fill(6, {arg i;\r\n\t\t\tvar env = ('c' ++ i ++ 'env').asSymbol.kr(controllerEnv.asArray);\r\n\t\t\tvar amp = ('c' ++ i ++ 'amp').asSymbol.kr(1);\r\n\t\t\tvar ts = ('c' ++ i ++ 'env_ts').asSymbol.kr(1);\r\n\t\t\tvar envgen = EnvGen.kr(env, gate:trig, levelScale:amp, timeScale:ts);\r\n\t\t\t[freq * ('c' ++ i).asSymbol.kr(1) + LFNoise2.kr(0.01).range(-5,5), 0, envgen]\r\n\t\t});\r\n\r\n\t\tvar mods = Array.fill2D(6, 6, {arg r, c;\r\n\t\t\tvar key = ('m' ++ r ++ '_' ++ c);\r\n\t\t\tkey.asSymbol.kr(0);\r\n\t\t}) * 2pi; // in radians\r\n\r\n\t\tvar sig = FM7.ar(ctrls, mods) * (0..5).collect({arg i; ('chan' ++ i).asSymbol.kr(0)});\r\n\r\n\t\tsig = sig * AmpCompA.kr(freq) * env * \\amp.kr(defaultAmp);\r\n\r\n\t\tPan2.ar(Mix.ar(sig), \\pan.kr(0));\r\n\r\n\t}).filter(1, {arg in;\r\n\r\n\t\tvar sig = in;\r\n\t\tvar lo_freq = \\lo_freq.kr(100).lag(0.2);\r\n\t\tvar lo_db = \\lo_db.kr(0).lag(0.2);\r\n\t\tvar mid_freq = \\mid_freq.kr(1000).lag(0.2);\r\n\t\tvar mid_db = \\mid_db.kr(0).lag(0.2);\r\n\t\tvar hi_freq = \\hi_freq.kr(10000).lag(0.2);\r\n\t\tvar hi_db = \\hi_db.kr(0).lag(0.2);\r\n\r\n\t\tsig = BPeakEQ.ar(sig, lo_freq, 1, lo_db);\r\n\t\tsig = BPeakEQ.ar(sig, mid_freq, 1, mid_db);\r\n\t\tsig = BPeakEQ.ar(sig, hi_freq, 1, hi_db);\r\n\t\tsig;\r\n\r\n\t}).set(\\wet1, 0);\r\n\r\n\tvar setMod = {arg row, col, val;\r\n\t\tvar key = ('m' ++ row ++ '_' ++ col).asSymbol;\r\n\t\tnode.set(key, val);\r\n\t};\r\n\r\n\tvar channels = (0..5).collect({arg i;\r\n\t\tCheckBox().action_({arg ctrl;\r\n\t\t\tvar key = ('chan' ++ i).asSymbol;\r\n\t\t\tif (ctrl.value) {\r\n\t\t\t\tnode.set(key, 1);\r\n\t\t\t} {\r\n\t\t\t\tnode.set(key, 0);\r\n\t\t\t}\r\n\t\t})\r\n\t});\r\n\r\n\tvar gridBoxes = Array.fill2D(6, 6, {arg r, c;\r\n\t\tNumberBox().minHeight_(15).minWidth_(30)\r\n\t\t.action_({arg ctrl;\r\n\t\t\tsetMod.(r, c, ctrl.value);\r\n\t\t})\r\n\t\t.clipLo_(0)\r\n\t\t.clipHi_(2)\r\n\t\t.decimals_(2)\r\n\t\t.normalColor_(Color.white)\r\n\t});\r\n\r\n\tvar grid = GridLayout.rows(\r\n\r\n\t\t// grid with column headers and row headers\r\n\t\t*(0..6).collect({arg k;\r\n\t\t\tif (k == 0) {\r\n\t\t\t\t(0..6).collect({arg i;\r\n\t\t\t\t\tif (i == 0) {\r\n\t\t\t\t\t\tnil\r\n\t\t\t\t\t} {\r\n\t\t\t\t\t\tStaticText().string_(i).align_(\\center);//.stringColor_(Color.black);\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t} {\r\n\t\t\t\t(0..6).collect({arg i;\r\n\t\t\t\t\tvar color = Color.clear;\r\n\t\t\t\t\tif ((k-1) == (i-1)) {color = Color.blue.alpha_(0.2)};\r\n\t\t\t\t\tif (i == 0) {\r\n\t\t\t\t\t\tStaticText().string_(k)\r\n\t\t\t\t\t} {\r\n\t\t\t\t\t\tgridBoxes[k-1][i-1].background_(color)\r\n\t\t\t\t\t}\r\n\t\t\t\t})\r\n\t\t\t}\r\n\t\t})\r\n\t).margins_(1).spacing_(0);\r\n\r\n\tvar envViews = (0..5).collect({arg i;\r\n\r\n\t\tEnvelopeView()\r\n\t\t.minHeight_(50)\r\n\t\t.drawLines_(true)\r\n\t\t.selectionColor_(Color.red)\r\n\t\t.drawRects_(true)\r\n\t\t.resize_(5)\r\n\t\t.step_(0.0)\r\n\t\t.thumbSize_(10)\r\n\t\t.keepHorizontalOrder_(true)\r\n\t\t.setEnv(modEnv)\r\n\t\t.action_({arg ctrl;\r\n\t\t\tvar key = ('c' ++ i ++ 'env').asSymbol;\r\n\t\t\tnode.set(key,ctrl.asEnv);\r\n\t\t})\r\n\t\t.fillColor_(Color.blue);\r\n\t});\r\n\r\n\tvar loadAlgo = {arg num;\r\n\r\n\t\t// reset\r\n\t\tvar mod_vals = algos.(num-1);\r\n\t\tvar chans = mod_vals.key;\r\n\t\tvar vals = mod_vals.value;\r\n\r\n\t\t6.do({arg i;\r\n\t\t\tchannels[i].valueAction_(0);\r\n\t\t\t6.do({arg k;\r\n\t\t\t\tvar color = Color.clear;\r\n\t\t\t\tif (i == k) {color = Color.blue.alpha_(0.2)};\r\n\t\t\t\tgridBoxes[i][k].valueAction_(0).background_(color);\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\tenvViews.do({arg v, i;\r\n\t\t\tvar key = ('c' ++ i ++ 'env').asSymbol;\r\n\t\t\tv.setEnv(modEnv);\r\n\t\t\tv.valueAction_(modEnv.asArray);\r\n\t\t});\r\n\t\tchans.do({arg i;\r\n\t\t\tvar key = ('c' ++ i ++ 'env').asSymbol;\r\n\t\t\tchannels[i].valueAction_(1);\r\n\t\t\tenvViews[i].setEnv(controllerEnv);\r\n\t\t\tenvViews[i].valueAction_(modEnv.asArray);\r\n\t\t});\r\n\r\n\r\n\t\tvals.do({arg val;\r\n\t\t\tgridBoxes[val[0]][val[1]].valueAction_(0.15).background_(Color.gray);\r\n\t\t});\r\n\t};\r\n\r\n\tvar freqViews = (0..5).collect({arg i;\r\n\r\n\t\tNumberBox()\r\n\t\t.minHeight_(15)\r\n\t\t.minWidth_(30)\r\n\t\t.clipLo_(0)\r\n\t\t.clipHi_(14)\r\n\t\t.decimals_(4)\r\n\t\t.action_({arg ctrl;\r\n\t\t\tvar key = ('c' ++ i).asSymbol;\r\n\t\t\tvar val = ctrl.value;\r\n\t\t\tnode.set(key, val);\r\n\t\t})\r\n\t\t.value_(1)\r\n\t\t.normalColor_(Color.white)\r\n\t});\r\n\r\n\tvar specs = (\r\n\t\t//trig: \\set,\r\n\t\t//freq: \\set,\r\n\t\tvrate: [0, 10, \\lin, 0, 6],\r\n\t\tvdepth: [0, 1, \\lin, 0, 0],\r\n\t\tvdelay: [0, 1, \\lin, 0, 0],\r\n\t\tvonset: [0, 1, \\lin, 0, 0],\r\n\t\tvrateVar: [0, 1, \\lin, 0, 0.04],\r\n\t\tvdepthVar: [0, 1, \\lin, 0, 0.1],\r\n\t\t//susLevel: [0,1,\\lin,0,0.5]\r\n\t);\r\n\r\n\tvar view = View().layout_(VLayout().spacing_(2).margins_(2))\r\n\t.minWidth_(400)\r\n\t.minHeight_(700)\r\n\t.palette_(QPalette.dark);\r\n\t\r\n\tvar controllersView = View().layout_(VLayout().margins_(3).spacing_(3));\r\n\r\n\t2.do({arg r;\r\n\r\n\t\tif (r > 0) {\r\n\t\t\tcontrollersView.layout.add(\r\n\t\t\t\tStaticText().string_(\" \").background_(Color.black).maxHeight_(2)\r\n\t\t\t);\r\n\t\t};\r\n\r\n\t\tcontrollersView.layout.add(\r\n\t\t\tHLayout(\r\n\t\t\t\t*(0..2).collect({arg c;\r\n\r\n\t\t\t\t\tvar num = (3 * r + c);\r\n\t\t\t\t\tVLayout(\r\n\t\t\t\t\t\tHLayout(\r\n\t\t\t\t\t\t\tchannels[num],\r\n\t\t\t\t\t\t\tStaticText().string_(\"#\" ++ (num+1)),\r\n\t\t\t\t\t\t\tnil\r\n\t\t\t\t\t\t),\r\n\t\t\t\t\t\t// controller freq ratio\r\n\t\t\t\t\t\tfreqViews[num],\r\n\r\n\t\t\t\t\t\tenvViews[num],\r\n\t\t\t\t\t\tHLayout(\r\n\t\t\t\t\t\t\tStaticText().string_(\"Level Scale\"),\r\n\t\t\t\t\t\t\tSlider().orientation_(\\horizontal).value_(1).maxHeight_(15).maxWidth_(50)\r\n\t\t\t\t\t\t\t.action_({arg ctrl;\r\n\t\t\t\t\t\t\t\tvar key = ('c' ++ num ++ 'amp').asSymbol;\r\n\t\t\t\t\t\t\t\tnode.set(key,ctrl.value);\r\n\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t),\r\n\t\t\t\t\t\tHLayout(\r\n\t\t\t\t\t\t\tStaticText().string_(\"Time Scale\"),\r\n\t\t\t\t\t\t\tSlider().orientation_(\\horizontal).value_(1).maxHeight_(15).maxWidth_(50)\r\n\t\t\t\t\t\t\t.action_({arg ctrl;\r\n\t\t\t\t\t\t\t\tvar key = ('c' ++ num ++ 'env_ts').asSymbol;\r\n\t\t\t\t\t\t\t\tnode.set(key, ctrl.value);\r\n\t\t\t\t\t\t\t})\r\n\t\t\t\t\t\t)\r\n\t\t\t\t\t)\r\n\t\t\t\t});\r\n\t\t\t);\r\n\t\t);\r\n\t});\r\n\r\n\t// algo, randomize\r\n\tview.layout.add(\r\n\t\tHLayout(\r\n\t\t\tStaticText().string_(\"algo\"),\r\n\t\t\talgoPopup = PopUpMenu()\r\n\t\t\t.items_([\"\"] ++ Array.fill(32, {arg i; i + 1}))\r\n\t\t\t.action_({arg ctrl;\r\n\t\t\t\tloadAlgo.(ctrl.value)\r\n\t\t\t}).maxHeight_(15),\r\n\t\t\tnil,\r\n\t\t\trandomizeBtn = Button().states_([[\"Randomize\"]]).action_({arg ctrl;\r\n\r\n\t\t\t\tvar num = (1..32).choose;\r\n\t\t\t\talgoPopup.valueAction_(num);\r\n\t\t\t\tfreqViews.do({arg v,i;\r\n\r\n\t\t\t\t\tvar val = if (channels[i].value) { (1..4).choose } { (rrand(1.0,14.0).dup(14) ++ (1.0..14.0)).choose };\r\n\t\t\t\t\tv.valueAction_(val);\r\n\r\n\t\t\t\t\t6.do({arg r;\r\n\t\t\t\t\t\t6.do({arg c;\r\n\t\t\t\t\t\t\tvar val = gridBoxes[r][c].value;\r\n\t\t\t\t\t\t\tif (val > 0) {\r\n\t\t\t\t\t\t\t\tval = rrand(0.01, 0.15);\r\n\t\t\t\t\t\t\t\tgridBoxes[r][c].valueAction_(val);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t})\r\n\t\t\t\t\t})\r\n\t\t\t\t});\r\n\t\t\t})\r\n\t\t).spacing_(5)\r\n\t);\r\n\r\n\tview.layout.add(StaticText().string_(\" \").background_(Color.black).maxHeight_(2));\r\n\tview.layout.add(StaticText().string_(\"Controllers\"));\r\n\tview.layout.add(controllersView);\r\n\tview.layout.add(StaticText().string_(\" \").background_(Color.black).maxHeight_(2));\r\n\tview.layout.add(StaticText().string_(\"Modulators\"));\r\n\tview.layout.add(grid);\r\n\tview.layout.add(StaticText().string_(\" \").background_(Color.black).maxHeight_(2));\r\n\tview.layout.add(StaticText().string_(\"Envelope\"));\r\n\r\n\tview.layout.add(\r\n\t\tHLayout(\r\n\t\t\tVLayout(\r\n\t\t\t\tKnob().value_(defaultAtk).action_({arg ctrl;\r\n\t\t\t\t\tvar key = \\atk;\r\n\t\t\t\t\tnode.set(key,ctrl.value);\r\n\t\t\t\t}),\r\n\t\t\t\tStaticText().string_(\"A\").align_(\\center)\r\n\t\t\t),\r\n\t\t\tVLayout(\r\n\t\t\t\tKnob().value_(defaultDecay).action_({arg ctrl;\r\n\t\t\t\t\tvar key = \\decay;\r\n\t\t\t\t\tnode.set(key,ctrl.value);\r\n\t\t\t\t}),\r\n\t\t\t\tStaticText().string_(\"D\").align_(\\center)\r\n\t\t\t),\r\n\t\t\tVLayout(\r\n\t\t\t\tHLayout(\r\n\t\t\t\t\tKnob().value_(defaultSus).action_({arg ctrl;\r\n\t\t\t\t\tvar key = \\sus;\r\n\t\t\t\t\tnode.set(key,ctrl.value);\r\n\t\t\t\t}),\r\n\t\t\t\t\tSlider().maxHeight_(35).maxWidth_(15).thumbSize_(10).value_(defaultSusLevel)\r\n\t\t\t\t\t.action_({arg ctrl;\r\n\t\t\t\t\t\tvar key = \\susLevel;\r\n\t\t\t\t\t\tnode.set(key,ctrl.value);\r\n\t\t\t\t\t})\r\n\t\t\t\t),\r\n\t\t\t\tStaticText().string_(\"S\").align_(\\center)\r\n\t\t\t),\r\n\t\t\tVLayout(\r\n\t\t\t\tKnob().value_(defaultRel).action_({arg ctrl;\r\n\t\t\t\t\tvar key = \\rel;\r\n\t\t\t\t\tnode.set(key,ctrl.value);\r\n\t\t\t\t}),\r\n\t\t\t\tStaticText().string_(\"R\").align_(\\center)\r\n\t\t\t),\r\n\t\t\tVLayout(\r\n\t\t\t\tKnob().value_(defaultAmp).action_({arg ctrl;\r\n\t\t\t\t\tvar key = \\amp;\r\n\t\t\t\t\tnode.set(key,ctrl.value);\r\n\t\t\t\t}),\r\n\t\t\t\tStaticText().string_(\"Output\").align_(\\center)\r\n\t\t\t)\r\n\t\t)\r\n\t);\r\n\r\n\tview.layout.add(StaticText().string_(\" \").background_(Color.black).maxHeight_(2));\r\n\r\n\tview.layout.add(StaticText().string_(\"EQ\"));\r\n\r\n\tview.layout.add(HLayout(\r\n\t\tSlider2D().fixedSize_(45).action_({arg ctrl;\r\n\t\t\tnode.set(\\lo_freq, ctrl.x.linlin(0,1,0.1,1000));\r\n\t\t\tnode.set(\\lo_db, ctrl.y.linlin(0,1,-18,18));\r\n\t\t}).x_(100.linlin(0,1000,0,1)).y_(0.linlin(-18,18,0,1)),\r\n\r\n\t\tSlider2D().fixedSize_(45).action_({arg ctrl;\r\n\t\t\tnode.set(\\mid_freq, ctrl.x.linlin(0,1,1000,10000));\r\n\t\t\tnode.set(\\mid_db, ctrl.y.linlin(0,1,-18,18));\r\n\t\t}).x_(1000.linlin(1000,10000,0,1)).y_(0.linlin(-18,18,0,1)),\r\n\r\n\t\tSlider2D().fixedSize_(45).action_({arg ctrl;\r\n\t\t\tnode.set(\\hi_freq, ctrl.x.linlin(0,1,10000,20000));\r\n\t\t\tnode.set(\\hi_db, ctrl.y.linlin(0,1,-18,18));\r\n\t\t}).x_(10000.linlin(10000,20000,0,2)).y_(0.linlin(-18,18,0,1))\r\n\t));\r\n\r\n\tview.layout.add(\r\n\t\tHLayout(\r\n\t\t\tStaticText().string_(\"Wet\"),\r\n\t\t\tSlider().action_({arg ctrl;\r\n\t\t\t\tnode.set(\\wet1, ctrl.value);\r\n\t\t\t}).value_(0).orientation_(\\horizontal)\r\n\t\t)\r\n\t);\r\n\r\n\tview.front;\r\n\t\r\n\trandomizeBtn.valueAction_(0);\r\n\t\r\n\tnode;\r\n};\r\n)\r\n\r\n(\r\n/////////////////////////////////////////\r\n// #2\r\n// create the ui and nodeproxy\r\n~fm7 = ~fm7_ui.();\r\n~fm7.clock_(TempoClock.new(1));\r\n// start monitoring\r\n~fm7.play;\r\n)\r\n\r\n(\r\n/////////////////////////////////////////\r\n// #3\r\n// add some fx\r\n\r\n// this fx requires the Feedback Quark\r\n// Comment this out if not installed.\r\n~fm7.filter(3, {arg in;\r\n\t\r\n\tvar tap1, tap2, tap3, tap4;\r\n\tvar fbNode = FbNode(1, 6.5, 4);\r\n\r\n\tvar tap1_delay = \\tap1_delay.kr(0.2).lag(0.1);\r\n\tvar tap2_delay = \\tap2_delay.kr(0.5).lag(0.1);\r\n\tvar tap3_delay = \\tap3_delay.kr(0.7).lag(0.1);\r\n\tvar tap4_delay = \\tap4_delay.kr(1).lag(0.1);\r\n\r\n\tvar tap1_mul = \\tap1_mul.kr(1).lag(0.1);\r\n\tvar tap2_mul = \\tap2_mul.kr(0.7).lag(0.1);\r\n\tvar tap3_mul = \\tap3_mul.kr(0.5).lag(0.1);\r\n\tvar tap4_mul = \\tap4_mul.kr(0.2).lag(0.1);\r\n\r\n\ttap1 = fbNode.delay(tap1_delay);\r\n\ttap2 = fbNode.delay(tap2_delay);\r\n\ttap3 = fbNode.delay(tap3_delay);\r\n\ttap4 = fbNode.delay(tap4_delay);\r\n\r\n\tfbNode.write(Mix.ar(in)\r\n\t\t+ (tap1 * \\tap1_fb.kr(0).lag(0.1))\r\n\t\t+ (tap2 * \\tap2_fb.kr(0).lag(0.1))\r\n\t\t+ (tap3 * \\tap3_fb.kr(0).lag(0.1))\r\n\t\t+ (tap4 * \\tap4_fb.kr(0).lag(0.1))\r\n\t);\r\n\r\n\tSplay.ar([tap1 * tap1_mul, tap2 * tap2_mul, tap3 * tap3_mul, tap4 * tap4_mul],\r\n\t\t\\spread.kr(1),\r\n\t\tcenter:\\center.kr(0)\r\n\t);\r\n}).set(\\wet3, 0.5, \\tap1_delay, 1.63);\r\n\r\n~fm7.filter(4, {arg in;\r\n\tJPverb.ar(in);\r\n}).set(\\wet4, 0.3);\r\n\r\n// add a pattern\r\n~fm7[8] = \\set -> Pbind(\r\n        \\trig, 1,\r\n\t\\octave, 5,\r\n\t\\scale, Scale.minor,\r\n\t\\mtranspose, Pstutter(128, Pseq([1,0], inf)),\r\n\t\\degree, Pwhite(0, 5, inf),\r\n\t\\delta, 0.25\r\n));",
   "labels" : [
      "gui",
      "fm",
      "frequency modulation",
      "ui"
   ]
}
