1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
// A phrase is an array that behaves like a stream, but allows
// you to manipulate its data on the fly.
// Every phrase has a region defined that determines both what
// array data responds to the operation methods and what section of
// the phrase will loop when it's streamed.
Phrase{
var <initialPhrase, <>phrase;
var <returnProbs, <returnBools, <>loopReturns;
var <regionStart, <regionLength, <pos, <seed;
var counter;
*new{ arg phrase, returnProbs, loopReturns = true;
if(returnProbs.isNil, {
returnProbs = Array.fill(phrase.size, 1);
});
^this.newCopyArgs(
phrase.copy, phrase,
returnProbs, Array.newClear(phrase.size), loopReturns,
0, phrase.size, 0, Date.seed,
0
).calcReturns
}
// randomly choose element from region
choose{
var index, returnItem;
index = Array.newClear(regionLength);
regionLength.do({ arg i;
index[i] = (regionStart + i) % phrase.size;
});
pos = index.choose;
if(loopReturns, {
returnItem = returnBools[pos];
},{
returnItem = returnProbs[pos % returnProbs.size].coin;
});
if(returnItem, {
^phrase[pos]
},{
^nil
});
}
next{
var prevPos, returnItem;
prevPos = pos;
//pos = (pos + 1) % length;
// odd loop lengths don't work!!!
//pos = ((pos + 1).wrap(regionStart, regionStart+regionLength-1)) % phrase.size;
pos = (pos + 1) % phrase.size;
counter = counter + 1;
if(counter >= regionLength, {
counter = 0;
pos = regionStart;
});
if(loopReturns, {
returnItem = returnBools[prevPos];
},{
returnItem = returnProbs[prevPos % returnProbs.size].coin;
});
if(returnItem, {
^phrase[prevPos]
},{
^nil
});
}
calcReturns{ arg anotherSeed;
if(anotherSeed.isNil, {
thisThread.randSeed = seed;
},{
thisThread.randSeed = anotherSeed;
});
phrase.size.do({ arg i;
returnBools[i] = returnProbs[i % returnProbs.size].coin;
});
}
// A function used for doing operations on current region
regionFunc{ arg func ... sourceArrays;
var temp;
temp = Array.newClear(regionLength);
sourceArrays.do({ arg arr;
// extract region from source array
regionLength.do({ arg i;
temp[i] = arr[(regionStart + i)%(arr.size)];
});
// perform function on extracted region
temp = func.value(temp);
// copy modified region back into the source array
regionLength.do({ arg j;
arr[(regionStart + j)%(phrase.size)] = temp[j];
});
});
}
// Phrase operations
// Note: these work on the region [regionStart, regionStart + regionLength]
// change order of elements
ascend{
this.regionFunc({arg array; array.quickSort({arg a, b; a <= b}) }, phrase);
}
descend{
this.regionFunc({arg array; array.quickSort({arg a, b; a >= b}) }, phrase);
}
permute{ arg nthPermutation;
this.regionFunc({arg array; array.permute(nthPermutation) }, phrase, returnBools);
}
reverse{
this.regionFunc({arg array; array.reverse }, phrase, returnBools);
}
rotate{ arg n=1;
this.regionFunc({arg array; array.rotate(n) }, phrase, returnBools);
}
// change values of elements
gaussian{ arg dev;
thisThread.randSeed = seed;
this.regionFunc({arg array; array.gaussian(dev) }, phrase);
// phrase.size.do({ arg i;
// phrase[i] = initialPhrase[i] * (2.pow(0.gaussian(octaveDev)));
// });
}
invert{
this.regionFunc({arg array; array.invert }, phrase);
}
revert{
phrase = initialPhrase.copy;
}
scale{ arg scalar;
this.regionFunc({arg array; array * scalar }, phrase);
}
shift{ arg constant;
this.regionFunc({arg array; array + constant }, phrase);
}
// changing parameters
regionLength_{ arg newLength;
//if(newLength <= phrase.size, {
regionLength = newLength;
//});
}
regionStart_{ arg newLoopStart;
regionStart = newLoopStart % phrase.size;
}
returnProbs_{ arg probs, seed;
// If input probs is just a number, then fill the array
// with that number. If it's an array, lace it.
if(probs.class.superclass == SimpleNumber, {
returnProbs = returnProbs.fill(probs);
},{
returnProbs = probs;
});
this.calcReturns(seed);
}
seed_{ arg newSeed;
if(newSeed != seed, {
seed = newSeed;
//phrase = this.gaussify(initialPhrase, 0.5, );
});
}
}
|