2 var listPat, indexPat, repeats;
3 *new { arg listPat, indexPat, repeats=1;
4 ^super.newCopyArgs(listPat, indexPat, repeats)
6 storeArgs { ^[listPat,indexPat,repeats] }
7 embedInStream { arg inval;
8 var indexStream, index, item, itemCount;
9 var listStream = listPat.asStream;
10 repeats.value(inval).do {
11 var list = listStream.next(inval);
12 if (list.isNil) { ^inval };
13 indexStream = indexPat.asStream;
16 index = indexStream.next(inval);
19 itemCount = itemCount + 1;
20 item = list.wrapAt(index);
21 inval = item.embedInStream(inval);
23 if(itemCount == 0) { ^inval }
29 ListPattern : Pattern {
30 var <>list, <>repeats=1;
32 *new { arg list, repeats=1;
34 ^super.new.list_(list).repeats_(repeats)
36 Error("ListPattern (" ++ this.name ++ ") requires a non-empty collection; received "
37 ++ list ++ ".").throw;
41 ^super.copy.list_(list.copy)
43 storeArgs { ^[ list, repeats ] }
48 *new { arg list, repeats=1, offset=0;
49 ^super.new(list, repeats).offset_(offset)
51 embedInStream { arg inval;
52 var item, offsetValue;
53 offsetValue = offset.value(inval);
54 if (inval.eventAt('reverse') == true, {
55 repeats.value(inval).do({ arg j;
56 list.size.reverseDo({ arg i;
57 item = list.wrapAt(i + offsetValue);
58 inval = item.embedInStream(inval);
62 repeats.value(inval).do({ arg j;
64 item = list.wrapAt(i + offsetValue);
65 inval = item.embedInStream(inval);
71 storeArgs { ^[ list, repeats, offset ] }
75 embedInStream { arg inval;
77 var offsetValue = offset.value(inval);
78 if (inval.eventAt('reverse') == true, {
79 repeats.value(inval).reverseDo({ arg i;
80 item = list.wrapAt(i + offsetValue);
81 inval = item.embedInStream(inval);
84 repeats.value(inval).do({ arg i;
85 item = list.wrapAt(i + offsetValue);
86 inval = item.embedInStream(inval);
94 embedInStream { arg inval;
96 var localList = list.copy.scramble;
98 repeats.value(inval).do({ arg j;
99 localList.size.do({ arg i;
100 item = localList.wrapAt(i);
101 inval = item.embedInStream(inval);
108 Prand : ListPattern {
109 embedInStream { arg inval;
112 repeats.value(inval).do({ arg i;
113 item = list.at(list.size.rand);
114 inval = item.embedInStream(inval);
120 Pxrand : ListPattern {
121 embedInStream { arg inval;
123 var index = list.size.rand;
124 repeats.value(inval).do({ arg i;
126 index = (index + (size - 1).rand + 1) % size;
127 item = list.at(index);
128 inval = item.embedInStream(inval);
134 Pwrand : ListPattern {
136 *new { arg list, weights, repeats=1;
137 ^super.new(list, repeats).weights_(weights)
139 embedInStream { arg inval;
141 var wStr = weights.asStream;
142 repeats.value(inval).do({ arg i;
143 wVal = wStr.next(inval);
144 if(wVal.isNil) { ^inval };
145 item = list.at(wVal.windex);
146 inval = item.embedInStream(inval);
150 storeArgs { ^[ list, weights, repeats ] }
155 embedInStream { arg inval;
157 var maxState = ((list.size - 1) div: 2) - 1;
158 repeats.value(inval).do({
161 index = list.at(index).choose.clip(0, maxState) * 2 + 2;
162 item = list.at(index - 1);
165 inval = item.embedInStream(inval);
172 Pdfsm : ListPattern {
174 *new { arg list, startState=0, repeats=1;
175 ^super.new( list, repeats ).startState_(startState)
178 embedInStream { arg inval;
179 var currState, sigStream;
180 var sig, state, stream;
181 var numStates = list.size - 1;
182 repeats.value(inval).do({
184 currState = startState;
185 sigStream = list[0].asStream;
188 sig = sigStream.next(inval);
189 state = list[currState + 1];
190 if( sig.isNil, { false }, {
191 if( state.includesKey(sig), {
192 #currState, stream = state[sig];
194 #currState, stream = state[\default];
196 currState.notNil and: {currState < numStates};
199 inval = stream.embedInStream(inval);
207 var <>list, <>which=0;
208 *new { arg list, which=0;
209 ^super.new.list_(list).which_(which)
211 embedInStream { arg inval;
214 var indexStream = which.asStream;
216 (index = indexStream.next(inval)).notNil;
218 inval = list.wrapAt(index.asInteger).embedInStream(inval);
222 storeArgs { ^[ list, which ] }
226 embedInStream { arg inval;
227 var cleanup = EventStreamCleanup.new;
229 var streamList = list.collect({ arg pattern; pattern.asStream; });
230 var indexStream = which.asStream;
233 if ((index = indexStream.next(inval)).isNil) { ^cleanup.exit(inval) };
234 outval = streamList.wrapAt(index.asInteger).next(inval);
235 if (outval.isNil) { ^cleanup.exit(inval) };
236 cleanup.update(outval);
237 inval = outval.yield;
242 Ptuple : ListPattern {
243 embedInStream { arg inval;
244 var item, streams, tuple, outval;
246 repeats.value(inval).do({ arg j;
248 streams = list.collect({ arg item; item.asStream });
251 tuple = Array.new(streams.size);
252 streams.do({ arg stream;
253 outval = stream.next(inval);
254 if (outval.isNil, { sawNil = true; });
259 inval = yield(tuple);
267 embedInStream { arg inval;
269 var offsetValue = offset.value(inval);
271 if (inval.eventAt('reverse') == true, {
272 repeats.value(inval).do({ arg j;
273 list.size.reverseDo({ arg i;
274 item = list.wrapAt(i + offsetValue);
275 if (item.isSequenceableCollection, {
276 item = item.wrapAt(j);
278 inval = item.embedInStream(inval);
282 repeats.value(inval).do({ arg j;
283 list.size.do({ arg i;
284 item = list.wrapAt(i + offsetValue);
285 if (item.isSequenceableCollection, {
286 item = item.wrapAt(j);
288 inval = item.embedInStream(inval);
296 // similar to Place, but the list is an array of Patterns or Streams
298 embedInStream { |inval|
299 var consecutiveNils = 0, index, repeat, item;
300 var streamList = list.collect({ |item| item.asStream });
301 var offsetValue = offset.value(inval);
302 var localRepeats = repeats.value(inval);
305 while { (repeat < localRepeats) and: { consecutiveNils < list.size } } {
306 if(inval.eventAt(\reverse) == true) {
307 item = streamList.wrapAt(offsetValue - index - 1);
309 item = streamList.wrapAt(offsetValue + index);
311 if((item = item.next(inval)).notNil) {
313 inval = item.embedInStream(inval);
315 consecutiveNils = consecutiveNils + 1;
317 if((index = index + 1) == list.size) {
326 Pslide : ListPattern {
327 // 'repeats' is the number of segments.
328 // 'len' is the length of each segment.
329 // 'step' is how far to step the start of each segment from previous.
330 // 'start' is what index to start at.
331 // indexing wraps around if goes past beginning or end.
332 // step can be negative.
334 var <>len, <>step, <>start, <>wrapAtEnd;
335 *new { arg list, repeats = 1, len = 3, step = 1, start = 0, wrapAtEnd = true;
336 ^super.new(list, repeats).len_(len).step_(step).start_(start)
337 .wrapAtEnd_(wrapAtEnd);
339 embedInStream { arg inval;
342 var stepStr = step.asStream, stepVal;
343 var lengthStr = len.asStream, lengthVal;
345 repeats.value(inval).do {
346 lengthVal = lengthStr.next(inval);
347 if(lengthVal.isNil) { ^inval };
350 item = list.wrapAt(pos + j);
351 inval = item.embedInStream(inval);
356 item = list.at(pos + j);
358 inval = item.embedInStream(inval);
364 stepVal = stepStr.next(inval);
365 if(stepVal.isNil) { ^inval };
373 Pwalk : ListPattern {
374 // random walk pattern - hjh - jamshark70@gmail.com
376 var <>startPos, // starting index
377 <>stepPattern, // pattern for steps
378 <>directionPattern; // pattern should return a stream of:
379 // 1 to move in direction of stepPattern
380 // -1 to reverse the direction of stepPattern
381 // a new direction will be chosen when the walker
382 // reaches a boundary
384 *new { arg list, stepPattern, directionPattern = 1, startPos = 0;
385 ^super.new(list).startPos_(startPos)
386 .stepPattern_(stepPattern ?? { Prand([-1, 1], inf) })
387 .directionPattern_(directionPattern ? 1);
390 storeArgs { ^[list, stepPattern, directionPattern, startPos] }
393 embedInStream { arg inval;
395 var index = startPos;
396 var stepStream = stepPattern.asStream;
397 var directionStream = directionPattern.asStream;
398 // 1 = use steps as is; -1 = reverse direction
399 var direction = directionStream.next(inval) ? 1; // start with first value
402 // get step, stop when nil
403 (step = stepStream.next(inval)).notNil
405 inval = list[index].embedInStream(inval); // get value/stream out
406 step = step * direction; // apply direction
407 // if next thing will be out of bounds
408 if(((index + step) < 0) or: { (index + step) >= list.size }, {
409 direction = directionStream.next(inval) ? 1; // next direction, or 1
410 step = step.abs * direction.sign; // apply to this step
412 index = (index + step) % list.size;