deprecate SCViewHolder-layRight
[supercollider.git] / SCClassLibrary / Common / Streams / ListPatterns.sc
blob178777e6dd9ae1868cbb61310efaf6d075958320
1 Pindex : Pattern {
2         var listPat, indexPat, repeats;
3         *new { arg listPat, indexPat, repeats=1;
4                 ^super.newCopyArgs(listPat, indexPat, repeats)
5         }
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;
14                         itemCount = 0;
15                         while {
16                                 index = indexStream.next(inval);
17                                 index.notNil
18                         }{
19                                 itemCount = itemCount + 1;
20                                 item = list.wrapAt(index);
21                                 inval = item.embedInStream(inval);
22                         };
23                         if(itemCount == 0) { ^inval }
24                 };
25                 ^inval;
26         }
29 ListPattern : Pattern {
30         var <>list, <>repeats=1;
32         *new { arg list, repeats=1;
33                 if (list.size > 0) {
34                         ^super.new.list_(list).repeats_(repeats)
35                 }{
36                         Error("ListPattern (" ++ this.name ++ ") requires a non-empty collection; received "
37                                 ++ list ++ ".").throw;
38                 }
39         }
40         copy {
41                 ^super.copy.list_(list.copy)
42         }
43         storeArgs { ^[ list, repeats ] }
46 Pseq : ListPattern {
47         var <>offset;
48         *new { arg list, repeats=1, offset=0;
49                 ^super.new(list, repeats).offset_(offset)
50         }
51         embedInStream {  arg inval;
52                 var item, offsetValue;
53                 offsetValue = offset.value;
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);
59                                 });
60                         });
61                 },{
62                         repeats.value(inval).do({ arg j;
63                                 list.size.do({ arg i;
64                                         item = list.wrapAt(i + offsetValue);
65                                         inval = item.embedInStream(inval);
66                                 });
67                         });
68                 });
69                 ^inval;
70         }
71         storeArgs { ^[ list, repeats, offset ] }
74 Pser : Pseq {
75         embedInStream { arg inval;
76                 var item;
77                 var offsetValue = offset.value;
78                 if (inval.eventAt('reverse') == true, {
79                         repeats.value(inval).reverseDo({ arg i;
80                                 item = list.wrapAt(i + offsetValue);
81                                 inval = item.embedInStream(inval);
82                         });
83                 },{
84                         repeats.value(inval).do({ arg i;
85                                 item = list.wrapAt(i + offsetValue);
86                                 inval = item.embedInStream(inval);
87                         });
88                 });
89                 ^inval;
90         }
93 Pshuf : ListPattern {
94         embedInStream { arg inval;
95                 var item, stream;
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);
102                         });
103                 });
104                 ^inval;
105         }
108 Prand : ListPattern {
109         embedInStream { arg inval;
110                 var item;
112                 repeats.value(inval).do({ arg i;
113                         item = list.at(list.size.rand);
114                         inval = item.embedInStream(inval);
115                 });
116                 ^inval;
117         }
120 Pxrand : ListPattern {
121         embedInStream { arg inval;
122                 var item, size;
123                 var index = list.size.rand;
124                 repeats.value(inval).do({ arg i;
125                         size = list.size;
126                         index = (index + (size - 1).rand + 1) % size;
127                         item = list.at(index);
128                         inval = item.embedInStream(inval);
129                 });
130                 ^inval;
131         }
134 Pwrand : ListPattern {
135         var <>weights;
136         *new { arg list, weights, repeats=1;
137                 ^super.new(list, repeats).weights_(weights)
138         }
139         embedInStream {  arg inval;
140                 var item, wVal;
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);
147                 });
148                 ^inval
149         }
150         storeArgs { ^[ list, weights, repeats ] }
154 Pfsm : ListPattern {
155         embedInStream {  arg inval;
156                 var item, index=0;
157                 var maxState = ((list.size - 1) div: 2) - 1;
158                 repeats.value(inval).do({
159                         index = 0;
160                         while({
161                                 index = list.at(index).choose.clip(0, maxState) * 2 + 2;
162                                 item = list.at(index - 1);
163                                 item.notNil
164                         },{
165                                 inval = item.embedInStream(inval);
166                         });
167                 });
168                 ^inval;
169         }
172 Pdfsm : ListPattern {
173         var <>startState;
174         *new { arg list, startState=0, repeats=1;
175                 ^super.new( list, repeats ).startState_(startState)
176         }
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;
187                         while({
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];
193                                         }, {
194                                                 #currState, stream = state[\default];
195                                         });
196                                         currState.notNil and: {currState < numStates};
197                                 })
198                         }, {
199                                 inval = stream.embedInStream(inval);
200                         })
201                 });
202                 ^inval;
203         }
206 Pswitch : Pattern {
207         var <>list, <>which=0;
208         *new { arg list, which=0;
209                 ^super.new.list_(list).which_(which)
210         }
211         embedInStream {  arg inval;
212                 var item, index;
214                 var indexStream = which.asStream;
215                 while ({
216                         (index = indexStream.next(inval)).notNil;
217                 },{
218                         inval = list.wrapAt(index.asInteger).embedInStream(inval);
219                 });
220                 ^inval;
221         }
222         storeArgs { ^[ list, which ]  }
225 Pswitch1 : Pswitch {
226         embedInStream { arg inval;
227                 var index, outval;
228                 var streamList = list.collect({ arg pattern; pattern.asStream; });
229                 var indexStream = which.asStream;
231                 loop {
232                         if ((index = indexStream.next(inval)).isNil) { ^inval };
233                         outval = streamList.wrapAt(index.asInteger).next(inval);
234                         if (outval.isNil) { ^inval };
235                         inval = outval.yield;
236                 };
237         }
240 Ptuple : ListPattern {
241         embedInStream {  arg inval;
242                 var item, streams, tuple, outval;
244                 repeats.value(inval).do({ arg j;
245                         var sawNil = false;
246                         streams = list.collect({ arg item; item.asStream });
248                         while ({
249                                 tuple = Array.new(streams.size);
250                                 streams.do({ arg stream;
251                                         outval = stream.next(inval);
252                                         if (outval.isNil, { sawNil = true; });
253                                         tuple.add(outval);
254                                 });
255                                 sawNil.not
256                         },{
257                                 inval = yield(tuple);
258                         });
259                 });
260                 ^inval;
261         }
264 Place : Pseq {
265         embedInStream {  arg inval;
266                 var item;
267                 var offsetValue = offset.value;
269                 if (inval.eventAt('reverse') == true, {
270                         repeats.value(inval).do({ arg j;
271                                 list.size.reverseDo({ arg i;
272                                         item = list.wrapAt(i + offsetValue);
273                                         if (item.isSequenceableCollection, {
274                                                 item = item.wrapAt(j);
275                                         });
276                                         inval = item.embedInStream(inval);
277                                 });
278                         });
279                 },{
280                         repeats.value(inval).do({ arg j;
281                                 list.size.do({ arg i;
282                                         item = list.wrapAt(i + offsetValue);
283                                         if (item.isSequenceableCollection, {
284                                                 item = item.wrapAt(j);
285                                         });
286                                         inval = item.embedInStream(inval);
287                                 });
288                         });
289                 });
290                 ^inval;
291         }
294 // similar to Place, but the list is an array of Patterns or Streams
295 Ppatlace : Pseq {
296         embedInStream { |inval|
297                 var     consecutiveNils = 0, index, repeat, item;
298                 var streamList = list.collect({ |item| item.asStream });
299                 var offsetValue = offset.value;
300                 var localRepeats = repeats.value(inval);
302                 index = repeat = 0;
303                 while { (repeat < localRepeats) and: { consecutiveNils < list.size } } {
304                         if(inval.eventAt(\reverse) == true) {
305                                 item = streamList.wrapAt(offsetValue - index - 1);
306                         } {
307                                 item = streamList.wrapAt(offsetValue + index);
308                         };
309                         if((item = item.next(inval)).notNil) {
310                                 consecutiveNils = 0;
311                                 inval = item.embedInStream(inval);
312                         } {
313                                 consecutiveNils = consecutiveNils + 1;
314                         };
315                         if((index = index + 1) == list.size) {
316                                 index = 0;
317                                 repeat = repeat + 1;
318                         };
319                 };
320                 ^inval;
321         }
324 Pslide : ListPattern {
325     // 'repeats' is the number of segments.
326     // 'len' is the length of each segment.
327     // 'step' is how far to step the start of each segment from previous.
328     // 'start' is what index to start at.
329     // indexing wraps around if goes past beginning or end.
330     // step can be negative.
332     var <>len, <>step, <>start, <>wrapAtEnd;
333     *new { arg list, repeats = 1, len = 3, step = 1, start = 0, wrapAtEnd = true;
334         ^super.new(list, repeats).len_(len).step_(step).start_(start)
335                         .wrapAtEnd_(wrapAtEnd);
336     }
337     embedInStream { arg inval;
338         var item;
339         var pos = start;
340         var stepStr = step.asStream, stepVal;
341         var lengthStr = len.asStream, lengthVal;
343                 repeats.value(inval).do {
344                         lengthVal = lengthStr.next(inval);
345                         if(lengthVal.isNil) { ^inval };
346                         if(wrapAtEnd) {
347                                 lengthVal.do { |j|
348                                         item = list.wrapAt(pos + j);
349                                         inval = item.embedInStream(inval);
350                                 }
352                         } {
353                                 lengthVal.do { |j|
354                                         item = list.at(pos + j);
355                                         if(item.notNil) {
356                                                 inval = item.embedInStream(inval);
357                                         } {
358                                                 ^inval
359                                         };
360                                 }
361                         };
362                 stepVal = stepStr.next(inval);
363                 if(stepVal.isNil) { ^inval };
364                 pos = pos + stepVal;
365                 };
367              ^inval;
368     }
371 Pwalk : ListPattern {
372                 // random walk pattern - hjh - jamshark70@gmail.com
374         var     <>startPos,     // starting index
375                 <>stepPattern,  // pattern for steps
376                 <>directionPattern;     // pattern should return a stream of:
377                                                         // 1 to move in direction of stepPattern
378                                                         // -1 to reverse the direction of stepPattern
379                                                         // a new direction will be chosen when the walker
380                                                         // reaches a boundary
382         *new { arg list, stepPattern, directionPattern = 1, startPos = 0;
383                 ^super.new(list).startPos_(startPos)
384                         .stepPattern_(stepPattern ?? { Prand([-1, 1], inf) })
385                         .directionPattern_(directionPattern ? 1);
386         }
388         storeArgs { ^[list, stepPattern, directionPattern, startPos] }
391         embedInStream { arg inval;
392                 var     step;
393                 var index = startPos;
394                 var stepStream = stepPattern.asStream;
395                 var directionStream = directionPattern.asStream;
396                 // 1 = use steps as is; -1 = reverse direction
397                 var direction = directionStream.next(inval) ? 1;                // start with first value
399                 while({
400                         // get step, stop when nil
401                         (step = stepStream.next(inval)).notNil
402                 },{
403                         inval = list[index].embedInStream(inval);  // get value/stream out
404                         step = step * direction;        // apply direction
405                                 // if next thing will be out of bounds
406                         if(((index + step) < 0) or: { (index + step) >= list.size }, {
407                                 direction = directionStream.next(inval) ? 1;  // next direction, or 1
408                                 step = step.abs * direction.sign;  // apply to this step
409                         });
410                         index = (index + step) % list.size;
411                 });
413                 ^inval;
414         }