{
   "description" : "",
   "ancestor_list" : [],
   "author" : "David Morgan",
   "name" : "Language based n x n step sequencer",
   "id" : "1-55O",
   "is_private" : null,
   "code" : "/*\r\nLanguage based n x n step sequencer.\r\n\r\nWithout a UI it's easy to create and transform arbitrary matrixes. \r\nYou can also map x/x coordinates to whatever you wish.\r\n*/\r\n\r\n(\r\n// Factory method for creating loopr object\r\n~createLoopr = {arg dur;\r\n\t\r\n\tvar obj = (\r\n\t\t\r\n\t\tgrid: [],\r\n\t\t\r\n\t\tdur: 1,\r\n\t\t\r\n\t\tsetDur: {arg self, dur;\r\n\t\t\tself.dur = dur;\r\n\t\t\tself.seq = self.dur.asStream;\r\n\t\t},\r\n\t\t\r\n\t\tgetDur: {arg self;\r\n\t\t\tself.dur;\r\n\t\t},\r\n\t\t\r\n\t\tseq: 1.asStream,\r\n\t\t\r\n\t\tfunc: {},\r\n\t\t\r\n\t\tplayer: {arg self;\r\n\t\t\t\r\n\t\t\tvar me = self;\r\n\t\t\t\r\n\t\t\tvar pattern = Pspawner({arg sp;\r\n\t\t\t\tinf.do({arg i;\r\n\t\t\t\t\tvar time = me.seq.next;\r\n\t\t\t\t\tvar evt = me.process(i.asInt, time);\r\n\t\t\t\t\tsp.par(evt);\r\n\t\t\t\t\tsp.wait(time);\r\n\t\t\t\t});\r\n\t\t\t});\r\n\t\t\t\r\n\t\t\tEventPatternProxy.new(pattern);\r\n\t\t},\r\n\t\t\r\n\t\tprocess: {arg self, count, time;\r\n\t\t\t\r\n\t\t\tvar me = self;\r\n\t\t\t\r\n\t\t\tPlazy({\r\n\r\n\t\t\t\tvar rows = me.grid;\r\n\t\t\t\tvar evts = rows.collect({arg item, row;\r\n\t\t\t\t\t\r\n\t\t\t\t\tvar val;\r\n\t\t\t\t\tvar event;\r\n\t\t\t\t\tvar x = (count % item.size).asInt;\r\n\t\t\t\t\tval = item.wrapAt(count).value;\r\n\t\t\t\t\t\r\n\t\t\t\t\tevent = (isRest:true);\r\n\t\t\t\t\tif (val > 0) {\r\n\t\t\t\t\t\tvar myEvent = me.func(x, row, val, time, count);\r\n\t\t\t\t\t\tif (myEvent.isKindOf(Event) or: myEvent.isKindOf(Pattern)) {\r\n\t\t\t\t\t\t\tevent = myEvent;\r\n\t\t\t\t\t\t};\r\n\t\t\t\t\t};\r\n\t\t\t\t\t\r\n\t\t\t\t\tPn(event, 1);\r\n\t\t\t\t});\r\n\t\t\t\t\r\n\t\t\t\tPpar(evts);\r\n\t\t\t});\r\n\t\t}\t\r\n\t);\r\n\t\r\n\tobj.setDur(dur);\r\n\tobj;\r\n};\r\n)\r\n\r\n// Create a synth to play\r\n(\r\nSynthDef(\\blip, {arg freq, time = 1, out = 0;\r\n\tvar rel = TRand.kr(0.1,4,1);\r\n\tvar sig = SinOsc.ar(freq*[0.9,0.99,1,1.01,1.1], mul:[0.05,0.2,1,0.2,0.05]).mean;\r\n\tvar env = EnvGen.ar(Env.perc(1e-4,rel,0.75), 1, timeScale:time, doneAction:2);\r\n\tsig = Splay.ar(sig) * env * \\amp.kr(0.1) * AmpCompA.kr(freq);\r\n\tOut.ar(out, sig);\r\n}).add;\r\n)\r\n\r\n// Grid values greater than zero will invoke the func handler in order to do something.\r\n// You can map the x, y coordinates however you wish.\r\n// Plus the value at each point can be used for additional parameterization.\r\n(~grid = [\r\n\t[7 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0],\r\n\t[0 , 6 , 0 , 0 , 0 , 0 , 0 , 0 , 4 , 0 , 0 , 0 , 0 , 0 , 0 , 0],\r\n\t[0 , 0 , 5 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0],\r\n\t[0 , 0 , 0 , 4 , 0 , 0 , 0 , 0 , 5 , 5 , 5 , 5 , 0 , 0 , 0 , 0],\r\n\t[0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 6 , 0 , 0 , 0],\r\n\t[0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 6 , 0 , 0 , 0 , 0 , 7 , 0 , 0],\r\n\t// can handle asymetrical arrays\r\n\t[0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, 5],\r\n\t[6 , {[5,6].choose}, 4 , 0]\r\n]);\r\n\r\n// Create a new instance specifying the initial dur value\r\n~loopr1 = ~createLoopr.value(0.25);\r\n// Set the grid.\r\n~loopr1.grid = ~grid;\r\n\r\n// Set up the handler.\r\n// This is the function that will be called\r\n// for each non zero point in the grid.\r\n// Return an Event or Pattern to be played.\r\n(\r\nvar fx = NodeProxy.new(s, \\audio, 2);\r\nfx[1] = \\filter -> {arg in; GVerb.ar(in, 100); };\r\nfx.play;\r\n\t\r\n~loopr1.func = {arg self, x, y, val, time;\r\n\t\t\r\n\t// the value of each point maps to an octave\r\n\t// time is the event duration, i.e. the dur value\r\n\t(instrument: \\blip,\r\n\t\t\\amp: 0.5,\r\n\t\t\\degree: y,\r\n\t\t\\octave: val,\r\n\t\t\\scale: Scale.ritusen,\r\n\t\t\\time: time,\r\n\t\t\\group: fx.group,\r\n\t\t\\out: fx.bus\r\n\t);\r\n}\r\n);\r\n\r\n//Play the sequencer\r\n~loopr1.player.play(quant:1.0);\r\n\r\n// Apply transformations to the grid\r\n~loopr1.grid = ~grid.reverse;\r\n~loopr1.grid = ~grid.flop;\r\n~loopr1.grid = ~grid.stutter;\r\n~loopr1.grid = ~grid.mirror;\r\n~loopr1.grid = ~grid;\r\n\r\n// You can change the rhythm duration to a pattern\r\n(\r\n~loopr1.setDur( \r\n\tPseg(\r\n\t\tPwhite().linexp(0, 1, 1/32, 1),\r\n\t\tPbrown(0,1,0.05).linexp(0, 1, 1/8, 8),\r\n\t\t\\sin\r\n\t)\r\n)\r\n)\r\n\r\n// Reset\r\n~loopr1.setDur(0.25);",
   "labels" : [
      "sequencer"
   ]
}
