Lattice An object which holds one row of a tuning table based on overtones
This uses the sort of Tuning Table used by Ellen Fullman. One row might look like
1/1 5/4 3/2 7/4 9/8 // for otonality or
1/1 8/5 4/3 8/7 19/6 // for utonality
It also is able to generate and navigate a 3 dimentinal table:
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
Creation / Class Methods
*new (otones, base )
Creates a new Lattice
otones - An array of numbers to use for numerators in otonality.
Default value is [ 2, 5, 3, 7, 9, 11, 13, 15, 17, 19, 21, 23]
base - For octave based systems, this is 2, but if you wanted to base your system on 3s, you could use 3 instead. Default value is 2.
// Example
l = Lattice.new([2, 5, 3, 7, 9]);
// generates 1/1 5/4 3/2 7/4 9/8 for otonality as described above
*adjustOctave (ratio)
For a given ratio, does octave transpositions and returns a ratio between 1 and 2
// Example
Lattice.adjustOctave(9/2) // returns 1.125, which is 9/8
Accessing Instance and Class Variables
makeOvertoneIntervals (start, orientation)
For a given index, return a triad of ratios
start - The index in the lattice row in which to start. This wraps if need be.
orientation - Use true for utonality or false for otonailty. The triad is computed in regards to the base.
// Example
l = Lattice.new([2, 5, 3, 7, 9]);
l.makeOvertoneIntervals(4, true);
l.makeOvertoneIntervals(2, false);
makeIntervals (x, y, orientation)
For a given x and y index, return a triad of ratios
x - The index in the lattice row for o[x]/o[y] This wraps if need be.
y - The index in the lattice row for o[x]/o[y] This wraps if need be.
orientation - Use true for utonality such that the returned triads will change in the numerator, but not the demonimator. To change the denominator, use false.
// Example
l = Lattice.new([2, 5, 3, 7, 9]);
l.makeIntervals(4, 3, true); // returns [9/7, 8/7, 10/7]
l.makeIntervals(2, 2, false); // returns [1/1, 12/7, 4/3]
getOvertoneInterval (index, orientation)
Returns the fraction at the index
index - The index of the overtone or undertone
orientation - True for otonality, false for utonality
// Example
l = Lattice.new([2, 5, 3, 7, 9]);
l.getOvertoneInterval(2, true); // returns 3/2
l.getOvertoneInterval(3, false); // returns 8/7
getInterval (x, y)
For a given x and y index, return a ratio
x - The index in the lattice row for o[x]/o[y] This wraps if need be.
y - The index in the lattice row for o[x]/o[y] This wraps if need be.
d2Pivot (start)
Find a pivot based on a start point.
Finding the new pivot point means picking one of the fractions in a triad.
Finding the new start means figuring out wether the new pivot is the top, middle, or bottom
member of the triad and computing a new start index based on that computation
start - The starting index of the triad, in which we wish to pivot
d3Pivot (x, y, orientation)
Find a pivot based on a start point, describe by o[x]/o[y].
Finding the new pivot point means picking one of the fractions in a triad
Finding the new start means figuring out wether the new pivot is the top, middle, or bottom member of the triad and computing a new start index based on that computation
x - The starting index of the numerator of the triad in which we wish to pivot.
y - The starting index of the denominator of the triad in which we wish to pivot.
orientation - If true, the overtones will change in the pivot. If false, the undertones will change in the pivot.
Examples
// Use this SynthDef for all examples
(
SynthDef("sine", {arg out = 0, dur = 5, freq, amp=1, pan = 0;
// a sine wave where the attack and decay are each 10% of the duration
var env, osc;
env = EnvGen.kr(Env.sine(dur, amp), doneAction: 2);
osc = SinOsc.ar(freq, 0, env);
OffsetOut.ar(out, osc);
}).memStore;
)
// Moving through the lattice with a Pbind
(
var index, lattice, basefreq, orient;
lattice = Lattice.new;
basefreq = 440;
orient = false;
index = lattice.overtones.size;
Pbind(
\freq, Pfunc({
var freq;
index = index - 1;
// use the index to compute what frequency to play, but
// if the frequency is out of bounds, return nil
// the nil will halt the Pbind
if ((index <= lattice.overtones.size) && (index >= 0), {
freq = lattice.getOvertoneInterval(index, orient);
freq * basefreq;
}, {
nil;
});
}),
\amp, 0.3,
\instrument, \sine
).play
)
// Walking around a table
(
var lat, orientation, startx, starty, baseFreq;
lat = Lattice.new;
orientation = true;
startx = 0;
starty = 0;
baseFreq = 440;
Pbind(
\instrument, \sine,
\amp, 0.3,
\freq, Pfunc({
var starts, result;
orientation = orientation.not;
starts = lat.d3Pivot(startx, starty, orientation);
startx = starts.first;
starty = starts.last;
result = lat.makeIntervals(startx, starty, orientation);
(result * baseFreq)
})
).play
)