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