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
|
// 2003 Lance Putnam
+ SequenceableCollection {
// Makes a specified tuning scale
// The last element of stepRatios is the octave ratio. This is typically 2.
*tuningScale { arg rootFreq = 440, stepRatios=#[1.5, 2], loFreqBound = 20, hiFreqBound = 20000;
var index, octaveUp, octaveDown, divs, scaleFreqs;
var current, octave;
divs = stepRatios.size;
if(stepRatios[divs-1] <= 1.001, { ^nil });
index = -1;
octaveUp = stepRatios[divs - 1];
octaveDown = 1/octaveUp;
octave = rootFreq;
scaleFreqs = this.new;
while({ octave > loFreqBound }, { // below low bound?
octave = octave * octaveDown; // go down by "octave" from root
});
current = octave;
while({ current < loFreqBound }, { // below low bound?
index = index + 1;
if(index >= divs, {
index = 0;
octave = octave * octaveUp;
});
current = octave * stepRatios[index]; // go up one step
});
while({ current <= hiFreqBound }, { // at or below high bound?
scaleFreqs = scaleFreqs.add(current);
index = index + 1;
if(index >= divs, {
index = 0;
octave = octave * octaveUp;
});
current = octave * stepRatios[index];
});
^scaleFreqs
}
// does a binary search
nearestTo { arg value;
var lowerInd, upperInd, centerInd;
lowerInd = 0;
upperInd = this.size - 1;
while({ (upperInd - lowerInd) > 1 },{
centerInd = (((upperInd - lowerInd)/2.0)+lowerInd).round.asInt;
if( value < this[centerInd], {
upperInd = centerInd;
},{
lowerInd = centerInd;
});
});
if( (value - this[lowerInd]) < (this[upperInd] - value), {
^this[lowerInd]
},{
^this[upperInd]
});
}
// same as nearestTo, but input/output is an array
nearestToList { arg values;
var matches;
var lowerInd, upperInd, centerInd;
values.do({ arg value, i;
lowerInd = 0;
upperInd = this.size - 1;
while({ (upperInd - lowerInd) > 1 },{
centerInd = (((upperInd - lowerInd)/2.0)+lowerInd).round.asInt;
if( value < this[centerInd], {
upperInd = centerInd;
},{
lowerInd = centerInd;
});
//("In range: [" ++ this[lowerInd] ++ ", " ++ this[upperInd] ++ "]").postln;
});
if( (value - this[lowerInd]) < (this[upperInd] - value), {
matches = matches.add( this[lowerInd] );
},{
matches = matches.add( this[upperInd] );
});
});
^matches
}
}
|