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, adverb;
96 aSequenceableCollection = aSequenceableCollection.asSequenceableCollection;
98 if(adverb == 0) { ^this ++ aSequenceableCollection };
99 if(adverb == 1) { ^this +++ aSequenceableCollection };
100 if(adverb < 0) { ^aSequenceableCollection.perform('+++', this, adverb.neg) };
101 ^this.deepCollect(adverb - 1, { |sublist|
102 sublist.asSequenceableCollection.collect {|item, i|
103 item.asSequenceableCollection ++ aSequenceableCollection.wrapAt(i)
107 ^this.collect {|item, i|
108 item.asSequenceableCollection ++ aSequenceableCollection.wrapAt(i)
111 asSequenceableCollection { ^this }
113 // select an element at random
115 ^this.at(this.size.rand)
117 // select an element at random using an array of weights
118 wchoose { arg weights;
119 ^this.at(weights.windex)
123 if (aCollection.class != this.class) { ^false };
124 if (this.size != aCollection.size) { ^false };
125 this.do { | item, i |
126 if (item != aCollection[i]) { ^false };
132 var hash = this.class.hash;
134 hash = hash << 1 bitXor: item.hash // encode item order by left shifting
139 copyRange { arg start, end;
142 newColl = this.species.new(end - start);
144 newColl.add(this.at(i));
152 ^this.copyRange(0, n-1)
155 ^this.copyRange(size+n, size-1)
159 var size = this.size;
161 ^this.copyRange(n, size-1)
163 ^this.copyRange(0, size+n-1)
166 copyToEnd { arg start;
167 ^this.copyRange(start, this.size - 1)
169 copyFromStart { arg end;
170 ^this.copyRange(0, end)
174 this.do({ arg elem, i;
175 if ( item === elem, { ^i })
180 indexOfEqual { arg item, offset=0;
181 (this.size - offset).do ({ arg i;
183 if ( item == this[i], { ^i })
188 indicesOfEqual { |item|
190 this.do { arg val, i;
191 if (item == val) { indices = indices.add(i) }
197 find { |sublist, offset=0|
198 var subSize_1 = sublist.size - 1, first = sublist.first, index;
199 (this.size - offset).do { |i|
201 if (this[index] == first) {
202 if (this.copyRange(index, index + subSize_1) == sublist) { ^index }
208 findAll { arg arr, offset=0;
211 i = this.find(arr, offset);
214 indices = indices.add(i);
220 indexOfGreaterThan { arg val;
221 ^this.detectIndex { |item| item > val };
224 indexIn { arg val; // collection is sorted, returns closest index
226 var j = this.indexOfGreaterThan(val);
227 if(j.isNil) { ^this.size - 1 };
230 ^if((val - this[i]) < (this[j] - val)) { i } { j }
233 indexInBetween { arg val; // collection is sorted, returns linearly interpolated index
235 if(this.isEmpty) { ^nil };
236 i = this.indexOfGreaterThan(val);
237 if(i.isNil) { ^this.size - 1 };
239 a = this[i-1]; b = this[i];
242 ^((val - a) / div) + i - 1
245 resamp0 { arg newSize;
246 var factor = this.size - 1 / (newSize - 1);
247 ^this.species.fill(newSize, { |i| this.at((i * factor).round(1.0).asInteger) })
250 resamp1 { arg newSize;
251 var factor = this.size - 1 / (newSize - 1);
252 ^this.species.fill(newSize, { |i| this.blendAt(i * factor) })
256 var index = this.indexOf(item);
257 ^if ( index.notNil, {
258 this.removeAt(index);
264 var coll = this.copy;
269 var index = this.indexOf(item);
270 ^if ( index.notNil, {
278 lastIndex { ^if(this.size > 0) { this.size - 1 } { nil } }
279 middleIndex { ^if(this.size > 0) { (this.size - 1) div: 2 } { nil } }
281 first { if (this.size > 0, { ^this.at(0) }, { ^nil }) }
282 last { if (this.size > 0, { ^this.at(this.size - 1) }, { ^nil }) }
283 middle { if (this.size > 0, { ^this.at((this.size - 1) div: 2) }, { ^nil }) }
286 putFirst { arg obj; if (this.size > 0, { ^this.put(0, obj) }) }
287 putLast { arg obj; if (this.size > 0, { ^this.put(this.size - 1, obj) }) }
290 // compatibility with isolated objects
292 obtain { arg index, default; ^this[index] ? default }
294 instill { arg index, item, default;
295 var res = if (index >= this.size) {
296 this.extend(index + 1, default)
300 ^res.put(index, item)
304 pairsDo { arg function;
305 forBy(0, this.size-2, 2) {|i|
306 function.value(this[i], this[i+1], i);
309 keysValuesDo { arg function;
310 ^this.pairsDo(function)
313 doAdjacentPairs { arg function;
314 (this.size - 1).do({ arg i;
315 function.value(this.at(i), this.at(i+1), i);
318 separate { arg function = true;
319 var list = Array.new;
320 var sublist = this.species.new;
321 this.doAdjacentPairs({ arg a, b, i;
322 sublist = sublist.add(a);
323 if ( function.value(a, b, i), {
324 list = list.add(sublist);
325 sublist = this.species.new;
328 if(this.notEmpty) { sublist = sublist.add(this.last) };
329 list = list.add(sublist);
332 delimit { arg function;
335 sublist = this.species.new;
336 this.do({ arg item, i;
337 if ( function.value(item, i), {
338 list = list.add(sublist);
339 sublist = this.species.new;
341 sublist = sublist.add(item);
344 list = list.add(sublist);
347 clump { arg groupSize;
348 var list = Array.new((this.size / groupSize).roundUp.asInteger);
349 var sublist = this.species.new(groupSize);
352 if (sublist.size >= groupSize, {
354 sublist = this.species.new(groupSize);
357 if (sublist.size > 0, { list = list.add(sublist); });
360 clumps { arg groupSizeList;
362 var list = Array.new(groupSizeList.size); // still better estimate than default
363 var subSize = groupSizeList.at(0);
364 var sublist = this.species.new(subSize);
366 sublist = sublist.add(item);
367 if (sublist.size >= subSize, {
369 list = list.add(sublist);
370 subSize = groupSizeList.wrapAt(i);
371 sublist = this.species.new(subSize);
374 if (sublist.size > 0, { list = list.add(sublist); });
377 curdle { arg probability;
378 ^this.separate({ probability.coin });
380 flatten { arg numLevels=1;
383 if (numLevels <= 0, { ^this });
384 numLevels = numLevels - 1;
386 list = this.species.new;
388 if (item.respondsTo('flatten'), {
389 list = list.addAll(item.flatten(numLevels));
391 list = list.add(item);
398 ^this.prFlat(this.species.new(this.flatSize))
402 this.do({ arg item, i;
403 if (item.respondsTo('prFlat'), {
404 list = item.prFlat(list);
406 list = list.add(item);
413 var list = this.species.new(this.size); // as we don't know the size, just guess
414 this.do({ arg item, i;
415 if (item.respondsTo('flatIf') and: { func.value(item, i) }, {
416 list = list.addAll(item.flatIf(func));
418 list = list.add(item);
425 var list, size, maxsize;
429 this.do({ arg sublist;
431 sz = if(sublist.isSequenceableCollection, { sublist.size }, { 1 });
432 if (sz > maxsize, { maxsize = sz });
435 list = this.species.fill(maxsize, { this.species.new(size) });
436 this.do({ arg isublist, i;
437 if(isublist.isSequenceableCollection, {
438 list.do({ arg jsublist, j;
439 jsublist.add( isublist.wrapAt(j) );
442 list.do({ arg jsublist, j;
443 jsublist.add( isublist );
451 var maxsize = this.maxValue { |sublist|
452 if(sublist.isSequenceableCollection) { sublist.size } { 1 }
455 ^this.species.fill(maxsize, { |i|
456 func.value( *this.collect { |sublist|
457 if(sublist.isSequenceableCollection) {
466 flopTogether { arg ... moreArrays;
467 var standIn, maxSize = 0, array;
468 array = [this] ++ moreArrays;
471 maxSize = max(maxSize, each.size)
474 standIn = 0.dup(maxSize);
475 array = array.collect { |sublist| sublist.add(standIn) };
476 ^array.collect { |sublist|
477 sublist.flop.collect { |each| each.drop(-1) } // remove stand-in
483 if(rank.isNil) { rank = this.maxDepth - 1 };
484 if(rank <= 1) { ^this.flop };
487 maxsize = this.maxSizeAtDepth(rank);
488 ^this.species.fill(maxsize, { |i|
489 this.wrapAtDepth(rank, i)
493 wrapAtDepth { arg rank, index;
494 if(rank == 0) { ^this.wrapAt(index) };
495 ^this.collect { |item, i|
496 if(item.isSequenceableCollection) {
497 item.wrapAtDepth(rank - 1, index)
504 unlace { arg numlists, clumpSize=1, clip=false;
505 var size, list, sublist, self;
507 size = (this.size + numlists - 1) div: numlists;
508 list = this.species.fill(numlists, { this.species.new(size) });
509 self = if(clip) { this.keep(this.size.trunc(clumpSize * numlists).postln)} { this };
510 self.do({ arg item, i;
511 sublist = list.at(i div: clumpSize % numlists);
519 list = this.class.new(this.size);
528 list = this.class.new(this.size);
530 list.add( item - prev );
535 // complement to Integer:asDigits
536 convertDigits { arg base=10;
537 var lastIndex = this.lastIndex;
539 if(x >= base) { Error("digit too large for base").throw };
540 base ** (lastIndex - i) * x
544 hammingDistance { |that|
545 // if this is shorter than that, size difference should be included
546 // (if this is longer, the do loop will take care of it)
547 var count = (that.size - this.size).max(0);
549 if(elem != that[i]) { count = count + 1 };
555 degreeToKey { arg scale, stepsPerOctave=12;
556 ^this.collect({ arg scaleDegree;
557 scaleDegree.degreeToKey(scale, stepsPerOctave);
560 keyToDegree { arg scale, stepsPerOctave=12;
561 ^this.collect { arg val; val.keyToDegree(scale, stepsPerOctave) }
564 nearestInScale { arg scale, stepsPerOctave=12; // collection is sorted
566 root = this.trunc(stepsPerOctave);
567 key = this % stepsPerOctave;
568 ^key.nearestInList(scale) + root
570 nearestInList { arg list; // collection is sorted
571 ^this.collect({ arg item; list.at(list.indexIn(item)) })
574 transposeKey { arg amount, octave=12;
575 ^((this + amount) % octave).sort
577 mode { arg degree, octave=12;
578 ^(rotate(this, degree.neg) - this.wrapAt(degree)) % octave
581 performDegreeToKey { arg scaleDegree, stepsPerOctave = 12, accidental = 0;
582 var baseKey = (stepsPerOctave * (scaleDegree div: this.size)) + this.wrapAt(scaleDegree);
583 ^if(accidental == 0) { baseKey } { baseKey + (accidental * (stepsPerOctave / 12.0)) }
586 performKeyToDegree { | degree, stepsPerOctave = 12 |
587 var n = degree div: stepsPerOctave * this.size;
588 var key = degree % stepsPerOctave;
589 ^this.indexInBetween(key) + n
592 performNearestInList { | degree |
593 ^this.at(this.indexIn(degree))
596 performNearestInScale { arg degree, stepsPerOctave=12; // collection is sorted
597 var root = degree.trunc(stepsPerOctave);
598 var key = degree % stepsPerOctave;
599 ^key.nearestInList(this) + root
602 // supports a variation of Mikael Laurson's rhythm list RTM-notation.
606 tie = this.convertOneRhythm(list);
607 if (tie > 0.0, { list.add(tie) }); // check for tie at end of rhythm
613 sum = sum + abs(if (beats.isSequenceableCollection) {
621 convertOneRhythm { arg list, tie = 0.0, stretch = 1.0;
622 var beats, divisions, repeats;
623 #beats, divisions, repeats = this;
624 repeats = repeats ? 1;
625 stretch = stretch * beats / divisions.sumRhythmDivisions;
628 if (val.isSequenceableCollection) {
629 tie = val.convertOneRhythm(list, tie, stretch)
644 isSequenceableCollection { ^true }
645 containsSeqColl { ^this.any(_.isSequenceableCollection) }
648 neg { ^this.performUnaryOp('neg') }
649 bitNot { ^this.performUnaryOp('bitNot') }
650 abs { ^this.performUnaryOp('abs') }
651 ceil { ^this.performUnaryOp('ceil') }
652 floor { ^this.performUnaryOp('floor') }
653 frac { ^this.performUnaryOp('frac') }
654 sign { ^this.performUnaryOp('sign') }
655 squared { ^this.performUnaryOp('squared') }
656 cubed { ^this.performUnaryOp('cubed') }
657 sqrt { ^this.performUnaryOp('sqrt') }
658 exp { ^this.performUnaryOp('exp') }
659 reciprocal { ^this.performUnaryOp('reciprocal') }
660 midicps { ^this.performUnaryOp('midicps') }
661 cpsmidi { ^this.performUnaryOp('cpsmidi') }
662 midiratio { ^this.performUnaryOp('midiratio') }
663 ratiomidi { ^this.performUnaryOp('ratiomidi') }
664 ampdb { ^this.performUnaryOp('ampdb') }
665 dbamp { ^this.performUnaryOp('dbamp') }
666 octcps { ^this.performUnaryOp('octcps') }
667 cpsoct { ^this.performUnaryOp('cpsoct') }
668 log { ^this.performUnaryOp('log') }
669 log2 { ^this.performUnaryOp('log2') }
670 log10 { ^this.performUnaryOp('log10') }
671 sin { ^this.performUnaryOp('sin') }
672 cos { ^this.performUnaryOp('cos') }
673 tan { ^this.performUnaryOp('tan') }
674 asin { ^this.performUnaryOp('asin') }
675 acos { ^this.performUnaryOp('acos') }
676 atan { ^this.performUnaryOp('atan') }
677 sinh { ^this.performUnaryOp('sinh') }
678 cosh { ^this.performUnaryOp('cosh') }
679 tanh { ^this.performUnaryOp('tanh') }
680 rand { ^this.performUnaryOp('rand') }
681 rand2 { ^this.performUnaryOp('rand2') }
682 linrand { ^this.performUnaryOp('linrand') }
683 bilinrand { ^this.performUnaryOp('bilinrand') }
684 sum3rand { ^this.performUnaryOp('sum3rand') }
686 distort { ^this.performUnaryOp('distort') }
687 softclip { ^this.performUnaryOp('softclip') }
688 coin { ^this.performUnaryOp('coin') }
689 even { ^this.performUnaryOp('even') }
690 odd { ^this.performUnaryOp('odd') }
691 isPositive { ^this.performUnaryOp('isPositive') }
692 isNegative { ^this.performUnaryOp('isNegative') }
693 isStrictlyPositive { ^this.performUnaryOp('isStrictlyPositive') }
695 rectWindow { ^this.performUnaryOp('rectWindow') }
696 hanWindow { ^this.performUnaryOp('hanWindow') }
697 welWindow { ^this.performUnaryOp('welWindow') }
698 triWindow { ^this.performUnaryOp('triWindow') }
700 scurve { ^this.performUnaryOp('scurve') }
701 ramp { ^this.performUnaryOp('ramp') }
703 asFloat { ^this.performUnaryOp('asFloat') }
704 asInteger { ^this.performUnaryOp('asInteger') }
706 nthPrime { ^this.performUnaryOp('nthPrime') }
707 prevPrime { ^this.performUnaryOp('prevPrime') }
708 nextPrime { ^this.performUnaryOp('nextPrime') }
709 indexOfPrime { ^this.performUnaryOp('indexOfPrime') }
711 real { ^this.performUnaryOp('real') }
712 imag { ^this.performUnaryOp('imag') }
714 magnitude { ^this.performUnaryOp('magnitude') }
715 magnitudeApx { ^this.performUnaryOp('magnitudeApx') }
716 phase { ^this.performUnaryOp('phase') }
717 angle { ^this.performUnaryOp('angle') }
719 rho { ^this.performUnaryOp('rho') }
720 theta { ^this.performUnaryOp('theta') }
722 degrad { ^this.performUnaryOp('degrad') }
723 raddeg { ^this.performUnaryOp('raddeg') }
726 + { arg aNumber, adverb; ^this.performBinaryOp('+', aNumber, adverb) }
727 - { arg aNumber, adverb; ^this.performBinaryOp('-', aNumber, adverb) }
728 * { arg aNumber, adverb; ^this.performBinaryOp('*', aNumber, adverb) }
729 / { arg aNumber, adverb; ^this.performBinaryOp('/', aNumber, adverb) }
730 div { arg aNumber, adverb; ^this.performBinaryOp('div', aNumber, adverb) }
731 mod { arg aNumber, adverb; ^this.performBinaryOp('mod', aNumber, adverb) }
732 pow { arg aNumber, adverb; ^this.performBinaryOp('pow', aNumber, adverb) }
733 min { arg aNumber, adverb; ^this.performBinaryOp('min', aNumber, adverb) }
734 max { arg aNumber=0, adverb; ^this.performBinaryOp('max', aNumber, adverb) }
737 < { arg aNumber, adverb; ^this.performBinaryOp('<', aNumber, adverb) }
738 <= { arg aNumber, adverb; ^this.performBinaryOp('<=', aNumber, adverb) }
739 > { arg aNumber, adverb; ^this.performBinaryOp('>', aNumber, adverb) }
740 >= { arg aNumber, adverb; ^this.performBinaryOp('>=', aNumber, adverb) }
742 bitAnd { arg aNumber, adverb; ^this.performBinaryOp('bitAnd', aNumber, adverb) }
743 bitOr { arg aNumber, adverb; ^this.performBinaryOp('bitOr', aNumber, adverb) }
744 bitXor { arg aNumber, adverb; ^this.performBinaryOp('bitXor', aNumber, adverb) }
745 bitHammingDistance { arg aNumber, adverb;
746 ^this.performBinaryOp('hammingDistance', aNumber, adverb)
749 lcm { arg aNumber, adverb; ^this.performBinaryOp('lcm', aNumber, adverb) }
750 gcd { arg aNumber, adverb; ^this.performBinaryOp('gcd', aNumber, adverb) }
751 round { arg aNumber=1, adverb; ^this.performBinaryOp('round', aNumber, adverb) }
752 roundUp { arg aNumber=1, adverb; ^this.performBinaryOp('roundUp', aNumber, adverb) }
753 trunc { arg aNumber=1, adverb; ^this.performBinaryOp('trunc', aNumber, adverb) }
754 atan2 { arg aNumber, adverb; ^this.performBinaryOp('atan2', aNumber, adverb) }
755 hypot { arg aNumber, adverb; ^this.performBinaryOp('hypot', aNumber, adverb) }
756 hypotApx { arg aNumber, adverb; ^this.performBinaryOp('hypotApx', aNumber, adverb) }
757 leftShift { arg aNumber, adverb; ^this.performBinaryOp('leftShift', aNumber, adverb) }
758 rightShift { arg aNumber, adverb; ^this.performBinaryOp('rightShift', aNumber, adverb) }
759 unsignedRightShift { arg aNumber, adverb; ^this.performBinaryOp('unsignedRightShift', aNumber, adverb) }
760 ring1 { arg aNumber, adverb; ^this.performBinaryOp('ring1', aNumber, adverb) }
761 ring2 { arg aNumber, adverb; ^this.performBinaryOp('ring2', aNumber, adverb) }
762 ring3 { arg aNumber, adverb; ^this.performBinaryOp('ring3', aNumber, adverb) }
763 ring4 { arg aNumber, adverb; ^this.performBinaryOp('ring4', aNumber, adverb) }
764 difsqr { arg aNumber, adverb; ^this.performBinaryOp('difsqr', aNumber, adverb) }
765 sumsqr { arg aNumber, adverb; ^this.performBinaryOp('sumsqr', aNumber, adverb) }
766 sqrsum { arg aNumber, adverb; ^this.performBinaryOp('sqrsum', aNumber, adverb) }
767 sqrdif { arg aNumber, adverb; ^this.performBinaryOp('sqrdif', aNumber, adverb) }
768 absdif { arg aNumber, adverb; ^this.performBinaryOp('absdif', aNumber, adverb) }
769 thresh { arg aNumber, adverb; ^this.performBinaryOp('thresh', aNumber, adverb) }
770 amclip { arg aNumber, adverb; ^this.performBinaryOp('amclip', aNumber, adverb) }
771 scaleneg { arg aNumber, adverb; ^this.performBinaryOp('scaleneg', aNumber, adverb) }
772 clip2 { arg aNumber=1, adverb; ^this.performBinaryOp('clip2', aNumber, adverb) }
773 fold2 { arg aNumber, adverb; ^this.performBinaryOp('fold2', aNumber, adverb) }
774 wrap2 { arg aNumber, adverb; ^this.performBinaryOp('wrap2', aNumber, adverb) }
775 excess { arg aNumber, adverb; ^this.performBinaryOp('excess', aNumber, adverb) }
776 firstArg { arg aNumber, adverb; ^this.performBinaryOp('firstArg', aNumber, adverb) }
777 rrand { arg aNumber, adverb; ^this.performBinaryOp('rrand', aNumber, adverb) }
778 exprand { arg aNumber, adverb; ^this.performBinaryOp('exprand', aNumber, adverb) }
780 // math op dispatch support
781 performUnaryOp { arg aSelector;
782 ^this.collect({ arg item; item.perform(aSelector) });
785 performBinaryOp { arg aSelector, theOperand, adverb;
786 ^theOperand.performBinaryOpOnSeqColl(aSelector, this, adverb);
788 performBinaryOpOnSeqColl { arg aSelector, theOperand, adverb;
791 size = this.size max: theOperand.size;
792 newList = this.species.new(size);
794 newList.add(theOperand.wrapAt(i).perform(aSelector, this.wrapAt(i)));
798 if (adverb.isInteger) {
800 size = this.size max: theOperand.size;
801 newList = this.species.new(size);
803 newList.add(theOperand.wrapAt(i).perform(aSelector, this.wrapAt(i)));
808 ^theOperand.collect {|item, i| item.perform(aSelector, this, adverb-1) }
810 ^this.collect {|item, i| theOperand.perform(aSelector, item, adverb+1) }
816 // newList = this.species.new(size);
818 // newList.add(theOperand.perform(aSelector, this.at(i)));
821 size = theOperand.size;
822 newList = this.species.new(size);
824 newList.add(theOperand.at(i).perform(aSelector, this));
830 // newList = this.species.new(size);
832 // newList.add(theOperand.perform(aSelector, this.at(i)));
835 size = theOperand.size * this.size;
836 newList = this.species.new(size);
837 theOperand.do({ arg a;
839 newList.add(a.perform(aSelector, b));
845 size = this.size min: theOperand.size;
846 newList = this.species.new(size);
848 newList.add(theOperand.wrapAt(i).perform(aSelector, this.wrapAt(i)));
853 size = this.size max: theOperand.size;
854 newList = this.species.new(size);
856 newList.add(theOperand.foldAt(i).perform(aSelector, this.foldAt(i)));
860 Error("unrecognized adverb: '" ++ adverb ++ "' for operator '" ++ aSelector ++ "'\n").throw;
863 performBinaryOpOnSimpleNumber { arg aSelector, aNumber, adverb;
864 ^this.collect({ arg item;
865 aNumber.perform(aSelector, item, adverb)
868 performBinaryOpOnComplex { arg aSelector, aComplex, adverb;
869 ^this.collect({ arg item;
870 aComplex.perform(aSelector, item, adverb)
874 asFraction { arg denominator=100, fasterBetter=true;
875 ^this.collect { |item| item.asFraction(denominator, fasterBetter) }
878 asPoint { ^Point(this[0] ? 0, this[1] ? 0) }
879 asRect { ^Rect(this[0] ? 0, this[1] ? 0, this[2] ? 0, this[3] ? 0) }
880 ascii { ^this.collect { arg item; item.ascii } }
883 // support UGen rate access
887 if(this.size == 1, { ^this.first.rate });
888 ^this.collect({ arg item; item.rate }).minItem;
889 // 'scalar' > 'control' > 'audio'
892 // if we don't catch the special case of an empty array,
893 // Object:multiChannelPerform goes into infinite recursion
894 multiChannelPerform { arg selector ... args;
896 ^super.multiChannelPerform(selector, *args);
902 // this method is for UGen inputs that require Refs to block direct multichannel expansion.
903 // here, we assume this is already an array of Refs, which we simply return.
904 multichannelExpandRef { arg rank;
908 // support some UGen convenience methods.
909 // NOTE: don't forget to add a wrapper here when adding a method to UGen or AbstractFunction
910 clip { arg ... args; ^this.multiChannelPerform('clip', *args) }
911 wrap { arg ... args; ^this.multiChannelPerform('wrap', *args) }
912 fold { arg ... args; ^this.multiChannelPerform('fold', *args) }
913 linlin { arg ... args; ^this.multiChannelPerform('linlin', *args) }
914 linexp { arg ... args; ^this.multiChannelPerform('linexp', *args) }
915 explin { arg ... args; ^this.multiChannelPerform('explin', *args) }
916 expexp { arg ... args; ^this.multiChannelPerform('expexp', *args) }
917 lincurve { arg ... args; ^this.multiChannelPerform('lincurve', *args) }
918 curvelin { arg ... args; ^this.multiChannelPerform('curvelin', *args) }
919 range { arg ... args; ^this.multiChannelPerform('range', *args) }
920 exprange { arg ... args; ^this.multiChannelPerform('exprange', *args) }
921 unipolar { arg ... args; ^this.multiChannelPerform('unipolar', *args) }
922 bipolar { arg ... args; ^this.multiChannelPerform('bipolar', *args) }
923 lag { arg ... args; ^this.multiChannelPerform('lag', *args) }
924 lag2 { arg ... args; ^this.multiChannelPerform('lag2', *args) }
925 lag3 { arg ... args; ^this.multiChannelPerform('lag3', *args) }
926 lagud { arg ... args; ^this.multiChannelPerform('lagud', *args) }
927 lag2ud { arg ... args; ^this.multiChannelPerform('lag2ud', *args) }
928 lag3ud { arg ... args; ^this.multiChannelPerform('lag3ud', *args) }
929 varlag { arg ... args; ^this.multiChannelPerform('varlag', *args) }
930 slew { arg ... args; ^this.multiChannelPerform('slew', *args) }
931 blend { arg ... args; ^this.multiChannelPerform('blend', *args) }
932 checkBadValues { arg ... args; ^this.multiChannelPerform('checkBadValues', *args) }
933 prune { arg ... args; ^this.multiChannelPerform('prune', *args) }
935 minNyquist { ^min(this, SampleRate.ir * 0.5) }
939 if (function.isNil) { function = { arg a, b; a <= b }; };
940 ^this.mergeSort(function)
943 ^this.sort({| a, b | a[key] <= b[key] })
945 sortMap { arg function;
946 ^this.sort({| a, b | function.value(a) <= function.value(b) })
953 index = this.middleIndex;
954 ^(this[index] + this[index+1]) / 2;
957 median { arg function;
958 //^this.sort(function).sortedMedian
959 // Note the copy, to prevent changing the input.
960 ^this.copy.hoareMedian(function)
963 quickSort { arg function;
964 this.quickSortRange(0, this.size - 1, function)
966 order { arg function;
967 var array, orderFunc;
968 // returns an array of indices that would sort the collection into order.
969 if(this.isEmpty) { ^[] };
970 if (function.isNil) { function = { arg a, b; a <= b }; };
971 array = [this, (0..this.lastIndex)].flop;
972 orderFunc = {|a,b| function.value(a[0], b[0]) };
973 ^array.mergeSort(orderFunc).flop[1]
983 quickSortRange { arg i, j, function;
984 //Sort elements i through j of this to be nondescending according to
986 var di, dij, dj, tt, ij, k, l, n;
988 // The prefix d means the data at that index.
989 if ((n = j + 1 - i) <= 1, { ^this }); // Nothing to sort.
994 if (function.value(di, dj).not, { // i.e., should di precede dj?
1000 if ( n > 2, { // More than two elements.
1001 ij = (i + j) div: 2; // ij is the midpoint of i and j.
1002 dij = this.at(ij); // Sort di,dij,dj. Make dij be their median.
1003 if (function.value(di, dij), { // i.e. should di precede dij?
1004 if (function.value(dij, dj).not, { // i.e., should dij precede dj?
1008 },{ // i.e. di should come after dij"
1012 if ( n > 3, { // More than three elements.
1013 // Find k>i and l<j such that dk,dij,dl are in reverse order.
1014 // Swap k and l. Repeat this procedure until k and l pass each other.
1020 k <= l and: { function.value(dij, this.at(l)) }
1021 }); // i.e. while dl succeeds dij
1024 k <= l and: { function.value(this.at(k), dij) };
1025 }); // i.e. while dij succeeds dk
1030 // Now l<k (either 1 or 2 less), and di through dl are all less than or equal to dk
1031 // through dj. Sort those two segments.
1032 this.quickSortRange(i, l, function);
1033 this.quickSortRange(k, j, function);
1040 mergeSort { arg function;
1042 tempArray = this.class.newClear(this.size);
1043 this.mergeSortTemp(function, tempArray, 0, this.size - 1);
1046 mergeSortTemp { arg function, tempArray, left, right;
1049 size = right - left;
1050 if (size <= 0) { ^this };
1051 if (size <= 8) { ^this.insertionSortRange(function, left, right) };
1053 mid = (right + left) >> 1;
1054 this.mergeSortTemp(function, tempArray, left, mid);
1055 this.mergeSortTemp(function, tempArray, mid+1, right);
1056 this.mergeTemp(function, tempArray, left, mid+1, right);
1059 mergeTemp { arg function, tempArray, left, mid, right;
1060 var i, leftEnd, size, tempPos;
1063 size = right - left + 1;
1064 while { (left <= leftEnd) && (mid <= right) }
1066 if (function.value( this[left], this[mid] ))
1068 tempArray[tempPos] = this[left];
1069 tempPos = tempPos + 1;
1073 tempArray[tempPos] = this[mid];
1074 tempPos = tempPos + 1;
1078 while { left <= leftEnd }
1080 tempArray[tempPos] = this[left];
1081 tempPos = tempPos + 1;
1084 while { mid <= right }
1086 tempArray[tempPos] = this[mid];
1087 tempPos = tempPos + 1;
1091 this[right] = tempArray[right];
1096 insertionSort { arg function;
1097 ^this.insertionSortRange(function, 0, this.size - 1)
1099 insertionSortRange { arg function, left, right;
1102 while { i <= right }
1106 while { (j > left) && { function.value(this[j-1], test).not } }
1108 this[j] = this[j-1];
1117 // Finds the median efficiently, by rearranging the array IN-PLACE.
1118 hoareMedian { |function|
1119 if(this.isEmpty) { ^nil };
1120 ^if(this.size.even, {
1121 [this.hoareFind(this.size/ 2 - 1, function),
1122 this.hoareFind(this.size/ 2, function)].mean;
1124 this.hoareFind(this.size - 1 / 2, function);
1128 // Finds the kth element in the array, according to a given sorting function.
1129 // This is typically fast (order is O(n) rather than O(n log n)) because it
1130 // doesn't attempt to completely sort the array. Method is due to C. A. F. Hoare.
1131 // Note: this rearranges array elements IN PLACE.
1132 hoareFind { |k, function, left, right|
1135 if (function.isNil) { function = { | a, b | a < b } };
1138 j = right ?? {this.size-1};
1142 # l, r = this.hoarePartition(i,j,p, function);
1144 // kth smallest is in right split
1148 // kth smallest is in left split
1152 // The desired element is in desired position
1156 // In-place partitioning method used by hoareFind.
1157 // Note: for efficiency this doesn't check that function is defined, so you
1158 // must supply a function! See hoareFind for example
1159 hoarePartition { |l0, r0, p, function|
1167 while { (l < this.size) and: { function.value(this[l], p) } }{
1171 while { (r >= 0) and: { function.value(p, this[r]) } }{
1174 // check and exchange
1190 *streamContents { arg function;
1192 stream = CollStream.on(this.new(100));
1193 function.value(stream);
1196 *streamContentsLimit { arg function, limit=2000;
1198 stream = LimitedWriteStream.on(this.new(100 min: limit));
1199 stream.limit_(limit).limitFunc_({ ^stream.contents });
1200 function.value(stream);
1205 index = index % this.size;
1208 wrapPut { arg index, value;
1209 index = index % this.size;
1210 ^this.put(index, value)
1212 reduce { arg operator;
1213 var once = true, result;
1214 if(this.size==1){ ^this[0] };
1215 this.doAdjacentPairs {|a, b|
1218 result = operator.applyTo(a, b);
1220 result = operator.applyTo(result, b);
1226 ^String.streamContents { arg stream;
1229 this.do { arg item; stream << item };
1231 stop = this.size - 1;
1232 this.do { arg item,i;
1234 if(i < stop) { stream << joiner };
1241 // TempoClock play quantization
1242 nextTimeOnGrid { arg clock;
1243 ^clock.nextTimeOnGrid(*this);
1246 // we break up the array so that missing elements are set to nil in the Quant
1247 asQuant { ^Quant(*this) }
1249 // asUGenInput { ^this.asArray.asUGenInput }
1251 schedBundleArrayOnClock { |clock, bundleArray, lag = 0, server, latency|
1252 latency = latency ? server.latency;
1257 SystemClock.sched(lag.wrapAt(i), {
1258 server.sendBundle(latency, bundleArray.wrapAt(i)) })
1264 server.sendBundle(latency, bundleArray.wrapAt(i))