number extras Additions of psychoacoustic, music theoretical and harmonic math operations to numbers and collections for SuperCollider
Some of these added methods are used by the other classes in DissonanceLib. They are also useful for general calculations involving psychoacoustic units (barks, ERB and mels for pitch; phons and sones for loudness), music theory (simple methods for cents, representation of notes, and so on) and harmonic math. This latter means the use of ratios and harmonic measures.
Ratios are handled in DissonanceLib as two element arrays. This may not be the best object oriented way of working but for now, it is more practical than working with a Ratio class, which may come later. There are methods for reducing and dividing ratios, for rationalizing decimal frequency ratios (asRatio and rationalize) and also for calculating harmonic measures (there are 3 measures: harmonicity, harmonic distance and gradus suavitatis), see HarmonicVector, HarmonicMetric and PitchSet for more info regarding harmonic arithmetic.
Additions to SimpleNumber
Some of these methods also work for collections of numbers, as implemented in SequenceableCollection
cents
Return the value of a frequency interval in cents:
500.cents(400);
equivalent to:
[500,400].cents;
[ (1 + 5.sqrt)/2, 1.exp, pi].cents.round(0.1);
addCents
Add a cent value to a frequency:
440.addCents(Array.series(12, 0, 100)).asNote;
cents2Frq(frq = 1)
The same as the previous method but with a different semantic. If no frq argument is given, it is assumed
one, which is semantically the same as converting from cents to frequency ratios:
[100, 150, 200, 300].cents2Frq
Array.series(7, 0, 100).cents2Frq(440).round(0.01).asNote
asNote
Represent a frequency as a note name and a deviation in cents from equal temperament:
440.asNote;
550.asNote;
[200,300,400,500].asNote;
asPitchBend(pb = 400)
Calculate pitchbend value for midi playback of microtones (in cents).
pb is the pitch bend ammount (400 = +/- 1 tone, i.e. -200 to +200 cents)
50.asPitchBend; // - > 16
asBark
Return the bark (subjetive pitch) value of a frequency in Hz. See http://en.wikipedia.org/wiki/Bark_scale
200.asBark; // -> 1.980..
barkToFreq
Convert from bark to Hz interpolating from the edges of the critical bandwidth.
(1..20).barkToFreq;
barkToHz
Convert from bark to Hz using the inverse of the asBark function.
(1..20).barkToHz;
criticalBW
Gives the size (in Hz) of the critical bandwidth given in barks:
(1..10).criticalBW; // the numbers represent the width of each critical band
hzToErb
Convert from Hz to ERB (Equivalent Rectangula Bandwidth, another scale based on the critical
bandwidth: see http://en.wikipedia.org/wiki/Equivalent_rectangular_bandwidth). Also called the ERB-rate
of a tone. It is used in the masking analysis methods of LoudnessModel
440.hzToErb;
hzToMel
Yet another subjective pitch scale, not yet used by other classes but implemented for
completeness. See http://en.wikipedia.org/wiki/Mel_scale
440.hzToMel;
melToHz
As its name imples.
100.melToHz;
phonToSone
Convert from phons to sones. http://en.wikipedia.org/wiki/Phon
[40,50,60,70,80,90].phonToSone
soneToPhon
Convert sones to phons. http://en.wikipedia.org/wiki/Sone
Array.geom(6,1,2).soneToPhon;
asPhon(spl, calib = 0)
Return the value in phons for a frequency at a certain db SPL level. Calib should be 0 if loudness is in
dB SPL; a positive number if the values are in dBFS (dB's with respect to a full scale sine wave); or
negative dB's relative to 0 which is the case when translating from amplitude value to dB with ampdb.
100.asPhon(100); // at 100Hz, 100dB is heard as 90.588dB
asSone(spl, calib = 0)
Return the value in sons for a frequency at a certain db SPL level. Calib should be 0 if loudness is in
dB SPL; a positive number if the values are in dBFS (dB's with respect to a full scale sine wave); or
negative dB's relative to 0 which is the case when translating from amplitude value to dB with ampdb.
100.asSone(100); // 100Hz@100dB sounds perceptually as 33.33 sones
asDynamic(freq, ref = 100, fff = 3)
Returns a symbol expressing the dynamic value (ppp-fff) of an amplitude and frequency. The number
should be an amplitude; it is converted to dBFS, then phon, sone and musical dynamics. The reference
value is 100, which assumes that the amplitude value of 1.0 at 1000Hz will translate to 64 sones,
equivalent to fff (see also LoudnessModel).
The upper boundary for sones is 64 because equal loudness contours stop at 100 phons. The fff argument
is there to adjust how many f's correspond to 64 sones. The default of 3 is subtracted from 6, which is the power of two of 64, yielding 3f's. If it is less than 3, more f's will correspond to that maximum dynamic.
According to one's needs, values can go from, say, ppppp-fffff.
Examples:
1.0.asDynamic(100); // full code sine wave at 100Hz -> ff
1.0.asDynamic(50) ; // only perceived as f an octave lower
1.0.asDynamic(500) ; // and fff at 500Hz
// descending scale of amplitudes in relation to 5000Hz:
Array.geom(10, 1.0, 0.35).round(0.0001).postln.asDynamic(5000);
// and in relation to 440Hz:
Array.geom(10, 1.0, 0.35).asDynamic(440);
For arrays of amps and freqs, you can use an array (of the same size as the amp array) for the freq arg:
// a series o frequencies in relation to 0.5 amp
// (like the representation in musical notation of an equal loudness curve)
({0.5}!25).asDynamic(Array.geom(25,20000, 0.75).round(0.1).postln);
// the dynamic curve is shifted so that 64 sones is fffff:
({0.5}!25).asDynamic(Array.geom(25,20000, 0.75).round(0.1).postln, 100, 1);
// random amps and freqs:
({rrand(0.0001, 0.1)}!8).round(0.001).postln.asDynamic(({rrand(50,2000)}!8).postln);
bintodb(zeta = 8)
Convert the magnitude of an fft bin to dB. Implemented according to a formula found in Nick Collins PhD
Thesis. zeta is a calibration factor. Its value is 184262 in the formula, but from my experience, for practical
purposes a value of 8 works well with SC's PV_MagBuffer and PV_FreqBuffer (see the topic
liveDissonance).
3.bintodb;
3.bintodb(184262);
3.bintodb(1)
asWavelength(c = 343)
Return the wavelength size in meters of a frequency, c being the speed of sound in meters/second.
The default value corresponds to the speed of sound at 20 degrees Celsius.
2400.asWavelength;
440.asWavelength;
100.asWavelength;
20.asWavelength;
minHarmonicityVector(pitchRange = 1, maxPrime = 11)
Return a sequence of largest prime powers for a given harmonicity minimum. Pitch range is
in octaves, ex, 0.03.minHarmonicityVector(1,13) yields [12, 8, 3, 2, 1, 1].
They correspond to the powers of the harmonic space bases 2,3,5,7,11,and 13 inside an octave.
"A maximum powers sequence includes intervals, the harmonicities of which may lie
below the minimum suggested [by this method]...The maximum power sequence guarantees merely
that all intervals that are more harmonic than a given minimum [harmonicity] value can be
expressed by the sequence. [12, 8, 3, 2, 1, 1] results in as many as 3,964 different intervals
within one octave (!), of which only 211 are truly more harmonic than 0.03" ("Two Essays on Theory",
C. Barlow (CMJ, 1987)). This is related to the highestPower method, see below.
0.03.minHarmonicityVector(1,13); // -> [12, 8, 3, 2, 1, 1]
asRatio
This is like SimpleNumber:asFraction but hacked in order to handle rounding errors for
harmonic interpretation of periodic decimals (0.333 will be 1/3 and not 333/1000)
0.333.asRatio;
1.667.asRatio; // compare with:
1.667.asFraction;
Additions to Integer
Some of these methods are also implemented for SequenceableCollection
indigestibility
Barlow's indigestibility of an integer. A measure of how a number may be psychologically 'digestible'
according to its prime factors. See Barlow, C, "Two Essays on Theory", Computer Music Journal, 1987.
It is rarely used on its own but is the basis for the harmonicity function.
Formula:
r=∞
ξ(N)=2∑{n(p-1)/p}
r=1
where N = ∏pn (the prime factors of integer N)
Example:
// see how primes are much more indigestible than composites
(0..31).collect(_.indigestibility).plot2(\indigestibility, Rect(300,300,800,300))
harmonicity
Barlow's harmonicity formula for an interval p/q. It is the reciprocal of the sum of the indigestibilties of
p and q, with its sign indicating the interval's polarity.
H(P,Q) = sgn(ξ(Q)-ξ(P)) / (ξ(P)+ξ(Q))
Negative polarity means that the interval is weighted towards its upper tone and not towards its lower
tone, as with a positive value. As an example, a perfect fifth has its 'weight' on the lower tone, while its
inverse, a perfect fourth, has its weight on the highest tone. The absolute value of a harmonicity is called
harmonic intensity.
The harmonicity of 1/1 is infinite. There is a flag (clean = true) in the implementation of harmonicity for
collections that is used for setting the harmonicity of 1/1 to 2 instead of NaN.
Compare:
[[1,1],[2,1],[3,1],[8,1],[3,2]].harmonicity(false);
[[1,1],[2,1],[3,1],[8,1],[3,2]].harmonicity;
Examples:
2.harmonicity(3); // harmonicity of a perfect fifth
[3,2].harmonicity; // Equivalent notation
[[3,2],[2,3],[4,3],[3,4]].harmonicity; // notice the polarity of those intervals
highestPower
Barlow's formula N(p) from "Two Essays on Theory". It is used by minHarmVector, see above.
divisorSet
Returns an array with all the integers that divide this. It is useful for making scales out of whole numbers.
See for example, Erkki Kurenniemi, "Chords, scales, and divisor lattices".
60.divisorSet; // -> [ 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60 ]
multiples(...primes)
Returns an array with all the multiples of a list of primes up to this integer.
35.multiples(3,5,7); // -> [ 3, 5, 7, 9, 15, 21, 25, 27, 35 ]
99.multiples(5,7,11); // -> [ 5, 7, 11, 25, 35, 49, 55, 77 ]
harmonics(max)
Returns an array with the harmonics of a number up to the highest harmonic (max).
5.harmonics(48); // -> [ 5, 10, 15, 20, 25, 30, 35, 40, 45 ]
primeHarmonics(maxPartial)
Returns a nested array with all the harmonics up to maxPartial of a prime (this) along with all the lower
primes.
17.primeHarmonics(20);
// [ [ 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 ],
// [ 3, 6, 9, 12, 15, 18 ], [ 5, 10, 15, 20 ],
// [ 7, 14 ], [ 11 ], [ 13 ], [ 17 ]
// ]
listOfHarmonics(max)
Returns an array with the harmonics (up to max) of all the primes below (and including) this. It is
equivalent to: highest_harmonic.multiples(array of primes up to this).
7.listOfHarmonics(50)
Working with harmonic ratios
These are methods implemented for SequenceableCollection. They assume arrays of two elements.
ratioDiv(that, reduce = true)
Ratio division. If reduce = true, the result will be expressed in its lowest terms.
[5,4].ratioDiv([3,2]); // -> [5, 6]
[5,4].ratioDiv([3,2], false); // -> [10, 12]
reduceRatio
Reduce a ratio to its lowest terms [p,q] , where p and q are coprime.
[20,15].reduceRatio; // -> [4,3]
ratioPost(char = ", ")
Utiity for representing [p,q] ratios as p/q strings. If the array has only two elements, then the string "p/q" will
be returned. If the array is an array of [p,q] it will return a string of "p1/q1 ... pn/qn" separated by char.
[7,4].ratioPost;
[ [1,1], [9,8], [81,64] ].ratioPost;
[ [5,4], [4,3], [64,45] ].ratioPost(" -> ");
lcd
The lowest common denominator to an array of [p, q] ratios.
[[5,4], [4,3], [64,45]].lcd;
[[1,1], [9,8], [81,64]].lcd;
[[1,1], [9,8], [5,4]].lcd;
[[1,1], [9,8], [6,5]].lcd;
katapykne(n = 1)
A method of densification of intervals used by ancient greek harmonists. See John Chalmers "Divisions of the Tetrachord", Chapter 2: "Katapyknosis consists of the division, or rather the filling-in, of a musical
interval by multiplying its numerator and denominator by a set of integers of increasing magnitude ... The
intervals form a series of microtones which are then recombined to produce the desired melodic division,
usually composed of epimore [superparticular] ratios."
n is the number of levels of this process
[5,4].katapykne;
[5,4].katapykne(2); // 10/9 * 9/8 = 5/4
[5,4].katapykne(5); // all those ratios divide 5/4 into epimore ratios
[5,4].katapykne(5).product.reduceRatio; // that intervallicaly sum to 5/4
katapykne_ab(a = 1, b = 2)
A variation on katapyknosis where the increment by factors a and b is not a simple arithmetic series .
[5,4].katapykne_ab(1,2)
[5,4].katapykne_ab(1,3)
[5,4].katapykne_ab(2,3)
[5,4].katapykne_ab(2,6)
[5,4].katapykne_ab(4,2)
[5,4].katapykne_ab(5,3)
ratioToFreq
Express and array of [p, q] ratios as decimal frequency ratios.
[[1,1], [9,8], [5,4]].ratioToFreq;
ratioDifferentiate
Return an array of [p, q] ratios expressed as adjacency instead of absolute intervals.
[[1,1], [9,8], [5,4], [4,3], [45,32], [3,2]].ratioDifferentiate;
ratioToHarmonics
Convert an array of [p, q] ratios to the harmonics that correspond to those ratios.
[[1,1], [9,8], [5,4], [4,3], [45,32], [3,2]].ratioToHarmonics;
[[1,1], [5,4], [3,2]].ratioToHarmonics; // a major chord corresponds to harmonics 4,5,6
[[1,1], [6,5], [3,2]].ratioToHarmonics; // a minor chord to harmonics 10,12,15
[[1,1],[16,15],[6,5],[4,3],[3,2],[8,5],[9,5],[2,1]].ratioToHarmonics;
// Phrygian mode as a subset of the harmonic series -> [ 30, 32, 36, 40, 45, 48, 54, 60 ]
harmonicsToRatios
Convert an array of integers to the ratios they represent as harmonics.
[4,5,6,7].harmonicsToRatios; // a just seventh chord
[24,27,30,32,36,40,45,48].harmonicsToRatios;
// a diatonic major scale -> [[1,1],[9,8],[5,4],[4,3],[3,2],[5,3],[15,8],[2,1]]
60.divisorSet[5..].harmonicsToRatios;
// The series of numbers mentioned in Plato's Timaeus
// when the Demiurge harmoniously makes the World-Soul:
[6,8,9,12,16,18,24,27,32,36,48,54,81,108,162].harmonicsToRatios
subharmonicsToRatios
Convert an array of integers to the ratios they represent as subharmonics.
// For those who claim that Plato's numbers refer to slower rates of movement
// and not to lengths of strings or pipes (see A. Barker, Harmonics in Ancient Greece, 322)
[6,8,9,12,16,18,24,27,32,36,48,54,81,108,162].subharmonicsToRatios
arithmetic, harmonic, geometric means
integerArithmetic and harmonic means
Convert an array of integers to the ratios they represent as harmonics.
example of geometric means producing ET
rationalize(tolerance = 16, metric, type = \size, max)
An important method used in Dissonance to convert an array of decimal frequency ratios into [p,q] ratios.
It first finds a rough approximation using asRatio (explained above). Then it compares from a list of
intervals stored in the IntervalTable class (there are several possible tables, see its help file) and chooses
the one with the highest harmonic metric within the given tolerance range.
The tolerance (in cents) defines the range within which the search for intervals will be made.
The metric is either an instance of HarmonicMetric or a symbol:
\harmonicity, \harmonicDistance or \gradusSuavitatis
If no metric is specified, \harmonicity will be used. See below for more on harmonic measures.
The type is either \size or \prime. If \size is chosen, intervals in the table with numerator and denominator
larger than max (which defaults to [729, 512]) will be ignored. If \prime is chosen, intervals containing
prime factors larger than max (which defaults to 19) will be ignored. Default is \size.
Examples:
[1.0, 1.125, 1.333, 1.37, 1.67, 1.87, 1.91, 2.1].rationalize;
[1.0, 1.125, 1.333, 1.37, 1.67, 1.87, 1.91, 2.1].rationalize(5);
// notice how the second interval (a pythagorean ditone) is interpreted differently
// according to metric (and tolerance):
[1.125, 1.265625, 1.333, 1.36].rationalize(12, \harmonicDistance);
[1.125, 1.265625, 1.333, 1.36].rationalize(12, \harmonicity);
[1.125, 1.265625, 1.333, 1.36].rationalize(12, \gradusSuavitatis);
[1.125, 1.333, 1.37, 1.67, 1.897].rationalize(21, \harmonicity, \prime, 7);
[1.125, 1.333, 1.37, 1.67, 1.897].rationalize(21, \gradusSuavitatis, \prime, 11);
// irrational numbers phi, e & pi, compare:
[(1 + 5.sqrt)/2, 1.exp, pi ].rationalize; // phi as 45/28
[(1 + 5.sqrt)/2, 1.exp, pi ].rationalize(20); // phi as 8/5 minor sixth
[(1 + 5.sqrt)/2, 1.exp, pi ].rationalize(12, \harmonicDistance);// phi as 13/8, pi as 22/7
// to rationalize from cents to ratios use cents2Frq
Array.series(13, 0, 100).cents2Frq.rationalize; //12ET
analyseScale(tolerance = 16, type = \size, maxNum = 729, maxDenom = 521, maxPrime = 31, post = true)
This method is called by rationalize but can also be handy on its own if one wants to classify a set of
intervals. The arguments are the same as above with the exception that the information type is not
contained in a single argument max but independently in arguments maxNum, maxDenom and
maxPrime. Additionally, when used on its own, it outputs the inteval lists. See also ratioToName below.
[1.0, 1.125, 1.333, 1.37, 1.67, 1.87, 1.91, 2.1].analyseScale
ratioToName(tolerance = 16, restore = true)
For posting the names of ratios from a list taken from the Huygens-Fokker foundation of around 356
intervals inside and octave, which is why this method works only with octave-reduced intervals.
Because IntervalTable as a whole class keeps one interval list loaded at any given time, restore is a flag
used to change the table back to the previously used one, as it is common to have a table that
encompasses many octaves and more intervals (the default is a table, called \030, has all intervals with
harmonicities higher than 0.03) but which don't contain a key for names. In this way, after posting the
names, the previous tables are loaded back as they were.
// Examples, see what is posted. May need a small font in the listener window to view properly
[[1,1], [9,8], [4,3], [11,8], [5,3], [15,8], [48,25], [25,12]].ratioToName;
[[1,1], [9,8], [4,3], [11,8], [5,3], [15,8], [48,25], [25,12]].ratioToName(2);
centsToName(tolerance = 16, restore = true)
Same as above but the array is of cent values instead of ratios.
Array.fill(10, {|x| (x*10) + rrand(0, 50)}).centsToName;
Harmonic measures
There are 3 main harmonic measures implemented in DissonanceLib. See HarmonicMetric for more info.
harmonicity
See above for a discussion.
harmonicDistance
James Tenney's harmonic distance. Defined as a city-block metric of harmonic lattices (Discussed for
example in his article, "John Cage and the Theory of Harmony", 1983).
[4,3].harmonicDistance;
[[1,1], [5,4], [3,2]].harmonicDistance; // -> [ 0, 2.995732273554, 1.7917594692281 ]
gradusSuavitatis
Leonhard Euler's degree of sweetness (1739). Similar to Barlow's harmonicity in that it deals with
primeness as a measure of harmonic concordance, but with the dissadvantage of giving the same
measures for different intervals. (For much more, see John Chalmers, "Divisions of theTetrachord").
Formula: G(a) = 1 + k1*(p1-1) + k2*(p2-1) +.... + kn * (pn-1)
where a = (p1^k1) *(p2^k2)*...*(pn^kn) and p1, p2, ... pn are its prime factors
[4,3].gradusSuavitatis;
[[1,1], [5,4], [3,2]].gradusSuavitatis;
[[1,1],[9,8],[5,4],[4,3],[3,2],[5,3],[15,8],[2,1]].gradusSuavitatis;
// -> [ 1, 8, 7, 5, 4, 7, 10, 2 ] notice how the GS of [5,4] and [5,3] is the same
gradusSuavitatisN
Degree of sweetness of a scale or chord.
[[1,1], [5,4], [3,2]].gradusSuavitatisN;
[[1,1],[9,8],[5,4],[4,3],[3,2],[5,3],[15,8],[2,1]].gradusSuavitatisN;
[4,5,6,7].harmonicsToRatios.gradusSuavitatisN;
Convenience methods
The following are designed to work with arrays of pairs of frecuencies and intensities [freq, spl]:
asPhon
Return the values in phons of arrays of [freq, spl] pairs.
[100, 100].asPhon;
[ [80,100], [160, 100], [320, 100], [640,100] ].asPhon;
asSone
Return the values in sones of arrays of [freq, spl] pairs.
[100, 100].asSone;
[ [80,100], [160, 100], [320, 100], [640,100] ].asSone;
compensateMasking(gradient = 12)
Returns the amplitudes of partials after masking. See LoudnessModel.
Values are input as arrays of [spl, freq] pairs.
[ [80,100], [160, 100], [320, 100], [640,100] ].compensateMasking.round(0.001);
// -> [ 98.326, 98.084, 99.435, 100 ], meaning that after masking each is slightly lower
[ [440,100], [554.36, 100], [659.25, 100], [783.99, 100] ].compensateMasking.round(0.001);
[ Array.series(3, 69, 1).midicps.round(0.001), 100!3].flop.compensateMasking.round(0.001)
Other utility methods:
*primes(maxPrime = 11)
A shortcut for making arrays of primes.
Array.primes(11); // -> [2, 3, 5, 7, 11]
removeDuplicates
A shortcut for removing duplicate items in a collection (does not preserve order).
[1,2,3,4,3,6,3,7].removeDuplicates
...
(c) 2005-2010, jsl