{
   "code" : "Launchpad{\r\n\tclassvar <>midiout;\r\n\tclassvar <>pads;//2DARRAY\r\n\tclassvar nonr,nofr,cor;//MIDI RESPONDER FUNCTIONS\r\n\t*initClass{\r\n\t\tif(Launchpad.initMIDI.notNil,{\r\n\t\t\tLaunchpad.setupLP;\r\n\t\t\tLaunchpad.pads=Array2D.fromArray(9,9,\r\n\t\t\t\tArray.fill(81,{|i|LPPad.new((i/9).asInteger,i%9)}));\r\n\t\t})\r\n\t}\r\n\t*initMIDI{\r\n\t\tvar non,nof,co,midisource,mididestination;\r\n\t\tMIDIClient.init;\r\n\t\tmidisource=MIDIClient.sources.detect{|a|a.name.contains(\"Launchpad\")};\r\n\t\tif(midisource.notNil,{\r\n\t\t\tmididestination=MIDIClient.destinations.detect{|a|a.name.contains(\"Launchpad\")};\r\n\t\t\tMIDIIn.connect(0, midisource.uid);\r\n\t\t\tmidiout=MIDIOut(0, mididestination.uid);\r\n\t\t\tMIDIOut.connect(0, mididestination.uid);\r\n\t\t\tnon={|src,chan,num,val|\r\n\t\t\t\tvar x=num%16;\r\n\t\t\t\tvar y=(num-x)/16;\r\n\t\t\t\t//[\\on,src,chan,num,val].postln;\r\n\t\t\t\t//r{\r\n\t\t\t\tif(val===127,{\r\n\t\t\t\t\tpads.at(x,y+1).responseOn;\r\n\t\t\t\t\t},{\r\n\t\t\t\t\t\tpads.at(x,y+1).responseOff;\r\n\t\t\t\t});\r\n\t\t\t\t//}.play;\r\n\t\t\t};\r\n\t\t\tnonr=NoteOnResponder(non,midisource.uid,swallowEvent:true);\r\n\t\t\tnof={|src,chan,num,val|\r\n\t\t\t\tvar x=num%16;\r\n\t\t\t\tvar y=(num-x)/16;\r\n\t\t\t\t//[\\off,src,chan,num,val].postln;\r\n\t\t\t\t//r{\r\n\t\t\t\tpads.at(x,y+1).responseOff;\r\n\t\t\t\t//}.play;\r\n\t\t\t};\r\n\t\t\tnofr=NoteOffResponder(non,midisource.uid,swallowEvent:true);\r\n\t\t\tco={|src,chan,num,val|\r\n\t\t\t\tvar x=num-104;\r\n\t\t\t\t//[\\co,src,chan,num,val].postln;\r\n\t\t\t\t//r{\r\n\t\t\t\tif((val%2)===1,{\r\n\t\t\t\t\tpads.at(x,0).responseOn;\r\n\t\t\t\t\t},{\r\n\t\t\t\t\t\tpads.at(x,0).responseOff;\r\n\t\t\t\t})\r\n\t\t\t\t//}.play;\r\n\t\t\t};\r\n\t\t\tcor=CCResponder(co,midisource.uid,swallowEvent:true);\r\n\t\t\t^ 1;\r\n\t\t\t},{\r\n\t\t\t\t\"Launchpad Not available\".postln;\r\n\t\t\t\t^nil;\r\n\t\t})\r\n\t}\r\n\t*resetLED{\r\n\t\t//reset\r\n\t\tpads.do{|i|i.led=LPLED.black};\r\n\t\tmidiout.control(0,0,0);\r\n\t}\r\n\t*xyMode{\r\n\t\tmidiout.control(0,0,1);\r\n\t}\r\n\t*drumMode{\r\n\t\tmidiout.control(0,0,2);\r\n\t}\r\n\t*setContrast{|num=1,denum=6|\r\n\t\tmidiout.control(0,30,((16*(num-1))+(denum-3)));\r\n\t}\r\n\t*setupLP{\r\n\t\tthis.resetLED;\r\n\t\tthis.xyMode;\r\n\t\tthis.setContrast;\r\n\t}\r\n\t*xyMIDINode{|x,y|\r\n\t\t^(x+(y*16))\r\n\t}\r\n\t*pos2CC{|pos|\r\n\t\t^(104+pos)\r\n\t}\r\n\t*getRange{|fx,fy,tx,ty|\r\n\t\tvar ttx,tty;\r\n\t\t//ttx=if(fx>=(tx?0),{fx+1},{tx+1});\r\n\t\t//tty=if(fy>=(ty?0),{fy+1},{ty+1s});\r\n\t\tttx=tx?fx;\r\n\t\ttty=ty?fy;\r\n\t\t^LPRange(pads.copyRange(fx,fy,ttx,tty));\r\n\t}\r\n\t//simply set LEDs\r\n\t*setLED{|x,y,val|\r\n\t\t//\\setLED.postln;\r\n\t\tif(y==0,{\r\n\t\t\tLaunchpad.setTopLED(x,y,val);\r\n\t\t},{\r\n\t\t\tLaunchpad.setMatrixLED(x,y,val);\r\n\t\t})\r\n\t}\r\n\t*setMatrixLED{|x,y,val|\r\n\t\tmidiout.noteOn(0, Launchpad.xyMIDINode(x,y-1), val);\r\n\t\t}\r\n\t*setTopLED{|x,y,val|\r\n\t\tmidiout.control(0, Launchpad.pos2CC(x), val);\r\n\t\t}\r\n\t*setPlayLED{|x,y,val|\r\n\t\tmidiout.noteOn(0, Launchpad.xyMIDINode(8,y), val);\r\n\t}\r\n\t//set LEDs for initialisation\r\n\t*setAllLED{|ledarray|\r\n\t\t\"todo\".postln;\r\n\t}\r\n\t//doublebuffering?\r\n\t//flashing?\r\n}\r\n\r\nLPRange{\r\n\tvar <>pads;//2DARRAY\r\n\t*new{|b|\r\n\t\t^super.new.init(b);\r\n\t}\r\n\tinit{|b|\r\n\t\tpads=b;\r\n\t}\r\n\tgetRange{|fx,fy,tx,ty|\r\n\t\tvar ttx,tty;\r\n\t\tttx=tx?fx;\r\n\t\ttty=ty?fy;\r\n\t\t^LPRange(pads.copyRange(fx,fy,ttx,tty));\r\n\t}\r\n\tparent_{|o|\r\n\t\tpads.do{|i|i.parent=o};\r\n\t}\r\n\tled_{|l|\r\n\t\tpads.do{|i|i.led=l};\r\n\t}\r\n}\r\n\r\nLPPad{\r\n\tvar <>x,<>y;\r\n\tvar led;\r\n\tvar <>pastparent;\r\n\tvar pastled;\r\n\tvar <parent;\r\n\tled_{|l|\r\n\t\tvar v,nv;\r\n\t\tpastled=led;\r\n\t\tled=l;\r\n\t\tv=if(pastled.notNil,{pastled.value.vel},{LPLED.black.vel});\r\n\t\tnv=led.value.vel;\r\n\t\t//[\\setled,x,y,v,nv,l.value.vel,led.value.vel].postln;\r\n\t\tif(v!=nv,{Launchpad.setLED(x,y,nv)});\r\n\t\t//Launchpad.setLED(x,y,l.value.vel);\r\n\t}\r\n\tparent_{|p|\r\n\t\tpastparent=parent;\r\n\t\tparent=p;\r\n\t\t//p.lppad=this;\t\twhy was this?\r\n\t}\r\n\tunparent{|blacking=true|\r\n\t\tparent=pastparent;\r\n\t\tpastparent=nil;\r\n\t\t//[\\parent,parent].postln;\r\n\t\tif(parent.isNil,{if(blacking,{led={LPLED.black};Launchpad.setLED(x,y,led.value.vel)})},{parent.initLED});\r\n\t}\r\n\t*new{|x,y|\r\n\t\t^super.new.init(x,y);\r\n\t}\r\n\tinit{|ax,ay,p|\r\n\t\tx=ax;\r\n\t\ty=ay;\r\n\t\tparent=p;\r\n\t}\r\n\tresponseOn{\r\n\t\tparent.responseOn(this);\r\n\t}\r\n\tresponseOff{\r\n\t\tparent.responseOff(this);\r\n\t}\r\n}\r\n\r\n\r\nLPLED{\r\n\tvar <>green,<>red,clear,copy;\r\n\t*new{|green=0,red=0,clear=1,copy=1|\r\n\t\t^super.new.init(green,red,clear,copy);\r\n\t}\r\n\t*black{^this.new(0)}\r\n\t*green{|s=3|s=s.min(3);^this.new(s)}\r\n\t*red{|s=3|s=s.min(3);^this.new(0,s)}\r\n\t*amber{|s=3|s=s.min(3); ^this.new(s,s)}\r\n\t*yellow{|s=2|s=s.min(2);^this.new(s+1,s)}\r\n\t*orange{|s=2|s=s.min(2);^this.new(s,s+1)}\r\n\tnext{\r\n\t\tvar g,r;\r\n\t\tvar ns=4.collect{|g| 4.collect{|r|[g,r]}}.flatten;\r\n\t\t#g,r=ns[(ns.indexOfEqual([green,red])+1)%ns.size];\r\n\t\tgreen=g;\r\n\t\tred=r;\r\n\t}\r\n\tinit{|gr,re,cl,co|\r\n\t\tgreen=gr;\r\n\t\tred=re;\r\n\t\tclear=cl;\r\n\t\tcopy=co;\r\n\t}\r\n\tvel{\r\n\t\t^(\r\n\t\t\t(2.pow(4)*green.value.round.asInteger)\r\n\t\t\t+\r\n\t\t\t(2.pow(3)*clear)\r\n\t\t\t+\r\n\t\t\t(2.pow(2)*copy)\r\n\t\t\t+\r\n\t\t\t(red.value.round.asInteger)\r\n\t\t);\r\n\t}\r\n}\r\n\r\nLPButton{//eine typische abstraktion\r\n\tvar <>parent;\r\n\tvar <>onFunction,<>offFunction;\r\n\t*new {|onFunction,offFunction|\r\n\t\t^super.new.padinit(onFunction,offFunction);\r\n\t}\r\n\tpadinit{| onf, offf|\r\n\t\tonFunction= onf;\r\n\t\toffFunction= offf;\r\n\t}\r\n\tresponseOn{|pad|\r\n\t\tonFunction.value(pad);\r\n\t}\r\n\tresponseOff{|pad|\r\n\t\toffFunction.value(pad);\r\n\t}\r\n\tinitLED{\r\n\t\tparent.initLED;\r\n\t}\r\n}\r\n\r\nLPWidget{//lpwidgets sind moegliche parents fuer ranges\r\n\tvar <>range;\r\n\tvar onfront;\r\n\tvar onhide;\r\n\tvar isfront;\r\n\t*new{|range,onfront,onhide|\r\n\t\t^super.new.winit(range,onfront,onhide);\r\n\t}\r\n\twinit{|r,of,oh|\r\n\t\trange=r;\r\n\t\tonfront=of;\r\n\t\tonhide=oh;\r\n\t}\r\n\tfront{|r|\r\n\t\tonfront.value(this);\r\n\t\tisfront=true;\r\n\t\trange=r?range;\r\n\t\tthis.initParent;\r\n\t\tthis.initLED;\r\n\t}\r\n\thide{|blacking=true|\r\n\t\tonhide.value(blacking);\r\n\t\tisfront!?{\r\n\t\t\tisfront=nil;\r\n\t\t\trange.pads.do{|p|p.unparent(blacking)};\r\n\t\t};\r\n\t}\r\n\tresponseOn{|pad|\r\n\t}\r\n\tresponseOff{|pad|\r\n\t}\r\n\tinitParent{\r\n\t\trange.parent=this;\r\n\t}\r\n\tinitLED{\r\n\t\t//range.led=...;\r\n\t}\r\n}\r\n\r\nLPBlackWidget : LPWidget{\r\n\tvar <>led;\r\n\t*new {|range,onfront,onhide|\r\n\t\t^super.new(range,onfront,onhide).bwinit;\r\n\t}\r\n\tbwinit{\r\n\t\tled=LPLED.black;\r\n\t}\r\n\tinitLED{\r\n\t\trange.led=led;\r\n\t}\r\n}\r\n\r\nLPLEDButton : LPWidget{\r\n\tvar <>button;\r\n\tvar <>onled;\r\n\tvar <>offled;\r\n\tvar state;\r\n\t*new {|button,onled,offled,range,onfront,onhide|\r\n\t\t^super.new(range,onfront,onhide).ledpadinit(button,onled,offled);\r\n\t}\r\n\tledpadinit{|bt,onl,offl,r|\r\n\t\tstate=0;\r\n\t\tbutton=bt??{LPButton()};\r\n\t\tbutton.parent=this;\r\n\t\tonled=onl??{LPLED.red(2)};\r\n\t\toffled=offl??{LPLED.green(2)};\r\n\t}\r\n\tinitLED{\r\n\t\trange.led=offled;\r\n\t}\r\n\tresponseOn{|pad|\r\n\t\tbutton.responseOn(pad);\r\n\t\trange.led=onled;\r\n\t}\r\n\tresponseOff{|pad|\r\n\t\tbutton.responseOff(pad);\r\n\t\trange.led=offled;\r\n\t}\r\n}\r\n\r\nLPLEDSwitch : LPWidget{\r\n\tvar functions;\r\n\tvar leds;\r\n\tvar <state;\r\n\t*new{|functions,leds,state,range,onfront,onhide|\r\n\t\t^super.new(range,onfront,onhide).ledbuttoninit(functions,leds,state);\r\n\t}\r\n\tledbuttoninit{|f,l,s|\r\n\t\tfunctions=f;\r\n\t\tleds=l;\r\n\t\tstate=s;\r\n\t\tif(functions.size!=leds.size,{^MethodError(\"function array size unequal led array size\",this).throw});\r\n\t\tstate=functions.size-1;\r\n\t}\r\n\tinitLED{\r\n\t\trange.led=leds[state];\r\n\t}\r\n\tresponseOn{|pad|\r\n\t\tthis.state=(state+1)%functions.size;\r\n\t\tfunctions[state].value(pad);\r\n\t}\r\n\tstate_{|x|\r\n\t\tstate=x;\r\n\t\tthis.initLED;\r\n\t}\r\n}\r\n\r\nLPFader : LPWidget{\r\n\tvar statevarroutine;\r\n\tvar <>onoff;\r\n\tvar func;\r\n\tvar <>state;\r\n\tvar getstatefunc;\r\n\tvar size;\r\n\tvar oncolor;\r\n\tvar offcolor;\r\n\t*new {|func,getstatefunc,oncolor,offcolor,range,onfront,onhide|\r\n\t\t//\"LPVFader is not tested\".postln;\r\n\t\t^super.new(range,onfront,onhide).finit(func,getstatefunc,oncolor,offcolor);\r\n\t}\r\n\tfinit{|f,g,onc,ofc|\r\n\t\tgetstatefunc=g;\r\n\t\tfunc=f;\r\n\t\toncolor=onc;\r\n\t\toffcolor=ofc;\r\n\t}\r\n\tupdateState{|padpos|\r\n\t\tonoff=true;\r\n\t\tstatevarroutine.stop;\r\n\t\tstatevarroutine=r{\r\n\t\t\twhile({onoff},{\r\n\t\t\t\tfunc.value(this,padpos);\r\n\t\t\t\tthis.updateLED;\r\n\t\t\t\t0.2.wait;\r\n\t\t\t})\r\n\t\t}.play;\r\n\t}\r\n\tinitParent{\r\n\t\tsize=range.pads.size;\r\n\t\tstate=getstatefunc.value(this);\r\n\t\trange.pads.do{|item,i|\r\n\t\t\titem.parent=LPButton({this.updateState(i)},{onoff=false});\r\n\t\t\titem.parent.parent=this;\r\n\t\t};\r\n\t}\r\n\tinitLED{\r\n\t\tthis.updateLED;\r\n\t}\r\n\tupdateLED{\r\n\t\tvar ledstate,lls;\r\n\t\tledstate=state*size;\r\n\t\trange.pads.do{|item,i|\r\n\t\t\tif(ledstate>((size-1)-i),{\r\n\t\t\t\tlls=ledstate-((size-1)-i);\r\n\t\t\t\tledstate=ledstate-lls;\r\n\t\t\t\titem.led=LPLED.perform(oncolor,lls*3);\r\n\t\t\t\t//{item.led=LPLED.green(lls*3)},\r\n\t\t\t\t//{item.led=LPLED.red(lls*3)}\r\n\t\t\t\t//);\r\n\t\t\t},{\r\n\t\t\t\titem.led=LPLED.perform(offcolor,1);\r\n\t\t\t})\r\n\t\t}\r\n\t}\r\n}\r\n\r\nLPParameterFader :LPFader{\r\n\tvar rand;\r\n\t*new{|parameter,oncolor,offcolor,range,onfront,onhide,rand|\r\n\t\t^super.new(nil,nil,nil,nil,range,onfront,onhide).pfinit(parameter,oncolor,offcolor,rand);\r\n\t}\r\n\tpfinit{|parameter,oncolor,offcolor,r|\r\n\t\trand=r;\r\n\t\tthis.finit({|fader,padpos|\r\n\t\t\tvar state=parameter.asSpec.map(fader.state+[0.1,0.02,0.005,rand.postln.value.postln.bilinrand.postln(\\rand), -0.005, -0.02, -0.1][padpos]);\r\n\t\t\tfader.state=parameter.asSpec.unmap(state);\r\n\t\t\tLPSetupNormalGlobals.synth.value.node.set(parameter,state.postln(\" \"++parameter++\":\"));\r\n\t\t},{\r\n\t\t\tvar value=LPSetupNormalGlobals.synth.value.node.getKeysValues.detect{|i|i[0]===parameter}[1];\r\n\t\t\tparameter.asSpec.unmap(value);\r\n\t\t},oncolor,offcolor);\r\n\t}\r\n}\r\n\r\n\r\nLPSpecFader : LPWidget{\r\n\tvar statevarroutine;\r\n\tvar onoff;\r\n\tvar func;\r\n\tvar state;\r\n\tvar spec;\r\n\tvar size;\r\n\t*new {|func,spec,range,onfront,onhide|\r\n\t\t//\"LPVFader is not tested\".postln;\r\n\t\t^super.new(range,onfront,onhide).finit(func,spec);\r\n\t}\r\n\tfinit{|f,s|\r\n\t\tspec=s;\r\n\t\tstate=spec.unmap(spec.default);\r\n\t\tfunc=f;\r\n\t}\r\n\tupdateState{|padpos|\r\n\t\tvar ud = ((size - 1) / 2) - padpos;\r\n\t\tvar specstep=if(spec.step==0,{spec.range/512},{spec.step});\r\n\t\tvar step=specstep/spec.range;\r\n\t\tonoff=true;\r\n\t\tstatevarroutine.stop;\r\n\t\tstatevarroutine=r{\r\n\t\t\twhile({onoff},{\r\n\t\t\t\tcase\r\n\t\t\t\t//{ud >  0}{state=spec.unmap(spec.map(state)+(step*2.pow(ud)))}\r\n\t\t\t\t{ud >  0}{state=((state)+(step*2.pow(ud))).min(1)}\r\n\t\t\t\t{ud == 0}{state.postln;}\r\n\t\t\t\t//{ud <  0}{state=spec.unmap(spec.map(state)-(step*2.pow(ud.abs)))}\r\n\t\t\t\t{ud <  0}{state=((state)-(step*2.pow(ud.abs))).max(0)}\r\n\t\t\t\t;\r\n\t\t\t\tthis.updateLED;\r\n\t\t\t\tfunc.value(spec.map(state),this);\r\n\t\t\t\t(0.1/ud.abs).wait;\r\n\t\t\t})\r\n\t\t}.play;\r\n\t}\r\n\tinitParent{\r\n\t\tsize=range.pads.size;\r\n\t\trange.pads.do{|item,i|\r\n\t\t\titem.parent=LPButton({this.updateState(i)},{onoff=false});\r\n\t\t\titem.parent.parent=this;\r\n\t\t};\r\n\t}\r\n\tinitLED{\r\n\t\tthis.updateLED;\r\n\t}\r\n\tupdateLED{\r\n\t\tvar ledstate,lls;\r\n\t\tvar green=true;\r\n\t\tledstate=state*size;\r\n\t\trange.pads.do{|item,i|\r\n\t\t\tif(ledstate>((size-1)-i),{\r\n\t\t\t\tlls=ledstate-((size-1)-i);\r\n\t\t\t\tledstate=ledstate-lls;\r\n\t\t\t\tif(green,\r\n\t\t\t\t\t{item.led=LPLED.green(lls*3)},\r\n\t\t\t\t\t{item.led=LPLED.red(lls*3)}\r\n\t\t\t\t);\r\n\t\t\t},{\r\n\t\t\t\titem.led=LPLED.black;\r\n\t\t\t})\r\n\t\t}\r\n\t}\r\n}\r\n\r\nLPSwitchArray : LPWidget{\r\n\tvar <>functions;\r\n\tvar <>onleds;\r\n\tvar <>ofleds;\r\n\tvar <state;\r\n\t*new{|functions,onleds,ofleds,range,onfront,onhide|\r\n\t\t^super.new(range,onfront,onhide).sainit(functions,onleds,ofleds);\r\n\t}\r\n\tsainit{|f,onl,ofl|\r\n\t\t//[f,onl,ofl].postln;\r\n\t\tfunctions=f;\r\n\t\tonleds=onl;\r\n\t\tofleds=ofl;\r\n\t\tif(functions.size!=onl.size,{^MethodError(\"function array size unequal onled array size\",this).throw});\r\n\t\tif(functions.size!=ofl.size,{^MethodError(\"function array size unequal offled array size\",this).throw});\r\n\t\tif(onl.size!=ofl.size,{^MethodError(\"onleds array size unequal offled array size\",this).throw});\r\n\t}\r\n\tinitParent{\r\n\t\t//size=range.pads.size;\r\n\t\trange.pads.do{|item,i|\r\n\t\t\titem.parent=LPButton({this.updateState(i)});\r\n\t\t\titem.parent.parent=this;\r\n\t\t};\r\n\t}\r\n\tinitLED{\r\n\t\trange.pads.do{|item,i|\r\n\t\t\tif(i==state,{\r\n\t\t\t\titem.led=onleds[i];\r\n\t\t\t},{\r\n\t\t\t\titem.led=ofleds[i];\r\n\t\t\t})\r\n\t\t}\r\n\t}\r\n\texecuteState{\r\n\t\tif(state.notNil,{functions[state].value(state,this)});\r\n\t}\r\n\tupdateState{|i|\r\n\t\tthis.state=i;\r\n\t\tthis.executeState;\r\n\t}\r\n\tstate_{|x|\r\n\t\trange.pads.asArray.at(state?0).led=ofleds[state?0];\r\n\t\tstate=x;\r\n\t\trange.pads.asArray.at(state).led=onleds[state];\r\n\t}\r\n}",
   "is_private" : null,
   "id" : "1-4Sy",
   "labels" : [
      "midi",
      "midicontroller",
      "interface"
   ],
   "description" : "This are classes i wrote to use the Novation Launchpad in a GUI like manner ... because i never programmed a GUI before, they might be a little bit esoteric. use examples will follow ...",
   "ancestor_list" : [],
   "name" : "Launchpad",
   "author" : "olafhochherz"
}
