TuningOffset : EqualTemperament
TuningOffset allows you to specify deviations from equal temperament in terms of fractions of note indices.
*new(stepsPerOctave, calibratefreq, calibratenote, tunings)
stepsPerOctave: How many notes per octave.
calibratefreq: What frequency to calibrate to.
calibratenote: What note number should match the calibratefreq.
tunings: An array with stepsPerOctave numbers containing the offset from equal temperament. 0.01 = one cent above equal temperament (where cent = 1/100 of one note index, with stepsPerOctave * 100 cents per octave).
calibrate(freq, noteindex)
Behaves as in EqualTemperament.
cps(noteindex)
value(noteindex)
Compute frequency in Hz for the given note index. If you use a fractional indices, the offset from the array will be interpolated using blendAt. That is, if note 0 has an offset of 0 and note 1 has an offset of 0.1, note 0.5 will have an offset of 0.05.
t = TuningOffset(12, 60.midicps, 60, ([0, 0.1] ! 6).flat);
t.cps(0).cpsmidi // note 0 has no offset
0
t.cps(1).cpsmidi // note 1 has offset 0.1 (1.1 = 1.0 + 0.1)
1.1
t.cps(0.5).cpsmidi // note 0.5 has offset 0.05 (0.55 = 0.5 + 0.05)
0.55
t.cps(0.75).cpsmidi
0.82499999999999 // or 0.825 = 0.75 + 0.075
t.cps((0.0, 0.02 .. 4.0)).plot; // observe that the plot is just off of a straight line
// Example: Kirnberger III (?)
// cents values from http://tonalsoft.com/enc/k/kirnberger.aspx
c = [0, 90.225, 193.157, 294.135, 386.314, 498.045, 590.224, 696.578, 792.18, 889.735, 996.09, 1088.27];
// convert to offsets from intervals of 100 cents, then divide by 100 for tuning values
c = (c - (0, 100 .. 1100)) * 0.01;
t = TuningOffset(12, 60.midicps, 60, c);
// play white-key music using 12ET
// also include debugging output to show scale degree --> Hz mapping
SynthDescLib.global.read;
(
p = Pbind(
\degree, Pwhite(0, 11, inf),
\delta, Pwrand(#[0.125, 0.25, 0.5], #[1, 4, 2].normalizeSum, inf),
\sustain, Pkey(\delta) * Pwhite(0.8, 1.8, inf),
\instrument, \default
).collect({ |ev| [ev.degree, ev.use({ ~freq.value })].postln; ev }).play;
)
p.stop;
// play the same using the Kirnberger tuning
// I rewrite the protoevent to use a tuning object rather than midicps
(
p = Pbind(
\degree, Pwhite(0, 11, inf),
\delta, Pwrand(#[0.125, 0.25, 0.5], #[1, 4, 2].normalizeSum, inf),
\sustain, Pkey(\delta) * Pwhite(0.8, 1.8, inf),
\instrument, \default,
\tuning, t
).collect({ |ev| [ev.degree, ev.use({ ~freq.value })].postln; ev })
.play(protoEvent: Event.default.copy.put(\freq, #{ ~tuning.cps(~midinote.value + ~ctranspose) * ~harmonic }));
)
p.stop;