/* A basic pd-pure pattern sequencing example. This Pure script generates the sequences played by the seqdemo.pd patch. */ using math; /* Simple (monophonic) musical patterns with aleatoric elements represented as streams. */ rand m::int = int (uint random/0x100000000*(m+1)); rand (n::int,m::int) = rand (m-n) + n; /* Choose an element at random. */ choose xs = (xs!rand (#xs-1)); /* Concatenate a recursive pattern to a flat sequence. */ mkseq [] = []; mkseq (x:xs) = catmap mkseq (x:xs); mkseq x = [x] otherwise; /* Sample patterns. pat1 is shamelessly pilfered from the SuperCollider documentation, pat2 is a finite section of pat1, and pat3 is a simple random C minor arpeggio. */ pat1 = [[24, 31, 36, 43, 48, 55, [[60, choose [63, 65], 67, choose [70, 72, 74]] | i = 1..rand (2,5)], [choose [74, 75, 77, 79, 81] | i = 1..rand (3,8)]] | i = 1..inf]; pat2 = [[24, 31, 36, 43, 48, 55, [[60, choose [63, 65], 67, choose [70, 72, 74]] | i = 1..rand (2,5)], [choose [74, 75, 77, 79, 81] | i = 1..rand (3,8)]] | i = 1..rand (2,5)]; pat3 = [[60,60,choose [63,67]] | i = 1..inf]; /* The sequencer object. */ nonfix bang reset; // we respond to these nonfix stop note pan wet; // we generate these sequencer = process with /* Process events. Respond to the messages 'bang' (produce the next stream member), 'reset' (rewind the stream to the beginning), numbers (change the note duration a.k.a. delta time value) and a pattern (to switch patterns on the fly). Last but not least we also send back a 'stop' message when the stream ends (of course this will only happen if the sequence is finite). */ process x::double = () when put dur x end; process pat@(_:_) = () when pat = mkseq pat; put time 0; put ctr 0; put seq pat; put seq0 pat; end; process reset = () when put seq (get seq0); put time 0; end; process bang = case get seq of n:seq1 = event n when put seq seq1; put time (get dur); end; _ = stop; end; process _ = stop; /* Turn a stream member (a note number in this case) into a sequence of events (a.k.a. Pd messages). The sample event function below illustrates how to carry around some state (a running counter in this case) in order to implement some dynamic effects, and how to do random pitch, velocity and onset variations on the fly. Also note that here we return an entire "bundle" (i.e., list) of Pd messages for each pattern element. */ event n = {// play a note on voice #2: t 2 note n 1 d, // vary the pan and wet controls of voice #2 in a periodic // fashion to simulate a sound source walking around in // circles: t 2 pan (0.4+0.3*u), t 2 wet (0.35+0.1*w), // play the same note, delayed by a small amount of time, // transposed down an octave and slightly detuned, // alternating between voice #1 and voice #3: (t+dt) (2*k+1) note (n-12+dn) v d} when i = getctr ctr; k = i mod 2; x = i mod 100/100*2*pi; u = cos x; w = sin x; t = get time; d = get dur; dt = rand (0,10); dn = rand (-20,20)/1000; v = rand (90,120)/100; end; getctr c = k when k = get c; put c (k+1) end; end when // initialize dur = ref 500; time = ref 0; ctr = ref 0; pat = mkseq pat1; seq = ref pat; seq0 = ref pat; end;