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

)