«simple timeline for patterns» by 56228375
on 30 Apr'20 00:20 insimple timeline for scheduling start and stop of patterns at specific beats (and an experimental extension with absolute time scheduling)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
// // Did you ever wonder how to easily schedule starting/stopping patterns at specific times // as part of building up and evolving a piece from a smaller building blocks? // Here's a simple approach. // // It can be kept very basic because it specifies start and stop in beats, // and not in absolute time. This means that the TempoClock used for playing the pattern // will influence the timeline. // // Nevertheless, it can already be useful. // // // Manual: // // schedule pattern to start on beat a and run until beat b with: // // ptl.beat(a, b, pattern) // // schedule pattern to start on beat a, and stop after producing N events with: // // ptl.number(a, N, pattern) // // finally, after configuring your timeline, it's time to play it. Do: // // ptl.asPattern.play // // don't pay attention to the stupid patterns in the example below, they are just // for demoing the timeline // ( s.waitForBoot({ var ptl = ( \internallist : [], \beat : { | self, start_beat, stop_beat, pattern | self[\internallist] = self[\internallist].add(Ptpar([start_beat, Pfindur(stop_beat - start_beat, pattern)])); }, \number : { | self, start_beat, no_of_events, pattern | self[\internallist] = self[\internallist].add(Ptpar([start_beat, Pfin(no_of_events, pattern)])); }, \asPattern : { |self| Ppar(self[\internallist]); } ); ~bpm = 60; // at 60 beats per minute, one beat takes one second ~tc = TempoClock(~bpm/60); // now schedule patterns in any order ptl.beat(0, 10, // first pattern to run from beat 0 to beat 10 Pbind(\instrument, \default, \midinote, Pseq([65], inf).trace, \amp, 0.8, \dur, 1)); ptl.beat(5.7, 7.3, // second pattern to run from beat 5.7 to beat 7.3 Pbind(\instrument, \default, \midinote, Pseq([70], inf).trace, \amp, 0.8, \dur, 0.1)); ptl.beat(3, 10, // fourth pattern to run from beat 3 and produce 10 notes Pbind(\instrument, \default, \midinote, Pseq([53], inf).trace, \amp, 0.8, \dur, 0.3)); // don't start multiple instances of the same timeline simultaneously if (~player.notNil) { ~player.stop; }; ~player = ptl.asPattern.play(~tc); }); ) // here's an experimental (not very well tested) extension of the system that also supports // scheduling using absolute time moments (start/stop time independent of tempoclock) // // note that the patterns scheduled with absolute time still obey the tempoclock // // extra calls are // // ptl.abstime(abs_start_time, abs_duration, pattern) // // ptl.abstimenumber(abs_start_time, number, pattern) // // other changes: // // asPattern call is removed and timeline self-manages its players // ptl is now equipped with a "start" and "end" api call to start/end playing ( s.waitForBoot({ var ptl = ( \internalcounter : 0, \internalnewcounter : { | self | var cnt = self[\internalcounter]; self[\internalcounter] = self[\internalcounter] + 1; cnt; }, \internallist : [], \abssched : [], \internalplayers : (), \beat : { | self, start_beat, stop_beat, pattern | self[\internallist] = self[\internallist].add(Ptpar([start_beat, Pfindur(stop_beat - start_beat, pattern)])); }, \abstime : { | self, delta_time, duration, pattern | self[\abssched] = self[\abssched].add((\dt: delta_time, \dur: duration, \p : pattern, \type : \time)); }, \number : { | self, start_beat, no_of_events, pattern | self[\internallist] = self[\internallist].add(Ptpar([start_beat, Pfin(no_of_events, pattern)])); }, \abstimenumber : { | self, delta_time, no_of_events, pattern | self[\abssched] = self[\abssched].add((\dt: delta_time, \dur: no_of_events, \p : pattern, \type : \number)); }, \start : { |self, tempoclock | if (tempoclock.isNil) { tempoclock = TempoClock.default; }; self[\abssched].do({ |el| var cnt = self.internalnewcounter; var type = el.type; if (type == \time) { SystemClock.sched(el.dt, { self[\internalplayers][cnt.asSymbol] = el.p.play(tempoclock); nil}); SystemClock.sched(el.dt + el.dur, { self[\internalplayers][cnt.asSymbol].stop; nil}); } { SystemClock.sched(el.dt, { self[\internalplayers][cnt.asSymbol] = Pfin(el.dur, el.p).play(tempoclock); nil}); }; }); self[\internalplayers][self.internalnewcounter.asSymbol] = Ppar(self[\internallist]).play(tempoclock); }, \end : { | self | self[\internalplayers].keysValuesDo({ | key, value | value.stop; }); self[\internalplayers] = (); }; ); ~bpm = 120; // at 60 beats per minute, one beat takes one second ~tc = TempoClock(~bpm/60); // now schedule patterns in any order ptl.beat(0, 10, // first pattern to run from beat 0 to beat 10 Pbind(\instrument, \default, \midinote, Pseq([65], inf).trace, \amp, 0.8, \dur, 1)); ptl.beat(5.7, 7.3, // second pattern to run from beat 5.7 to beat 7.3 Pbind(\instrument, \default, \midinote, Pseq([70], inf).trace, \amp, 0.8, \dur, 0.1)); ptl.abstimenumber(2, 10, Pbind(\instrument, \default, \midinote, Pseq([90], inf).trace, \amp, 0.8, \dur, 1)); ptl.beat(3, 10, // fourth pattern to run from beat 3 and produce 10 notes Pbind(\instrument, \default, \midinote, Pseq([53], inf).trace, \amp, 0.8, \dur, 0.3)); ptl.start(~tc); }); )
reception
in the mean time, this has been converted to a quark https://github.com/shimpe/sc-timeline with demo video here: https://www.youtube.com/watch?v=imToXbOqAl4