{
   "ancestor_list" : [],
   "description" : "simple timeline for scheduling start and stop of patterns at specific beats \r\n(and an experimental extension with absolute time scheduling)",
   "name" : "simple timeline for patterns",
   "author" : "56228375",
   "code" : "//\r\n// Did you ever wonder how to easily schedule starting/stopping patterns at specific times \r\n// as part of building up and evolving a piece from a smaller building blocks?\r\n// Here's a simple approach.\r\n//\r\n// It can be kept very basic because it specifies start and stop in beats, \r\n// and not in absolute time. This means that the TempoClock used for playing the pattern\r\n// will influence the timeline.\r\n//\r\n// Nevertheless, it can already be useful.\r\n//\r\n//\r\n// Manual: \r\n//\r\n// schedule pattern to start on beat a and run until beat b with:\r\n//\r\n// ptl.beat(a, b, pattern)\r\n//\r\n// schedule pattern to start on beat a, and stop after producing N events with:\r\n//\r\n// ptl.number(a, N, pattern)\r\n//\r\n// finally, after configuring your timeline, it's time to play it. Do:\r\n//\r\n// ptl.asPattern.play\r\n//\r\n// don't pay attention to the stupid patterns in the example below, they are just \r\n// for demoing the timeline\r\n//\r\n\r\n(\r\ns.waitForBoot({\r\n\tvar ptl = (\r\n\t\t\\internallist : [],\r\n\t\t\\beat : {\r\n\t\t\t| self, start_beat, stop_beat, pattern |\r\n\t\t\tself[\\internallist] = self[\\internallist].add(Ptpar([start_beat, Pfindur(stop_beat - start_beat, pattern)]));\r\n\t\t},\r\n\t\t\\number : {\r\n\t\t\t| self, start_beat, no_of_events, pattern |\r\n\t\t\tself[\\internallist] = self[\\internallist].add(Ptpar([start_beat, Pfin(no_of_events, pattern)]));\r\n\t\t},\r\n\t\t\\asPattern : {\r\n\t\t\t|self|\r\n\t\t\tPpar(self[\\internallist]);\r\n\t\t}\r\n\t);\r\n\t\r\n\t~bpm = 60; // at 60 beats per minute, one beat takes one second\r\n\t~tc = TempoClock(~bpm/60);\r\n\t\r\n\t// now schedule patterns in any order\r\n\tptl.beat(0, 10, // first pattern to run from beat 0 to beat 10\r\n\t\tPbind(\\instrument, \\default, \\midinote, Pseq([65], inf).trace, \\amp, 0.8, \\dur, 1));\r\n\tptl.beat(5.7,  7.3, // second pattern to run from beat 5.7 to beat 7.3\r\n\t\tPbind(\\instrument, \\default, \\midinote, Pseq([70], inf).trace, \\amp, 0.8, \\dur, 0.1));\r\n\tptl.beat(3, 10, // fourth pattern to run from beat 3 and produce 10 notes\r\n\t\tPbind(\\instrument, \\default, \\midinote, Pseq([53], inf).trace, \\amp, 0.8, \\dur, 0.3));\r\n\t\r\n\t// don't start multiple instances of the same timeline simultaneously\r\n\tif (~player.notNil) {\r\n\t\t~player.stop;\r\n\t};\r\n\t~player = ptl.asPattern.play(~tc);\r\n});\r\n)\r\n\r\n\r\n// here's an experimental (not very well tested) extension of the system that also supports\r\n// scheduling using absolute time moments (start/stop time independent of tempoclock)\r\n// \r\n// note that the patterns scheduled with absolute time still obey the tempoclock\r\n//\r\n// extra calls are\r\n//\r\n// ptl.abstime(abs_start_time, abs_duration, pattern)\r\n// \r\n// ptl.abstimenumber(abs_start_time, number, pattern)\r\n//\r\n// other changes:\r\n//\r\n// asPattern call is removed and timeline self-manages its players\r\n// ptl is now equipped with a \"start\" and \"end\" api call to start/end playing\r\n\r\n(\r\ns.waitForBoot({\r\n\tvar ptl = (\r\n\t\t\\internalcounter : 0,\r\n\t\t\\internalnewcounter : {\r\n\t\t\t| self |\r\n\t\t\tvar cnt = self[\\internalcounter];\r\n\t\t\tself[\\internalcounter] = self[\\internalcounter] + 1;\r\n\t\t\tcnt;\r\n\t\t},\r\n\t\t\\internallist : [],\r\n\t\t\\abssched : [],\r\n\t\t\\internalplayers : (),\r\n\t\t\\beat : {\r\n\t\t\t| self, start_beat, stop_beat, pattern |\r\n\t\t\tself[\\internallist] = self[\\internallist].add(Ptpar([start_beat, Pfindur(stop_beat - start_beat, pattern)]));\r\n\t\t},\r\n\t\t\\abstime : {\r\n\t\t\t| self, delta_time, duration, pattern |\r\n\t\t\tself[\\abssched] = self[\\abssched].add((\\dt: delta_time, \\dur: duration, \\p : pattern, \\type : \\time));\r\n\t\t},\r\n\t\t\\number : {\r\n\t\t\t| self, start_beat, no_of_events, pattern |\r\n\t\t\tself[\\internallist] = self[\\internallist].add(Ptpar([start_beat, Pfin(no_of_events, pattern)]));\r\n\t\t},\r\n\t\t\\abstimenumber : {\r\n\t\t\t| self, delta_time, no_of_events, pattern |\r\n\t\t\tself[\\abssched] = self[\\abssched].add((\\dt: delta_time, \\dur: no_of_events, \\p : pattern, \\type : \\number));\r\n\t\t},\r\n\t\t\\start : {\r\n\t\t\t|self, tempoclock |\r\n\t\t\tif (tempoclock.isNil) {\r\n\t\t\t\ttempoclock = TempoClock.default;\r\n\t\t\t};\r\n\t\t\tself[\\abssched].do({\r\n\t\t\t\t|el|\r\n\t\t\t\tvar cnt = self.internalnewcounter;\r\n\t\t\t\tvar type = el.type;\r\n\t\t\t\tif (type == \\time) {\r\n\t\t\t\t\tSystemClock.sched(el.dt, { self[\\internalplayers][cnt.asSymbol] = el.p.play(tempoclock); nil});\r\n\t\t\t\t\tSystemClock.sched(el.dt + el.dur, { self[\\internalplayers][cnt.asSymbol].stop; nil});\r\n\t\t\t\t} {\r\n\t\t\t\t\tSystemClock.sched(el.dt, { self[\\internalplayers][cnt.asSymbol] = Pfin(el.dur, el.p).play(tempoclock); nil});\r\n\t\t\t\t};\r\n\t\t\t});\r\n\t\t\tself[\\internalplayers][self.internalnewcounter.asSymbol] = Ppar(self[\\internallist]).play(tempoclock);\r\n\t\t},\r\n\t\t\\end : {\r\n\t\t\t| self |\r\n\t\t\tself[\\internalplayers].keysValuesDo({\r\n\t\t\t\t| key, value |\r\n\t\t\t\tvalue.stop;\r\n\t\t\t});\r\n\t\t\tself[\\internalplayers] = ();\r\n\t\t};\r\n\t);\r\n\t\r\n\t~bpm = 120; // at 60 beats per minute, one beat takes one second\r\n\t~tc = TempoClock(~bpm/60);\r\n\t\r\n\t// now schedule patterns in any order\r\n\tptl.beat(0, 10, // first pattern to run from beat 0 to beat 10\r\n\t\tPbind(\\instrument, \\default, \\midinote, Pseq([65], inf).trace, \\amp, 0.8, \\dur, 1));\r\n\tptl.beat(5.7,  7.3, // second pattern to run from beat 5.7 to beat 7.3\r\n\t\tPbind(\\instrument, \\default, \\midinote, Pseq([70], inf).trace, \\amp, 0.8, \\dur, 0.1));\r\n\tptl.abstimenumber(2, 10,\r\n\t\tPbind(\\instrument, \\default, \\midinote, Pseq([90], inf).trace, \\amp, 0.8, \\dur, 1));\r\n\tptl.beat(3, 10, // fourth pattern to run from beat 3 and produce 10 notes\r\n\t\tPbind(\\instrument, \\default, \\midinote, Pseq([53], inf).trace, \\amp, 0.8, \\dur, 0.3));\r\n\t\r\n\tptl.start(~tc);\r\n});\r\n)",
   "id" : "1-5df",
   "is_private" : null,
   "labels" : [
      "pattern",
      "beat",
      "timeline"
   ]
}
