1 SequenceableCollection : Collection {
3 |@| { arg index; ^this.clipAt(index) }
4 @@ { arg index; ^this.wrapAt(index) }
5 @|@ { arg index; ^this.foldAt(index) }
7 // fill with ramp of values
8 *series { arg size, start=0, step=1;
9 var obj = this.new(size);
11 obj.add(start + (step * i));
16 // fill with geometric series
17 *geom { arg size, start, grow;
19 var obj = this.new(size);
27 // fill with fibonacci series
28 *fib { arg size, a=0.0, b=1.0;
30 var obj = this.new(size);
40 *rand { arg size, minVal, maxVal;
42 var obj = this.new(size);
44 obj.add(rrand(minVal, maxVal));
49 *exprand { arg size, minVal, maxVal;
51 var obj = this.new(size);
53 obj.add(exprand(minVal, maxVal));
58 *rand2 { arg size, val;
60 var obj = this.new(size);
67 *linrand { arg size, minVal, maxVal;
69 var range = maxVal - minVal;
70 var obj = this.new(size);
72 obj.add(minVal + range.linrand);
78 // fill with interpolation of values between start and end
79 *interpolation { arg size, start=0.0, end=1.0;
80 var obj = this.new(size), step;
81 if(size == 1) { ^obj.add(start) };
82 step = (end - start) / (size - 1);
84 obj.add(start + (i * step));
90 ++ { arg aSequenceableCollection;
91 var newlist = this.species.new(this.size + aSequenceableCollection.size);
92 newlist = newlist.addAll(this).addAll(aSequenceableCollection);
95 +++ { arg aSequenceableCollection;
96 aSequenceableCollection = aSequenceableCollection.asSequenceableCollection;
97 ^this.collect {|item, i|
98 item.asSequenceableCollection ++ aSequenceableCollection.wrapAt(i)
101 asSequenceableCollection { ^this }
103 // select an element at random
105 ^this.at(this.size.rand)
107 // select an element at random using an array of weights
108 wchoose { arg weights;
109 ^this.at(weights.windex)
113 if (aCollection.class != this.class) { ^false };
114 if (this.size != aCollection.size) { ^false };
115 this.do { | item, i |
116 if (item != aCollection[i]) { ^false };
121 copyRange { arg start, end;
124 newColl = this.species.new(end - start);
126 newColl.add(this.at(i));
134 ^this.copyRange(0, n-1)
137 ^this.copyRange(size+n, size-1)
141 var size = this.size;
143 ^this.copyRange(n, size-1)
145 ^this.copyRange(0, size+n-1)
148 copyToEnd { arg start;
149 ^this.copyRange(start, this.size - 1)
151 copyFromStart { arg end;
152 ^this.copyRange(0, end)
156 this.do({ arg elem, i;
157 if ( item === elem, { ^i })
162 indexOfEqual { arg item, offset=0;
163 (this.size - offset).do ({ arg i;
165 if ( item == this[i], { ^i })
170 indicesOfEqual { |item|
172 this.do { arg val, i;
173 if (item == val) { indices = indices.add(i) }
179 find { |sublist, offset=0|
180 var subSize_1 = sublist.size - 1, first = sublist.first, index;
181 (this.size - offset).do { |i|
183 if (this[index] == first) {
184 if (this.copyRange(index, index + subSize_1) == sublist) { ^index }
190 findAll { arg arr, offset=0;
193 i = this.find(arr, offset);
196 indices = indices.add(i);
202 indexOfGreaterThan { arg val;
203 ^this.detectIndex { |item| item > val };
206 indexIn { arg val; // collection is sorted, returns closest index
208 var j = this.indexOfGreaterThan(val);
209 if(j.isNil) { ^this.size - 1 };
212 ^if((val - this[i]) < (this[j] - val)) { i } { j }
215 indexInBetween { arg val; // collection is sorted, returns linearly interpolated index
217 if(this.isEmpty) { ^nil };
218 i = this.indexOfGreaterThan(val);
219 if(i.isNil) { ^this.size - 1 };
221 a = this[i-1]; b = this[i];
224 ^((val - a) / div) + i - 1
227 resamp0 { arg newSize;
228 var factor = this.size - 1 / (newSize - 1);
229 ^this.species.fill(newSize, { |i| this.at((i * factor).round(1.0).asInteger) })
232 resamp1 { arg newSize;
233 var factor = this.size - 1 / (newSize - 1);
234 ^this.species.fill(newSize, { |i| this.blendAt(i * factor) })
238 var index = this.indexOf(item);
239 ^if ( index.notNil, {
240 this.removeAt(index);
246 var coll = this.copy;
251 var index = this.indexOf(item);
252 ^if ( index.notNil, {
260 lastIndex { ^if(this.size > 0) { this.size - 1 } { nil } }
261 middleIndex { ^if(this.size > 0) { (this.size - 1) div: 2 } { nil } }
263 first { if (this.size > 0, { ^this.at(0) }, { ^nil }) }
264 last { if (this.size > 0, { ^this.at(this.size - 1) }, { ^nil }) }
265 middle { if (this.size > 0, { ^this.at((this.size - 1) div: 2) }, { ^nil }) }
268 putFirst { arg obj; if (this.size > 0, { ^this.put(0, obj) }) }
269 putLast { arg obj; if (this.size > 0, { ^this.put(this.size - 1, obj) }) }
272 // compatibility with isolated objects
274 obtain { arg index, default; ^this[index] ? default }
276 instill { arg index, item, default;
277 var res = if (index >= this.size) {
278 this.extend(index + 1, default)
282 ^res.put(index, item)
286 pairsDo { arg function;
287 forBy(0, this.size-2, 2) {|i|
288 function.value(this[i], this[i+1], i);
291 keysValuesDo { arg function;
292 ^this.pairsDo(function)
295 doAdjacentPairs { arg function;
296 (this.size - 1).do({ arg i;
297 function.value(this.at(i), this.at(i+1), i);
300 separate { arg function = true;
301 var list = Array.new;
302 var sublist = this.species.new;
303 this.doAdjacentPairs({ arg a, b, i;
304 sublist = sublist.add(a);
305 if ( function.value(a, b, i), {
306 list = list.add(sublist);
307 sublist = this.species.new;
310 if(this.notEmpty) { sublist = sublist.add(this.last) };
311 list = list.add(sublist);
314 delimit { arg function;
317 sublist = this.species.new;
318 this.do({ arg item, i;
319 if ( function.value(item, i), {
320 list = list.add(sublist);
321 sublist = this.species.new;
323 sublist = sublist.add(item);
326 list = list.add(sublist);
329 clump { arg groupSize;
330 var list = Array.new((this.size / groupSize).roundUp.asInteger);
331 var sublist = this.species.new(groupSize);
334 if (sublist.size >= groupSize, {
336 sublist = this.species.new(groupSize);
339 if (sublist.size > 0, { list = list.add(sublist); });
342 clumps { arg groupSizeList;
344 var list = Array.new(groupSizeList.size); // still better estimate than default
345 var subSize = groupSizeList.at(0);
346 var sublist = this.species.new(subSize);
348 sublist = sublist.add(item);
349 if (sublist.size >= subSize, {
351 list = list.add(sublist);
352 subSize = groupSizeList.wrapAt(i);
353 sublist = this.species.new(subSize);
356 if (sublist.size > 0, { list = list.add(sublist); });
359 curdle { arg probability;
360 ^this.separate({ probability.coin });
362 flatten { arg numLevels=1;
365 if (numLevels <= 0, { ^this });
366 numLevels = numLevels - 1;
368 list = this.species.new;
370 if (item.respondsTo('flatten'), {
371 list = list.addAll(item.flatten(numLevels));
373 list = list.add(item);
380 ^this.prFlat(this.species.new(this.flatSize))
384 this.do({ arg item, i;
385 if (item.respondsTo('prFlat'), {
386 list = item.prFlat(list);
388 list = list.add(item);
395 var list = this.species.new(this.size); // as we don't know the size, just guess
396 this.do({ arg item, i;
397 if (item.respondsTo('flatIf') and: { func.value(item, i) }, {
398 list = list.addAll(item.flatIf(func));
400 list = list.add(item);
407 var list, size, maxsize;
411 this.do({ arg sublist;
413 sz = if (sublist.isSequenceableCollection, { sublist.size },{ 1 });
414 if (sz > maxsize, { maxsize = sz });
417 list = this.species.fill(maxsize, { this.species.new(size) });
418 this.do({ arg isublist, i;
419 if (isublist.isSequenceableCollection, {
420 list.do({ arg jsublist, j;
421 jsublist.add( isublist.wrapAt(j); );
424 list.do({ arg jsublist, j;
425 jsublist.add( isublist );
432 flopTogether { arg ... moreArrays;
433 var standIn, maxSize = 0, array;
434 array = [this] ++ moreArrays;
437 maxSize = max(maxSize, each.size)
440 standIn = 0.dup(maxSize);
441 array = array.collect { |sublist| sublist.add(standIn) };
442 ^array.collect { |sublist|
443 sublist.flop.collect { |each| each.drop(-1) } // remove stand-in
447 unlace { arg numlists, clumpSize=1, clip=false;
448 var size, list, sublist, self;
450 size = (this.size + numlists - 1) div: numlists;
451 list = this.species.fill(numlists, { this.species.new(size) });
452 self = if(clip) { this.keep(this.size.trunc(clumpSize * numlists).postln)} { this };
453 self.do({ arg item, i;
454 sublist = list.at(i div: clumpSize % numlists);
462 list = this.class.new(this.size);
471 list = this.class.new(this.size);
473 list.add( item - prev );
478 // complement to Integer:asDigits
479 convertDigits { arg base=10;
480 var lastIndex = this.lastIndex;
482 if(x >= base) { Error("digit too large for base").throw };
483 base ** (lastIndex - i) * x
487 hammingDistance { |that|
488 // if this is shorter than that, size difference should be included
489 // (if this is longer, the do loop will take care of it)
490 var count = (that.size - this.size).max(0);
492 if(elem != that[i]) { count = count + 1 };
498 degreeToKey { arg scale, stepsPerOctave=12;
499 ^this.collect({ arg scaleDegree;
500 scaleDegree.degreeToKey(scale, stepsPerOctave);
503 keyToDegree { arg scale, stepsPerOctave=12;
504 ^this.collect { arg val; val.keyToDegree(scale, stepsPerOctave) }
507 nearestInScale { arg scale, stepsPerOctave=12; // collection is sorted
509 root = this.trunc(stepsPerOctave);
510 key = this % stepsPerOctave;
511 ^key.nearestInList(scale) + root
513 nearestInList { arg list; // collection is sorted
514 ^this.collect({ arg item; list.at(list.indexIn(item)) })
517 transposeKey { arg amount, octave=12;
518 ^((this + amount) % octave).sort
520 mode { arg degree, octave=12;
521 ^(rotate(this, degree.neg) - this.wrapAt(degree)) % octave
524 performDegreeToKey { arg scaleDegree, stepsPerOctave = 12, accidental = 0;
525 var baseKey = (stepsPerOctave * (scaleDegree div: this.size)) + this.wrapAt(scaleDegree);
526 ^if(accidental == 0) { baseKey } { baseKey + (accidental * (stepsPerOctave / 12.0)) }
529 performKeyToDegree { | degree, stepsPerOctave = 12 |
530 var n = degree div: stepsPerOctave * this.size;
531 var key = degree % stepsPerOctave;
532 ^this.indexInBetween(key) + n
535 performNearestInList { | degree |
536 ^this.at(this.indexIn(degree))
539 performNearestInScale { arg degree, stepsPerOctave=12; // collection is sorted
540 var root = degree.trunc(stepsPerOctave);
541 var key = degree % stepsPerOctave;
542 ^key.nearestInList(this) + root
545 // supports a variation of Mikael Laurson's rhythm list RTM-notation.
549 tie = this.convertOneRhythm(list);
550 if (tie > 0.0, { list.add(tie) }); // check for tie at end of rhythm
556 sum = sum + abs(if (beats.isSequenceableCollection) {
564 convertOneRhythm { arg list, tie = 0.0, stretch = 1.0;
565 var beats, divisions, repeats;
566 #beats, divisions, repeats = this;
567 repeats = repeats ? 1;
568 stretch = stretch * beats / divisions.sumRhythmDivisions;
571 if (val.isSequenceableCollection) {
572 tie = val.convertOneRhythm(list, tie, stretch)
587 isSequenceableCollection { ^true }
588 containsSeqColl { ^this.any(_.isSequenceableCollection) }
591 neg { ^this.performUnaryOp('neg') }
592 bitNot { ^this.performUnaryOp('bitNot') }
593 abs { ^this.performUnaryOp('abs') }
594 ceil { ^this.performUnaryOp('ceil') }
595 floor { ^this.performUnaryOp('floor') }
596 frac { ^this.performUnaryOp('frac') }
597 sign { ^this.performUnaryOp('sign') }
598 squared { ^this.performUnaryOp('squared') }
599 cubed { ^this.performUnaryOp('cubed') }
600 sqrt { ^this.performUnaryOp('sqrt') }
601 exp { ^this.performUnaryOp('exp') }
602 reciprocal { ^this.performUnaryOp('reciprocal') }
603 midicps { ^this.performUnaryOp('midicps') }
604 cpsmidi { ^this.performUnaryOp('cpsmidi') }
605 midiratio { ^this.performUnaryOp('midiratio') }
606 ratiomidi { ^this.performUnaryOp('ratiomidi') }
607 ampdb { ^this.performUnaryOp('ampdb') }
608 dbamp { ^this.performUnaryOp('dbamp') }
609 octcps { ^this.performUnaryOp('octcps') }
610 cpsoct { ^this.performUnaryOp('cpsoct') }
611 log { ^this.performUnaryOp('log') }
612 log2 { ^this.performUnaryOp('log2') }
613 log10 { ^this.performUnaryOp('log10') }
614 sin { ^this.performUnaryOp('sin') }
615 cos { ^this.performUnaryOp('cos') }
616 tan { ^this.performUnaryOp('tan') }
617 asin { ^this.performUnaryOp('asin') }
618 acos { ^this.performUnaryOp('acos') }
619 atan { ^this.performUnaryOp('atan') }
620 sinh { ^this.performUnaryOp('sinh') }
621 cosh { ^this.performUnaryOp('cosh') }
622 tanh { ^this.performUnaryOp('tanh') }
623 rand { ^this.performUnaryOp('rand') }
624 rand2 { ^this.performUnaryOp('rand2') }
625 linrand { ^this.performUnaryOp('linrand') }
626 bilinrand { ^this.performUnaryOp('bilinrand') }
627 sum3rand { ^this.performUnaryOp('sum3rand') }
629 distort { ^this.performUnaryOp('distort') }
630 softclip { ^this.performUnaryOp('softclip') }
631 coin { ^this.performUnaryOp('coin') }
632 even { ^this.performUnaryOp('even') }
633 odd { ^this.performUnaryOp('odd') }
634 isPositive { ^this.performUnaryOp('isPositive') }
635 isNegative { ^this.performUnaryOp('isNegative') }
636 isStrictlyPositive { ^this.performUnaryOp('isStrictlyPositive') }
638 rectWindow { ^this.performUnaryOp('rectWindow') }
639 hanWindow { ^this.performUnaryOp('hanWindow') }
640 welWindow { ^this.performUnaryOp('welWindow') }
641 triWindow { ^this.performUnaryOp('triWindow') }
643 scurve { ^this.performUnaryOp('scurve') }
644 ramp { ^this.performUnaryOp('ramp') }
646 asFloat { ^this.performUnaryOp('asFloat') }
647 asInteger { ^this.performUnaryOp('asInteger') }
649 nthPrime { ^this.performUnaryOp('nthPrime') }
650 prevPrime { ^this.performUnaryOp('prevPrime') }
651 nextPrime { ^this.performUnaryOp('nextPrime') }
652 indexOfPrime { ^this.performUnaryOp('indexOfPrime') }
654 real { ^this.performUnaryOp('real') }
655 imag { ^this.performUnaryOp('imag') }
657 magnitude { ^this.performUnaryOp('magnitude') }
658 magnitudeApx { ^this.performUnaryOp('magnitudeApx') }
659 phase { ^this.performUnaryOp('phase') }
660 angle { ^this.performUnaryOp('angle') }
662 rho { ^this.performUnaryOp('rho') }
663 theta { ^this.performUnaryOp('theta') }
665 degrad { ^this.performUnaryOp('degrad') }
666 raddeg { ^this.performUnaryOp('raddeg') }
669 + { arg aNumber, adverb; ^this.performBinaryOp('+', aNumber, adverb) }
670 - { arg aNumber, adverb; ^this.performBinaryOp('-', aNumber, adverb) }
671 * { arg aNumber, adverb; ^this.performBinaryOp('*', aNumber, adverb) }
672 / { arg aNumber, adverb; ^this.performBinaryOp('/', aNumber, adverb) }
673 div { arg aNumber, adverb; ^this.performBinaryOp('div', aNumber, adverb) }
674 mod { arg aNumber, adverb; ^this.performBinaryOp('mod', aNumber, adverb) }
675 pow { arg aNumber, adverb; ^this.performBinaryOp('pow', aNumber, adverb) }
676 min { arg aNumber, adverb; ^this.performBinaryOp('min', aNumber, adverb) }
677 max { arg aNumber=0, adverb; ^this.performBinaryOp('max', aNumber, adverb) }
680 < { arg aNumber, adverb; ^this.performBinaryOp('<', aNumber, adverb) }
681 <= { arg aNumber, adverb; ^this.performBinaryOp('<=', aNumber, adverb) }
682 > { arg aNumber, adverb; ^this.performBinaryOp('>', aNumber, adverb) }
683 >= { arg aNumber, adverb; ^this.performBinaryOp('>=', aNumber, adverb) }
685 bitAnd { arg aNumber, adverb; ^this.performBinaryOp('bitAnd', aNumber, adverb) }
686 bitOr { arg aNumber, adverb; ^this.performBinaryOp('bitOr', aNumber, adverb) }
687 bitXor { arg aNumber, adverb; ^this.performBinaryOp('bitXor', aNumber, adverb) }
688 bitHammingDistance { arg aNumber, adverb;
689 ^this.performBinaryOp('hammingDistance', aNumber, adverb)
692 lcm { arg aNumber, adverb; ^this.performBinaryOp('lcm', aNumber, adverb) }
693 gcd { arg aNumber, adverb; ^this.performBinaryOp('gcd', aNumber, adverb) }
694 round { arg aNumber=1, adverb; ^this.performBinaryOp('round', aNumber, adverb) }
695 roundUp { arg aNumber=1, adverb; ^this.performBinaryOp('roundUp', aNumber, adverb) }
696 trunc { arg aNumber=1, adverb; ^this.performBinaryOp('trunc', aNumber, adverb) }
697 atan2 { arg aNumber, adverb; ^this.performBinaryOp('atan2', aNumber, adverb) }
698 hypot { arg aNumber, adverb; ^this.performBinaryOp('hypot', aNumber, adverb) }
699 hypotApx { arg aNumber, adverb; ^this.performBinaryOp('hypotApx', aNumber, adverb) }
700 leftShift { arg aNumber, adverb; ^this.performBinaryOp('leftShift', aNumber, adverb) }
701 rightShift { arg aNumber, adverb; ^this.performBinaryOp('rightShift', aNumber, adverb) }
702 unsignedRightShift { arg aNumber, adverb; ^this.performBinaryOp('unsignedRightShift', aNumber, adverb) }
703 ring1 { arg aNumber, adverb; ^this.performBinaryOp('ring1', aNumber, adverb) }
704 ring2 { arg aNumber, adverb; ^this.performBinaryOp('ring2', aNumber, adverb) }
705 ring3 { arg aNumber, adverb; ^this.performBinaryOp('ring3', aNumber, adverb) }
706 ring4 { arg aNumber, adverb; ^this.performBinaryOp('ring4', aNumber, adverb) }
707 difsqr { arg aNumber, adverb; ^this.performBinaryOp('difsqr', aNumber, adverb) }
708 sumsqr { arg aNumber, adverb; ^this.performBinaryOp('sumsqr', aNumber, adverb) }
709 sqrsum { arg aNumber, adverb; ^this.performBinaryOp('sqrsum', aNumber, adverb) }
710 sqrdif { arg aNumber, adverb; ^this.performBinaryOp('sqrdif', aNumber, adverb) }
711 absdif { arg aNumber, adverb; ^this.performBinaryOp('absdif', aNumber, adverb) }
712 thresh { arg aNumber, adverb; ^this.performBinaryOp('thresh', aNumber, adverb) }
713 amclip { arg aNumber, adverb; ^this.performBinaryOp('amclip', aNumber, adverb) }
714 scaleneg { arg aNumber, adverb; ^this.performBinaryOp('scaleneg', aNumber, adverb) }
715 clip2 { arg aNumber=1, adverb; ^this.performBinaryOp('clip2', aNumber, adverb) }
716 fold2 { arg aNumber, adverb; ^this.performBinaryOp('fold2', aNumber, adverb) }
717 wrap2 { arg aNumber, adverb; ^this.performBinaryOp('wrap2', aNumber, adverb) }
718 excess { arg aNumber, adverb; ^this.performBinaryOp('excess', aNumber, adverb) }
719 firstArg { arg aNumber, adverb; ^this.performBinaryOp('firstArg', aNumber, adverb) }
720 rrand { arg aNumber, adverb; ^this.performBinaryOp('rrand', aNumber, adverb) }
721 exprand { arg aNumber, adverb; ^this.performBinaryOp('exprand', aNumber, adverb) }
723 // math op dispatch support
724 performUnaryOp { arg aSelector;
725 ^this.collect({ arg item; item.perform(aSelector) });
728 performBinaryOp { arg aSelector, theOperand, adverb;
729 ^theOperand.performBinaryOpOnSeqColl(aSelector, this, adverb);
731 performBinaryOpOnSeqColl { arg aSelector, theOperand, adverb;
734 size = this.size max: theOperand.size;
735 newList = this.species.new(size);
737 newList.add(theOperand.wrapAt(i).perform(aSelector, this.wrapAt(i)));
741 if (adverb.isInteger) {
743 size = this.size max: theOperand.size;
744 newList = this.species.new(size);
746 newList.add(theOperand.wrapAt(i).perform(aSelector, this.wrapAt(i)));
751 ^theOperand.collect {|item, i| item.perform(aSelector, this, adverb-1) }
753 ^this.collect {|item, i| theOperand.perform(aSelector, item, adverb+1) }
759 // newList = this.species.new(size);
761 // newList.add(theOperand.perform(aSelector, this.at(i)));
764 size = theOperand.size;
765 newList = this.species.new(size);
767 newList.add(theOperand.at(i).perform(aSelector, this));
773 // newList = this.species.new(size);
775 // newList.add(theOperand.perform(aSelector, this.at(i)));
778 size = theOperand.size * this.size;
779 newList = this.species.new(size);
780 theOperand.do({ arg a;
782 newList.add(a.perform(aSelector, b));
788 size = this.size min: theOperand.size;
789 newList = this.species.new(size);
791 newList.add(theOperand.wrapAt(i).perform(aSelector, this.wrapAt(i)));
796 size = this.size max: theOperand.size;
797 newList = this.species.new(size);
799 newList.add(theOperand.foldAt(i).perform(aSelector, this.foldAt(i)));
803 error("unrecognized adverb: '" ++ adverb ++ "' for operator '" ++ aSelector ++ "'\n");
806 performBinaryOpOnSimpleNumber { arg aSelector, aNumber, adverb;
807 ^this.collect({ arg item;
808 aNumber.perform(aSelector, item, adverb)
811 performBinaryOpOnComplex { arg aSelector, aComplex, adverb;
812 ^this.collect({ arg item;
813 aComplex.perform(aSelector, item, adverb)
817 asFraction { arg denominator=100, fasterBetter=true;
818 ^this.collect { |item| item.asFraction(denominator, fasterBetter) }
821 asPoint { ^Point(this[0] ? 0, this[1] ? 0) }
822 asRect { ^Rect(this[0] ? 0, this[1] ? 0, this[2] ? 0, this[3] ? 0) }
823 ascii { ^this.collect { arg item; item.ascii } }
826 // support UGen rate access
830 if(this.size == 1, { ^this.first.rate });
831 ^this.collect({ arg item; item.rate }).minItem;
832 // 'scalar' > 'control' > 'audio'
835 // if we don't catch the special case of an empty array,
836 // Object:multiChannelPerform goes into infinite recursion
837 multiChannelPerform { arg selector ... args;
839 ^super.multiChannelPerform(selector, *args);
845 // support some UGen convenience methods.
846 // NOTE: don't forget to add a wrapper here when adding a method to UGen or AbstractFunction
847 clip { arg ... args; ^this.multiChannelPerform('clip', *args) }
848 wrap { arg ... args; ^this.multiChannelPerform('wrap', *args) }
849 fold { arg ... args; ^this.multiChannelPerform('fold', *args) }
850 linlin { arg ... args; ^this.multiChannelPerform('linlin', *args) }
851 linexp { arg ... args; ^this.multiChannelPerform('linexp', *args) }
852 explin { arg ... args; ^this.multiChannelPerform('explin', *args) }
853 expexp { arg ... args; ^this.multiChannelPerform('expexp', *args) }
854 lincurve { arg ... args; ^this.multiChannelPerform('lincurve', *args) }
855 curvelin { arg ... args; ^this.multiChannelPerform('curvelin', *args) }
856 range { arg ... args; ^this.multiChannelPerform('range', *args) }
857 exprange { arg ... args; ^this.multiChannelPerform('exprange', *args) }
858 unipolar { arg ... args; ^this.multiChannelPerform('unipolar', *args) }
859 bipolar { arg ... args; ^this.multiChannelPerform('bipolar', *args) }
860 lag { arg ... args; ^this.multiChannelPerform('lag', *args) }
861 lag2 { arg ... args; ^this.multiChannelPerform('lag2', *args) }
862 lag3 { arg ... args; ^this.multiChannelPerform('lag3', *args) }
863 lagud { arg ... args; ^this.multiChannelPerform('lagud', *args) }
864 lag2ud { arg ... args; ^this.multiChannelPerform('lag2ud', *args) }
865 lag3ud { arg ... args; ^this.multiChannelPerform('lag3ud', *args) }
866 varlag { arg ... args; ^this.multiChannelPerform('varlag', *args) }
867 blend { arg ... args; ^this.multiChannelPerform('blend', *args) }
868 checkBadValues { arg ... args; ^this.multiChannelPerform('checkBadValues', *args) }
869 prune { arg ... args; ^this.multiChannelPerform('prune', *args) }
871 minNyquist { ^min(this, SampleRate.ir * 0.5) }
875 if (function.isNil) { function = { arg a, b; a <= b }; };
876 ^this.mergeSort(function)
879 ^this.sort({| a, b | a[key] <= b[key] })
881 sortMap { arg function;
882 ^this.sort({| a, b | function.value(a) <= function.value(b) })
889 index = this.middleIndex;
890 ^(this[index] + this[index+1]) / 2;
893 median { arg function;
894 //^this.sort(function).sortedMedian
895 // Note the copy, to prevent changing the input.
896 ^this.copy.hoareMedian(function)
899 quickSort { arg function;
900 this.quickSortRange(0, this.size - 1, function)
902 order { arg function;
903 var array, orderFunc;
904 // returns an array of indices that would sort the collection into order.
905 if(this.isEmpty) { ^[] };
906 if (function.isNil) { function = { arg a, b; a <= b }; };
907 array = [this, (0..this.lastIndex)].flop;
908 orderFunc = {|a,b| function.value(a[0], b[0]) };
909 ^array.mergeSort(orderFunc).flop[1]
919 quickSortRange { arg i, j, function;
920 //Sort elements i through j of this to be nondescending according to
922 var di, dij, dj, tt, ij, k, l, n;
924 // The prefix d means the data at that index.
925 if ((n = j + 1 - i) <= 1, { ^this }); // Nothing to sort.
930 if (function.value(di, dj).not, { // i.e., should di precede dj?
936 if ( n > 2, { // More than two elements.
937 ij = (i + j) div: 2; // ij is the midpoint of i and j.
938 dij = this.at(ij); // Sort di,dij,dj. Make dij be their median.
939 if (function.value(di, dij), { // i.e. should di precede dij?
940 if (function.value(dij, dj).not, { // i.e., should dij precede dj?
944 },{ // i.e. di should come after dij"
948 if ( n > 3, { // More than three elements.
949 // Find k>i and l<j such that dk,dij,dl are in reverse order.
950 // Swap k and l. Repeat this procedure until k and l pass each other.
956 k <= l and: { function.value(dij, this.at(l)) }
957 }); // i.e. while dl succeeds dij
960 k <= l and: { function.value(this.at(k), dij) };
961 }); // i.e. while dij succeeds dk
966 // Now l<k (either 1 or 2 less), and di through dl are all less than or equal to dk
967 // through dj. Sort those two segments.
968 this.quickSortRange(i, l, function);
969 this.quickSortRange(k, j, function);
976 mergeSort { arg function;
978 tempArray = this.class.newClear(this.size);
979 this.mergeSortTemp(function, tempArray, 0, this.size - 1);
982 mergeSortTemp { arg function, tempArray, left, right;
986 if (size <= 0) { ^this };
987 if (size <= 8) { ^this.insertionSortRange(function, left, right) };
989 mid = (right + left) >> 1;
990 this.mergeSortTemp(function, tempArray, left, mid);
991 this.mergeSortTemp(function, tempArray, mid+1, right);
992 this.mergeTemp(function, tempArray, left, mid+1, right);
995 mergeTemp { arg function, tempArray, left, mid, right;
996 var i, leftEnd, size, tempPos;
999 size = right - left + 1;
1000 while { (left <= leftEnd) && (mid <= right) }
1002 if (function.value( this[left], this[mid] ))
1004 tempArray[tempPos] = this[left];
1005 tempPos = tempPos + 1;
1009 tempArray[tempPos] = this[mid];
1010 tempPos = tempPos + 1;
1014 while { left <= leftEnd }
1016 tempArray[tempPos] = this[left];
1017 tempPos = tempPos + 1;
1020 while { mid <= right }
1022 tempArray[tempPos] = this[mid];
1023 tempPos = tempPos + 1;
1027 this[right] = tempArray[right];
1032 insertionSort { arg function;
1033 ^this.insertionSortRange(function, 0, this.size - 1)
1035 insertionSortRange { arg function, left, right;
1038 while { i <= right }
1042 while { (j > left) && { function.value(this[j-1], test).not } }
1044 this[j] = this[j-1];
1053 // Finds the median efficiently, by rearranging the array IN-PLACE.
1054 hoareMedian { |function|
1055 if(this.isEmpty) { ^nil };
1056 ^if(this.size.even, {
1057 [this.hoareFind(this.size/ 2 - 1, function),
1058 this.hoareFind(this.size/ 2, function)].mean;
1060 this.hoareFind(this.size - 1 / 2, function);
1064 // Finds the kth element in the array, according to a given sorting function.
1065 // This is typically fast (order is O(n) rather than O(n log n)) because it
1066 // doesn't attempt to completely sort the array. Method is due to C. A. F. Hoare.
1067 // Note: this rearranges array elements IN PLACE.
1068 hoareFind { |k, function, left, right|
1071 if (function.isNil) { function = { | a, b | a < b } };
1074 j = right ?? {this.size-1};
1078 # l, r = this.hoarePartition(i,j,p, function);
1080 // kth smallest is in right split
1084 // kth smallest is in left split
1088 // The desired element is in desired position
1092 // In-place partitioning method used by hoareFind.
1093 // Note: for efficiency this doesn't check that function is defined, so you
1094 // must supply a function! See hoareFind for example
1095 hoarePartition { |l0, r0, p, function|
1103 while { (l < this.size) and: { function.value(this[l], p) } }{
1107 while { (r >= 0) and: { function.value(p, this[r]) } }{
1110 // check and exchange
1126 *streamContents { arg function;
1128 stream = CollStream.on(this.new(100));
1129 function.value(stream);
1132 *streamContentsLimit { arg function, limit=2000;
1134 stream = LimitedWriteStream.on(this.new(100 min: limit));
1135 stream.limit_(limit).limitFunc_({ ^stream.contents });
1136 function.value(stream);
1141 index = index % this.size;
1144 wrapPut { arg index, value;
1145 index = index % this.size;
1146 ^this.put(index, value)
1148 reduce { arg operator;
1149 var once = true, result;
1150 if(this.size==1){ ^this[0] };
1151 this.doAdjacentPairs {|a, b|
1154 result = operator.applyTo(a, b);
1156 result = operator.applyTo(result, b);
1162 ^String.streamContents { arg stream;
1165 this.do { arg item; stream << item };
1167 stop = this.size - 1;
1168 this.do { arg item,i;
1170 if(i < stop) { stream << joiner };
1177 // TempoClock play quantization
1178 nextTimeOnGrid { arg clock;
1179 ^clock.nextTimeOnGrid(*this);
1182 // we break up the array so that missing elements are set to nil in the Quant
1183 asQuant { ^Quant(*this) }
1185 // asUGenInput { ^this.asArray.asUGenInput }
1187 schedBundleArrayOnClock { |clock, bundleArray, lag = 0, server, latency|
1188 latency = latency ? server.latency;
1193 SystemClock.sched(lag.wrapAt(i), {
1194 server.sendBundle(latency, bundleArray.wrapAt(i)) })
1200 server.sendBundle(latency, bundleArray.wrapAt(i))