1 2/* A basic pd-pure pattern sequencing example. This Pure script generates the 3 sequences played by the seqdemo.pd patch. */ 4 5using math; 6 7/* Simple (monophonic) musical patterns with aleatoric elements represented as 8 streams. */ 9 10rand m::int = int (uint random/0x100000000*(m+1)); 11rand (n::int,m::int) 12 = rand (m-n) + n; 13 14/* Choose an element at random. */ 15 16choose xs = (xs!rand (#xs-1)); 17 18/* Concatenate a recursive pattern to a flat sequence. */ 19 20mkseq [] = []; 21mkseq (x:xs) = catmap mkseq (x:xs); 22mkseq x = [x] otherwise; 23 24/* Sample patterns. pat1 is shamelessly pilfered from the SuperCollider 25 documentation, pat2 is a finite section of pat1, and pat3 is a simple 26 random C minor arpeggio. */ 27 28pat1 = [[24, 31, 36, 43, 48, 55, 29 [[60, choose [63, 65], 67, choose [70, 72, 74]] | 30 i = 1..rand (2,5)], 31 [choose [74, 75, 77, 79, 81] | 32 i = 1..rand (3,8)]] | 33 i = 1..inf]; 34 35pat2 = [[24, 31, 36, 43, 48, 55, 36 [[60, choose [63, 65], 67, choose [70, 72, 74]] | 37 i = 1..rand (2,5)], 38 [choose [74, 75, 77, 79, 81] | 39 i = 1..rand (3,8)]] | 40 i = 1..rand (2,5)]; 41 42pat3 = [[60,60,choose [63,67]] | i = 1..inf]; 43 44/* The sequencer object. */ 45 46nonfix bang reset; // we respond to these 47nonfix stop note pan wet; // we generate these 48 49sequencer = process 50 51with 52 53 /* Process events. Respond to the messages 'bang' (produce the next stream 54 member), 'reset' (rewind the stream to the beginning), numbers (change 55 the note duration a.k.a. delta time value) and a pattern (to switch 56 patterns on the fly). Last but not least we also send back a 'stop' 57 message when the stream ends (of course this will only happen if the 58 sequence is finite). */ 59 60 process x::double 61 = () when put dur x end; 62 process pat@(_:_) 63 = () 64 when pat = mkseq pat; 65 put time 0; put ctr 0; 66 put seq pat; put seq0 pat; 67 end; 68 process reset = () when put seq (get seq0); put time 0; end; 69 process bang = case get seq of 70 n:seq1 = event n when 71 put seq seq1; put time (get dur); 72 end; 73 _ = stop; 74 end; 75 process _ = stop; 76 77 /* Turn a stream member (a note number in this case) into a sequence of 78 events (a.k.a. Pd messages). The sample event function below illustrates 79 how to carry around some state (a running counter in this case) in order 80 to implement some dynamic effects, and how to do random pitch, velocity 81 and onset variations on the fly. Also note that here we return an entire 82 "bundle" (i.e., list) of Pd messages for each pattern element. */ 83 84 event n = {// play a note on voice #2: 85 t 2 note n 1 d, 86 // vary the pan and wet controls of voice #2 in a periodic 87 // fashion to simulate a sound source walking around in 88 // circles: 89 t 2 pan (0.4+0.3*u), 90 t 2 wet (0.35+0.1*w), 91 // play the same note, delayed by a small amount of time, 92 // transposed down an octave and slightly detuned, 93 // alternating between voice #1 and voice #3: 94 (t+dt) (2*k+1) note (n-12+dn) v d} 95 when i = getctr ctr; k = i mod 2; 96 x = i mod 100/100*2*pi; u = cos x; w = sin x; 97 t = get time; d = get dur; dt = rand (0,10); 98 dn = rand (-20,20)/1000; 99 v = rand (90,120)/100; 100 end; 101 getctr c = k when k = get c; put c (k+1) end; 102 103end 104 105when 106 // initialize 107 dur = ref 500; time = ref 0; ctr = ref 0; 108 pat = mkseq pat1; 109 seq = ref pat; seq0 = ref pat; 110end; 111