{
   "name" : "multiple wavetable animation",
   "author" : "eli.fieldsteel",
   "description" : "GUI animation for multiple wavetable interpolation",
   "ancestor_list" : [],
   "labels" : [
      "animation",
      "multiple wavetable synthesis"
   ],
   "id" : "1-5bK",
   "is_private" : null,
   "code" : "(\r\n//after running code, esc key to close window and abort animation\r\n\r\nvar wt0, wt1, result,\r\nwt0view, wt1view, resultView, animateFn, wmean, numSteps, animate, wtIndex,\r\nwin, wtPosBox, wtPosView;\r\n\r\nanimateFn.stop;\r\nnumSteps = 101;\r\nanimate = true;\r\nwtIndex = 0.0;\r\n\r\n//weighted mean function\r\nwmean = {\r\n\targ coll, weights;\r\n\tcoll.sum({arg n,i; n*weights[i]}) / weights.sum;\r\n};\r\n\r\n/*----------------------------------*/\r\n//user can edit \"wt0\" and \"wt1\" variables\r\n//to be any Signal of size 384\r\n//\r\n//code will animate interpolation\r\n//between these two wavetables\r\n/*----------------------------------*/\r\n\r\n//wavetable 0: 8 lowest harmonics at equal phases and amplitudes\r\nwt0 = Signal.sineFill(384, 1/(1..8),0!8);\r\n\r\n//other options for wavetable 0, or DIY:\r\n//wt0 = Env({rrand(-1.0,1.0)}!8, {rrand(0,20)}!7, {rrand(-10,10)}!7).asSignal(384);\r\n\r\n//wavetable 1: partials 1,3,4,5 at various amplitudes and phases\r\nwt1 = Signal.sineFill(384, [1,0,1/2,1,1/4],[0,0,pi,0,pi]);\r\n\r\n//(or make your own DIY Signal for wt1)\r\n\r\n//do not edit \"result\" (calculated from wt0 and wt1)\r\nresult = Signal.fill(384, {\r\n\targ i;\r\n\twmean.([wt0,wt1].flop[i],[1 - wtIndex, wtIndex]);\r\n});\r\n\r\nWindow.closeAll;\r\nwin = Window.new(\"\", Window.screenBounds, false, false).front;\r\nwin.view.background_(Color.gray(0.1));\r\nwin.view.keyDownAction_({\r\n\targ view, char, mod, uni;\r\n\r\n\t//esc to abort & close window\r\n\tif(uni == 27, {animateFn.stop;win.close;})\r\n});\r\n\r\nStaticText(win, Rect(60,100,384,48))\r\n.font_(Font(Font.defaultSansFace, 36))\r\n.stringColor_(Color.gray(0.8))\r\n.string_(\"wavetable 0\")\r\n.align_(\\center);\r\n\r\nStaticText(win, Rect(400,347,50,20))\r\n.font_(Font(Font.defaultSansFace, 18))\r\n.stringColor_(Color.gray(0.8))\r\n.string_(\"time\")\r\n.align_(\\center);\r\n\r\nStaticText(win, Rect(218,170,30,20))\r\n.font_(Font(Font.defaultSansFace, 18))\r\n.stringColor_(Color.gray(0.8))\r\n.string_(\"+1\")\r\n.align_(\\center);\r\n\r\nStaticText(win, Rect(219,554,30,20))\r\n.font_(Font(Font.defaultSansFace, 18))\r\n.stringColor_(Color.gray(0.8))\r\n.string_(\"-1\")\r\n.align_(\\center);\r\n\r\nwt0view = UserView.new(win, Rect(60,180,384,384)).background_(Color.clear);\r\nwt0view.clearOnRefresh_(true);\r\nwt0view.drawFunc = {nil};\r\nwt0view.refresh;\r\nwt0view.drawFunc_({\r\n\tPen.strokeColor_(Color.gray(0.2));\r\n\tPen.width_(2);\r\n\tPen.line(192@0, 192@384);\r\n\tPen.line(0@192,384@192);\r\n\tPen.stroke;\r\n\tPen.strokeColor_(Color.gray(0.35));\r\n\tPen.width_(5);\r\n\tPen.moveTo(0@384);\r\n\r\n\t(wt0.size-1).do{\r\n\t\targ i;\r\n\t\tPen.line(\r\n\t\t\tPoint(i, wt0[i].linlin(-1.02,1.02,384,0)),\r\n\t\t\tPoint(i+1, wt0[i+1].linlin(-1.02,1.02,384,0))\r\n\t\t);\r\n\t\tPen.stroke;\r\n\t};\r\n\r\n});\r\n\r\nStaticText(win, Rect(517,100,384,48))\r\n.font_(Font(Font.defaultSansFace, 36))\r\n.stringColor_(Color.gray(0.8))\r\n.string_(\"result\")\r\n.align_(\\center);\r\n\r\nStaticText(win, Rect(855,347,50,20))\r\n.font_(Font(Font.defaultSansFace, 18))\r\n.stringColor_(Color.gray(0.8))\r\n.string_(\"time\")\r\n.align_(\\center);\r\n\r\nStaticText(win, Rect(673,170,30,20))\r\n.font_(Font(Font.defaultSansFace, 18))\r\n.stringColor_(Color.gray(0.8))\r\n.string_(\"+1\")\r\n.align_(\\center);\r\n\r\nStaticText(win, Rect(674,554,30,20))\r\n.font_(Font(Font.defaultSansFace, 18))\r\n.stringColor_(Color.gray(0.8))\r\n.string_(\"-1\")\r\n.align_(\\center);\r\n\r\n\r\nresultView = UserView.new(win, Rect(517,180,384,384)).background_(Color.clear);\r\nresultView.clearOnRefresh_(true);\r\nresultView.drawFunc = {nil};\r\nresultView.refresh;\r\n\r\nresultView.drawFunc_({\r\n\r\n\tresult = Signal.fill(384, {\r\n\t\targ i;\r\n\t\twmean.([wt0,wt1].flop[i],[1 - wtIndex, wtIndex]);\r\n\t});\r\n\r\n\tPen.strokeColor_(Color.gray(0.2));\r\n\tPen.width_(2);\r\n\tPen.line(192@0, 192@384);\r\n\tPen.line(0@192,384@192);\r\n\tPen.stroke;\r\n\tPen.strokeColor_(Color.gray(0.75));\r\n\tPen.width_(5);\r\n\tPen.moveTo(0@384);\r\n\r\n\r\n\t(result.size-1).do{\r\n\t\targ i;\r\n\t\tPen.line(\r\n\t\t\tPoint(i, result[i].linlin(-1.02,1.02,384,0)),\r\n\t\t\tPoint(i+1, result[i+1].linlin(-1.02,1.02,384,0))\r\n\t\t);\r\n\t\tPen.stroke;\r\n\t};\r\n\r\n});\r\nresultView.refresh;\r\n\r\nStaticText(win, Rect(974,100,384,48))\r\n.font_(Font(Font.defaultSansFace, 36))\r\n.stringColor_(Color.gray(0.8))\r\n.string_(\"wavetable 1\")\r\n.align_(\\center);\r\n\r\nStaticText(win, Rect(1314,347,50,20))\r\n.font_(Font(Font.defaultSansFace, 18))\r\n.stringColor_(Color.gray(0.8))\r\n.string_(\"time\")\r\n.align_(\\center);\r\n\r\nStaticText(win, Rect(1132,170,30,20))\r\n.font_(Font(Font.defaultSansFace, 18))\r\n.stringColor_(Color.gray(0.8))\r\n.string_(\"+1\")\r\n.align_(\\center);\r\n\r\nStaticText(win, Rect(1133,554,30,20))\r\n.font_(Font(Font.defaultSansFace, 18))\r\n.stringColor_(Color.gray(0.8))\r\n.string_(\"-1\")\r\n.align_(\\center);\r\n\r\nwt1view = UserView.new(win, Rect(974,180,384,384)).background_(Color.clear);\r\nwt1view.clearOnRefresh_(true);\r\nwt1view.drawFunc = {nil};\r\nwt1view.refresh;\r\nwt1view.drawFunc_({\r\n\tPen.strokeColor_(Color.gray(0.2));\r\n\tPen.width_(2);\r\n\tPen.line(192@0, 192@384);\r\n\tPen.line(0@192,384@192);\r\n\tPen.stroke;\r\n\tPen.strokeColor_(Color.gray(0.35));\r\n\tPen.width_(5);\r\n\tPen.moveTo(0@384);\r\n\t(wt1.size-1).do{\r\n\t\targ i;\r\n\t\tPen.line(\r\n\t\t\tPoint(i, wt1[i].linlin(-1.02,1.02,384,0)),\r\n\t\t\tPoint(i+1, wt1[i+1].linlin(-1.02,1.02,384,0))\r\n\t\t);\r\n\t\tPen.stroke;\r\n\t};\r\n\tPen.stroke;\r\n});\r\nwt1view.refresh;\r\n\r\nStaticText(win, Rect(483,680,358,50))\r\n.font_(Font(Font.defaultSansFace, 36))\r\n.stringColor_(Color.new(0,0.75,1,0.6))\r\n.string_(\"wavetable position:\")\r\n.align_(\\center);\r\n\r\nwtPosBox = NumberBox(win, Rect(853,685,85,40))\r\n.font_(Font(Font.defaultSansFace, 36))\r\n.background_(Color.gray(0.1))\r\n.normalColor_(Color.new(0,0.75,1,0.8))\r\n.decimals_(2)\r\n.value_(wtIndex)\r\n.enabled_(false);\r\n\r\nwtPosView = UserView.new(win, Rect(60,740,1298,26)).background_(Color.clear);\r\nwtPosView.drawFunc_({\r\n\tPen.strokeColor_(Color.gray(0.2));\r\n\tPen.width_(2);\r\n\tPen.line(195@13, 1103@13);\r\n\tPen.stroke;\r\n\tPen.width_(5);\r\n\tPen.strokeColor_(Color.new(0,0.75,1,0.8));\r\n\tPen.addArc(\r\n\t\tPoint(\r\n\t\t\twtIndex.linlin(0,1,195,1103),\r\n\t\t\t13\r\n\t\t),\r\n\t\t10, 0, 2pi\r\n\t);\r\n\tPen.stroke;\r\n});\r\n\r\nif(animate, {\r\n\tanimateFn = {\r\n\t\t1.wait;\r\n\t\tArray.interpolation(numSteps,0,1).do({\r\n\t\t\targ n;\r\n\t\t\twtIndex = n;\r\n\t\t\tresultView.drawFunc_({\r\n\r\n\t\t\t\tresult = Signal.fill(384, {\r\n\t\t\t\t\targ i;\r\n\t\t\t\t\twmean.([wt0,wt1].flop[i],[1 - wtIndex, wtIndex]);\r\n\t\t\t\t});\r\n\r\n\t\t\t\tPen.strokeColor_(Color.gray(0.2));\r\n\t\t\t\tPen.width_(2);\r\n\t\t\t\tPen.line(192@0, 192@384);\r\n\t\t\t\tPen.line(0@192,384@192);\r\n\t\t\t\tPen.stroke;\r\n\t\t\t\tPen.strokeColor_(Color.gray(0.75));\r\n\t\t\t\tPen.width_(5);\r\n\t\t\t\tPen.moveTo(0@384);\r\n\r\n\r\n\t\t\t\t(result.size-1).do{\r\n\t\t\t\t\targ i;\r\n\t\t\t\t\tPen.line(\r\n\t\t\t\t\t\tPoint(i, result[i].linlin(-1.02,1.02,384,0)),\r\n\t\t\t\t\t\tPoint(i+1, result[i+1].linlin(-1.02,1.02,384,0))\r\n\t\t\t\t\t);\r\n\t\t\t\t\tPen.stroke;\r\n\t\t\t\t};\r\n\r\n\t\t\t});\r\n\t\t\tresultView.refresh;\r\n\t\t\twtPosView.refresh;\r\n\t\t\twtPosBox.value_(wtIndex);\r\n\t\t\t0.02.wait;\r\n\t\t});\r\n\t}.fork(AppClock);\r\n});\r\n)"
}
