Yesterday, I added a new Quark to Supercollider, called TuningLib. It requires a recent version of MathLib, one with the Bessel.sc file included. There are several classes in the new Quark, all realted to tuning.
Stuff from Jascha
Scala - This class is based on the SCL class from Jascha Narveson, but updated so it's a subclass of the newer Tuning class. It opens Scala Files, which means you can use the large and interesting scala file library of thousands of tunings.
Key - Jascha's SCL file also did a bunch of other interesting tuning-related things that the newer Tuning class does not, so I put these features in Key. It tracks your key changes and can interpolate between a given frequency or tuning ratio and the current active Scale.
DissonanceCurve - is, I think, the most interesting part of the TuningLib. It generates Tunings, on the fly, for a given timbre. Give it your spectrum as lists of frequencies and amplitudes, or as a FFT buffer or as the specs for an FM tone, and it makes two different scales.
The first kind of scale it makes is the sort described by Bill Sethares. If you want to see the generated curve, you can plot it. Or you can get a Tuning from it. Or, you can get a scale made up of the n most consonant Tuning ratios. This is used in the second section of my piece Blakes 9
The other sort of tuning it does is based on a similar idea, but using the classic Just Intonation notions of consonance. Like with Sethares' algorithm, every partial of a timbre's spectrum is compared against every partial of the proposed tuning. It calculates the ratio between the frequencies. This could be 3/2, for example, or 115/114 or any whole number ratio. The numerator and denominator of that ratio are summed. In just intonation, smaller numbers are considered more consonant, so the smaller the sum, the more consonant the ratio. (This sum is related to Clarence Barlow's ideas of 'digestibility.') Then, the resultant sum is scaled by the amplitude of the quieter of the two partials. So if they are 3/2 and one has an amplitude of 0.2 and the other of 0.1, the result will be 0.5 ( = (3 + 2) * 0.1). This process repeats for every partial, and the results for each are summed, giving the level of dissonance (or digestibility) of the proposed tuning.
After computing the relative dissonance of all 1200 possible tunings in an octave, the next step is to figure out which ones to select as members of a scale. For this, the algorithm uses a moving window of n potential tunings. For a given tuning, if it is the most consonant of the n/2 tunings below it and the n/2 tunings above it, then it gets added to the Tuning returned by digestibleTuning.
I don't have any sound examples for this usage yet, but I'm working on some. I don't know of any pieces by anybody else using this algorithm either, but I'm sure I'm not the first person to think of it. If you know of any prior work using this idea, please leave a comment.
Lattice - This is based on some tuning methods that Ellen Fullman showed me a few years ago. Based on the numbers you feed it, which should be an array of 2 and then odd numbers, it generates a tuning table. for [2, 5, 3, 7, 9], it creates:
1/1 5/4 3/2 7/4 9/8 8/5 1/1 6/5 7/5 9/5 4/3 5/3 1/1 7/6 3/2 8/7 10/7 12/7 1/1 9/7 16/9 10/9 4/3 14/9 1/1
You can use this class to navigate around in your generated table. For otonality, adjacent fractions are horizontal neighbors, so they share a denominator. For utonality, neighbors are on the vertical axis, so they have the same numerator. Three neighboring ratios make up a triad. You can walk around the table, so that you're playing a triad, and then pick a member f that triad to be a pivot. Then, create a new triad on the other axis that contains your pivot as one of the members.
For example, one possible walk around the table, starting at 0,0 would be [1/1, 5/4, 3/2], [5/4, 1/1, 5/3], [3/2, 4/3, 5/3], [8/5, 4/3, 8/7], [8/7, 9/7, 1/1] etc. As you can (hopefully) see, the table wraps around at the edges.
There is also a class FMSpectrum that will compute the spectrum for a FM tone if given the carrier frequency, the modulation frequency and depth (in Hz). I would like to also add in a class to calculate the spectrum of phase-modulated signals, but I don't have the formula for this. If you know it (or where to find it), leave a comment!