3 var <degrees, <pitchesPerOctave, <tuning, <>name;
5 *new { | degrees, pitchesPerOctave, tuning, name = "Unknown Scale" |
6 ^super.new.init(degrees ? \ionian, pitchesPerOctave, tuning, name);
9 init { | inDegrees, inPitchesPerOctave, inTuning, inName |
10 degrees = inDegrees.asArray.asInteger;
11 pitchesPerOctave = inPitchesPerOctave ? this.guessPPO(degrees);
13 ^this.tuning_(inTuning ? Tuning.default(pitchesPerOctave));
16 *newFromKey { |key, tuning|
17 var scale = ScaleInfo.at(key);
18 scale ?? { ("Unknown scale " ++ key.asString).warn; ^nil };
19 tuning !? { scale.tuning_(tuning.asTuning) };
23 checkTuningForMismatch { |aTuning|
24 ^pitchesPerOctave == aTuning.size;
27 tuning_ { | inTuning |
28 inTuning = inTuning.asTuning;
29 if(this.checkTuningForMismatch(inTuning)) {
32 "Scale steps per octave % does not match tuning size ".format(pitchesPerOctave).warn;
37 // most common flavors of ET
38 // pick the smallest one that contains all scale degrees
39 var etTypes = #[12, 19, 24, 53, 128];
40 ^etTypes[etTypes.indexInBetween(degrees.maxItem).ceil];
44 ^this.semitones.as(class)
52 ^degrees.collect(tuning.wrapAt(_));
60 ^this.semitones.midiratio
64 ^tuning.at(degrees.wrapAt(index))
68 ^tuning.wrapAt(degrees.wrapAt(index))
71 performDegreeToKey { | scaleDegree, stepsPerOctave, accidental = 0 |
73 stepsPerOctave = stepsPerOctave ? tuning.stepsPerOctave;
74 baseKey = (stepsPerOctave * (scaleDegree div: this.size)) + this.wrapAt(scaleDegree);
75 ^if(accidental == 0) { baseKey } { baseKey + (accidental * (stepsPerOctave / 12.0)) }
78 performKeyToDegree { | degree, stepsPerOctave = 12 |
79 ^degrees.performKeyToDegree(degree, stepsPerOctave)
82 performNearestInList { | degree |
83 ^degrees.performNearestInList(degree)
86 performNearestInScale { | degree, stepsPerOctave=12 | // collection is sorted
87 ^degrees.performNearestInScale(degree, stepsPerOctave)
90 degreeToRatio { |degree, octave = 0|
91 ^this.ratios.at(degree) * (this.octaveRatio ** octave);
94 degreeToFreq { |degree, rootFreq, octave|
95 ^this.degreeToRatio(degree, octave) * rootFreq;
98 *choose { |size = 7, pitchesPerOctave = 12|
99 var scale = ScaleInfo.choose({
100 |x| (x.size == size) && (x.pitchesPerOctave == pitchesPerOctave)
103 ("No known scales with size " ++ size.asString ++
104 " and pitchesPerOctave " ++ pitchesPerOctave.asString).warn;
110 *doesNotUnderstand { |selector, args|
111 var scale = this.newFromKey(selector, args);
112 ^scale ?? { super.doesNotUnderstand(selector, args) };
125 ^tuning.stepsPerOctave
129 ^degrees == scale.degrees and: { tuning == scale.tuning }
133 ^degrees.hash bitXor: tuning.hash
137 var storedKey = this.storedKey;
138 stream << this.class.name;
139 if(storedKey.notNil) { stream << "." << storedKey } { this.storeParamsOn(stream) }
143 // can be optimised later
144 var stored = ScaleInfo.scales.detect(_ == this);
145 ^stored !? { ScaleInfo.scales.findKeyForValue(stored) }
148 storeArgs { ^[degrees, pitchesPerOctave, tuning, name] }
160 var <tuning, <octaveRatio, <>name;
162 *new { | tuning, octaveRatio = 2.0, name = "Unknown Tuning" |
163 ^super.newCopyArgs(tuning, octaveRatio, name);
166 *newFromKey { | key |
170 *default { | pitchesPerOctave |
171 ^this.et(pitchesPerOctave);
174 *et { |pitchesPerOctave = 12 |
175 ^this.new(this.calcET(pitchesPerOctave), 2.0, this.etName(pitchesPerOctave));
178 *calcET { | pitchesPerOctave |
179 ^(0..(pitchesPerOctave - 1)) * (12/pitchesPerOctave)
182 *etName { |pitchesPerOctave|
183 ^"ET" ++ pitchesPerOctave.asString
186 *choose { |size = 12|
187 ^TuningInfo.choose({ |x| x.size == size })
199 ^this.semitones * 100
203 ^this.semitones.as(class)
215 ^tuning.wrapAt(index)
219 ^tuning == argTuning.tuning and: { octaveRatio == argTuning.octaveRatio } }
222 ^tuning.hash bitXor: octaveRatio.hash
225 *doesNotUnderstand { |selector, args|
226 var tuning = this.newFromKey(selector, args);
227 ^tuning ?? { super.doesNotUnderstand(selector, args) }
231 ^TuningInfo.directory
235 ^octaveRatio.log2 * 12.0
247 var storedKey = this.storedKey;
248 stream << this.class.name;
249 if(storedKey.notNil) { stream << "." << storedKey } { this.storeParamsOn(stream) }
253 // can be optimised later
254 var stored = TuningInfo.tunings.detect(_ == this);
255 ^stored !? { TuningInfo.tunings.findKeyForValue(stored) }
259 ^[tuning, octaveRatio, name]
266 *new { | degrees, pitchesPerOctave, descDegrees, tuning, name = "Unknown Scale" |
267 ^super.new.init(degrees ? \ionian, pitchesPerOctave, tuning, name)
268 .descScale_(Scale(descDegrees ? \ionian, pitchesPerOctave, tuning, name ++ "desc"))
271 asStream { ^ScaleStream(this, 0) }
272 embedInStream { ScaleStream(this).yield }
277 var <>scale, <>curDegree;
279 *new { | scale, startDegree = 0 | ^super.newCopyArgs(scale, startDegree) }
281 chooseScale { |scaleDegree |
282 if (scaleDegree >= curDegree) {
283 curDegree = scaleDegree;
286 curDegree = scaleDegree;
290 performDegreeToKey { | degree, stepsPerOctave, accidental = 0 |
291 ^this.chooseScale(degree).performDegreeToKey(degree, stepsPerOctave, accidental);
295 performKeyToDegree { | degree, stepsPerOctave = 12 |
296 ^this.chooseScale(degree).performKeyToDegree(degree, stepsPerOctave)
299 performNearestInList { | degree |
300 ^this.chooseScale(degree).performNearestInList(degree)
303 performNearestInScale { | degree, stepsPerOctave=12 | // collection is sorted
304 ^this.chooseScale(degree).performNearestInScale(degree, stepsPerOctave)
310 classvar <scales, dirDoc;
314 Class.initClassTree(TuningInfo);
316 scales = IdentityDictionary[
318 // TWELVE TONES PER OCTAVE
320 \minorPentatonic -> Scale.new(#[0,3,5,7,10], 12, name: "Minor Pentatonic"),
321 \majorPentatonic -> Scale.new(#[0,2,4,7,9], 12, name: "Major Pentatonic"),
322 // another mode of major pentatonic
323 \ritusen -> Scale.new(#[0,2,5,7,9], 12, name: "Ritusen"),
324 // another mode of major pentatonic
325 \egyptian -> Scale.new(#[0,2,5,7,10], 12, name: "Egyptian"),
327 \kumoi -> Scale.new(#[0,2,3,7,9], 12, name: "Kumai"),
328 \hirajoshi -> Scale.new(#[0,2,3,7,8], 12, name: "Hirajoshi"),
329 \iwato -> Scale.new(#[0,1,5,6,10], 12, name: "Iwato"), // mode of hirajoshi
330 \chinese -> Scale.new(#[0,4,6,7,11], 12, name: "Chinese"), // mode of hirajoshi
331 \indian -> Scale.new(#[0,4,5,7,10], 12, name: "Indian"),
332 \pelog -> Scale.new(#[0,1,3,7,8], 12, name: "Pelog"),
334 \prometheus -> Scale.new(#[0,2,4,6,11], 12, name: "Prometheus"),
335 \scriabin -> Scale.new(#[0,1,4,7,9], 12, name: "Scriabin"),
337 // han chinese pentatonic scales
338 \gong -> Scale.new(#[0,2,4,7,9], 12, name: "Gong"),
339 \shang -> Scale.new(#[0,2,5,7,10], 12, name: "Shang"),
340 \jiao -> Scale.new(#[0,3,5,8,10], 12, name: "Jiao"),
341 \zhi -> Scale.new(#[0,2,5,7,9], 12, name: "Zhi"),
342 \yu -> Scale.new(#[0,3,5,7,10], 12, name: "Yu"),
346 \whole -> Scale.new((0,2..10), 12, name: "Whole Tone"),
347 \augmented -> Scale.new(#[0,3,4,7,8,11], 12, name: "Augmented"),
348 \augmented2 -> Scale.new(#[0,1,4,5,8,9], 12, name: "Augmented 2"),
350 // Partch's Otonalities and Utonalities
351 \partch_o1 -> Scale.new(#[0,8,14,20,25,34], 43,
352 Tuning.partch, "Partch Otonality 1"),
353 \partch_o2 -> Scale.new(#[0,7,13,18,27,35], 43,
354 Tuning.partch, "Partch Otonality 2"),
355 \partch_o3 -> Scale.new(#[0,6,12,21,29,36], 43,
356 Tuning.partch, "Partch Otonality 3"),
357 \partch_o4 -> Scale.new(#[0,5,15,23,30,37], 43,
358 Tuning.partch, "Partch Otonality 4"),
359 \partch_o5 -> Scale.new(#[0,10,18,25,31,38], 43,
360 Tuning.partch, "Partch Otonality 5"),
361 \partch_o6 -> Scale.new(#[0,9,16,22,28,33], 43,
362 Tuning.partch, "Partch Otonality 6"),
363 \partch_u1 -> Scale.new(#[0,9,18,23,29,35], 43,
364 Tuning.partch, "Partch Utonality 1"),
365 \partch_u2 -> Scale.new(#[0,8,16,25,30,36], 43,
366 Tuning.partch, "Partch Utonality 2"),
367 \partch_u3 -> Scale.new(#[0,7,14,22,31,37], 43,
368 Tuning.partch, "Partch Utonality 3"),
369 \partch_u4 -> Scale.new(#[0,6,13,20,28,38], 43,
370 Tuning.partch, "Partch Utonality 4"),
371 \partch_u5 -> Scale.new(#[0,5,12,18,25,33], 43,
372 Tuning.partch, "Partch Utonality 5"),
373 \partch_u6 -> Scale.new(#[0,10,15,21,27,34], 43,
374 Tuning.partch, "Partch Utonality 6"),
376 // hexatonic modes with no tritone
377 \hexMajor7 -> Scale.new(#[0,2,4,7,9,11], 12, name: "Hex Major 7"),
378 \hexDorian -> Scale.new(#[0,2,3,5,7,10], 12, name: "Hex Dorian"),
379 \hexPhrygian -> Scale.new(#[0,1,3,5,8,10], 12, name: "Hex Phrygian"),
380 \hexSus -> Scale.new(#[0,2,5,7,9,10], 12, name: "Hex Sus"),
381 \hexMajor6 -> Scale.new(#[0,2,4,5,7,9], 12, name: "Hex Major 6"),
382 \hexAeolian -> Scale.new(#[0,3,5,7,8,10], 12, name: "Hex Aeolian"),
385 \major -> Scale.new(#[0,2,4,5,7,9,11], 12, name: "Major"),
386 \ionian -> Scale.new(#[0,2,4,5,7,9,11], 12, name: "Ionian"),
387 \dorian -> Scale.new(#[0,2,3,5,7,9,10], 12, name: "Dorian"),
388 \phrygian -> Scale.new(#[0,1,3,5,7,8,10], 12, name: "Phrygian"),
389 \lydian -> Scale.new(#[0,2,4,6,7,9,11], 12, name: "Lydian"),
390 \mixolydian -> Scale.new(#[0,2,4,5,7,9,10], 12, name: "Mixolydian"),
391 \aeolian -> Scale.new(#[0,2,3,5,7,8,10], 12, name: "Aeolian"),
392 \minor -> Scale.new(#[0,2,3,5,7,8,10], 12, name: "Natural Minor"),
393 \locrian -> Scale.new(#[0,1,3,5,6,8,10], 12, name: "Locrian"),
395 \harmonicMinor -> Scale.new(#[0,2,3,5,7,8,11], 12, name: "Harmonic Minor"),
396 \harmonicMajor -> Scale.new(#[0,2,4,5,7,8,11], 12, name: "Harmonic Major"),
398 \melodicMinor -> Scale.new(#[0,2,3,5,7,9,11], 12, name: "Melodic Minor"),
399 \melodicMinorDesc -> Scale.new(#[0,2,3,5,7,8,10], 12,
400 name: "Melodic Minor Descending"),
401 \melodicMajor -> Scale.new(#[0,2,4,5,7,8,10], 12, name: "Melodic Major"),
403 \bartok -> Scale.new(#[0,2,4,5,7,8,10], 12, name: "Bartok"),
404 \hindu -> Scale.new(#[0,2,4,5,7,8,10], 12, name: "Hindu"),
407 \todi -> Scale.new(#[0,1,3,6,7,8,11], 12, name: "Todi"),
408 \purvi -> Scale.new(#[0,1,4,6,7,8,11], 12, name: "Purvi"),
409 \marva -> Scale.new(#[0,1,4,6,7,9,11], 12, name: "Marva"),
410 \bhairav -> Scale.new(#[0,1,4,5,7,8,11], 12, name: "Bhairav"),
411 \ahirbhairav -> Scale.new(#[0,1,4,5,7,9,10], 12, name: "Ahirbhairav"),
413 \superLocrian -> Scale.new(#[0,1,3,4,6,8,10], 12, name: "Super Locrian"),
414 \romanianMinor -> Scale.new(#[0,2,3,6,7,9,10], 12, name: "Romanian Minor"), \hungarianMinor -> Scale.new(#[0,2,3,6,7,8,11], 12, name: "Hungarian Minor"),
415 \neapolitanMinor -> Scale.new(#[0,1,3,5,7,8,11], 12, name: "Neapolitan Minor"),
416 \enigmatic -> Scale.new(#[0,1,4,6,8,10,11], 12, name: "Enigmatic"),
417 \spanish -> Scale.new(#[0,1,4,5,7,8,10], 12, name: "Spanish"),
419 // modes of whole tones with added note ->
420 \leadingWhole -> Scale.new(#[0,2,4,6,8,10,11], 12, name: "Leading Whole Tone"),
421 \lydianMinor -> Scale.new(#[0,2,4,6,7,8,10], 12, name: "Lydian Minor"),
422 \neapolitanMajor -> Scale.new(#[0,1,3,5,7,9,11], 12, name: "Neapolitan Major"),
423 \locrianMajor -> Scale.new(#[0,2,4,5,6,8,10], 12, name: "Locrian Major"),
426 \diminished -> Scale.new(#[0,1,3,4,6,7,9,10], 12, name: "Diminished"),
427 \diminished2 -> Scale.new(#[0,2,3,5,6,8,9,11], 12, name: "Diminished 2"),
430 \chromatic -> Scale.new((0..11), 12, name: "Chromatic"),
432 // TWENTY-FOUR TONES PER OCTAVE
434 \chromatic24 -> Scale.new((0..23), 24, name: "Chromatic 24"),
437 \ajam -> Scale.new(#[0,4,8,10,14,18,22], 24, name: "Ajam"),
438 \jiharkah -> Scale.new(#[0,4,8,10,14,18,21], 24, name: "Jiharkah"),
439 \shawqAfza -> Scale.new(#[0,4,8,10,14,16,22], 24, name: "Shawq Afza"),
442 \sikah -> Scale.new(#[0,3,7,11,14,17,21], 24, name: "Sikah"),
443 \sikahDesc -> Scale.new(#[0,3,7,11,13,17,21], 24, name: "Sikah Descending"),
444 \huzam -> Scale.new(#[0,3,7,9,15,17,21], 24, name: "Huzam"),
445 \iraq -> Scale.new(#[0,3,7,10,13,17,21], 24, name: "Iraq"),
446 \bastanikar -> Scale.new(#[0,3,7,10,13,15,21], 24, name: "Bastanikar"),
447 \mustar -> Scale.new(#[0,5,7,11,13,17,21], 24, name: "Mustar"),
450 \bayati -> Scale.new(#[0,3,6,10,14,16,20], 24, name: "Bayati"),
451 \karjighar -> Scale.new(#[0,3,6,10,12,18,20], 24, name: "Karjighar"),
452 \husseini -> Scale.new(#[0,3,6,10,14,17,21], 24, name: "Husseini"),
455 \nahawand -> Scale.new(#[0,4,6,10,14,16,22], 24, name: "Nahawand"),
456 \nahawandDesc -> Scale.new(#[0,4,6,10,14,16,20], 24, name: "Nahawand Descending"),
457 \farahfaza -> Scale.new(#[0,4,6,10,14,16,20], 24, name: "Farahfaza"),
458 \murassah -> Scale.new(#[0,4,6,10,12,18,20], 24, name: "Murassah"),
459 \ushaqMashri -> Scale.new(#[0,4,6,10,14,17,21], 24, name: "Ushaq Mashri"),
462 \rast -> Scale.new(#[0,4,7,10,14,18,21], 24, name: "Rast"),
463 \rastDesc -> Scale.new(#[0,4,7,10,14,18,20], 24, name: "Rast Descending"),
464 \suznak -> Scale.new(#[0,4,7,10,14,16,22], 24, name: "Suznak"),
465 \nairuz -> Scale.new(#[0,4,7,10,14,17,20], 24, name: "Nairuz"),
466 \yakah -> Scale.new(#[0,4,7,10,14,18,21], 24, name: "Yakah"),
467 \yakahDesc -> Scale.new(#[0,4,7,10,14,18,20], 24, name: "Yakah Descending"),
468 \mahur -> Scale.new(#[0,4,7,10,14,18,22], 24, name: "Mahur"),
471 \hijaz -> Scale.new(#[0,2,8,10,14,17,20], 24, name: "Hijaz"),
472 \hijazDesc -> Scale.new(#[0,2,8,10,14,16,20], 24, name: "Hijaz Descending"),
473 \zanjaran -> Scale.new(#[0,2,8,10,14,18,20], 24, name: "Zanjaran"),
476 \zanjaran -> Scale.new(#[0,2,8,10,14,16,22], 24, name: "Zanjaran"),
479 \saba -> Scale.new(#[0,3,6,8,12,16,20], 24, name: "Saba"),
480 \zamzam -> Scale.new(#[0,2,6,8,14,16,20], 24, name: "Zamzam"),
483 \kurd -> Scale.new(#[0,2,6,10,14,16,20], 24, name: "Kurd"),
484 \kijazKarKurd -> Scale.new(#[0,2,8,10,14,16,22], 24, name: "Kijaz Kar Kurd"),
487 \nawaAthar -> Scale.new(#[0,4,6,12,14,16,22], 24, name: "Nawa Athar"),
488 \nikriz -> Scale.new(#[0,4,6,12,14,18,20], 24, name: "Nikriz"),
489 \atharKurd -> Scale.new(#[0,2,6,12,14,16,22], 24, name: "Athar Kurd"),
492 // Ascending/descending scales
493 \melodicMinor -> ScaleAD(#[0,2,3,5,7,9,11], 12, #[0,2,3,5,7,8,10], name: "Melodic Minor"),
494 \sikah -> ScaleAD(#[0,3,7,11,14,17,21], 24, #[0,3,7,11,13,17,21], name: "Sikah"),
495 \nahawand -> ScaleAD(#[0,4,6,10,14,16,22], 24, #[0,4,6,10,14,16,20], name: "Nahawand"),
501 var res = scales[key];
502 ^res !? { res.deepCopy };
507 ^scales.values.select(selectFunc ? { true }).choose.deepCopy;
511 ^scales.keys.asArray.sort
514 var dirString = scales.keys.asArray.sort.collect({ |k|
515 "\\" ++ k ++ ": " ++ scales.at(k).name
519 Document.new("Tuning Directory", dirString)
520 .onClose_({ dirDoc.free; dirDoc = nil });
523 dirDoc.string = dirString;
530 classvar <tunings, dirDoc;
534 tunings = IdentityDictionary[
536 //TWELVE-TONE TUNINGS
537 \et12 -> Tuning.new((0..11), 2, "ET12"),
539 \pythagorean -> Tuning.new([1, 256/243, 9/8, 32/27, 81/64, 4/3, 729/512, 3/2,
540 128/81, 27/16, 16/9, 243/128].ratiomidi, 2, "Pythagorean"),
541 \just -> Tuning.new([1, 16/15, 9/8, 6/5, 5/4, 4/3, 45/32, 3/2, 8/5, 5/3,
542 9/5, 15/8].ratiomidi, 2, "5-Limit Just Intonation"),
543 \sept1 -> Tuning.new([1, 16/15, 9/8, 6/5, 5/4, 4/3, 7/5, 3/2, 8/5, 5/3,
544 9/5, 15/8].ratiomidi, 2, "Septimal Tritone Just Intonation"),
545 \sept2 -> Tuning.new([1, 16/15, 9/8, 6/5, 5/4, 4/3, 7/5, 3/2, 8/5, 5/3,
546 7/4, 15/8].ratiomidi, 2, "7-Limit Just Intonation"),
547 \mean4 -> Tuning.new(#[0, 0.755, 1.93, 3.105, 3.86, 5.035, 5.79, 6.965,
548 7.72, 8.895, 10.07, 10.82], 2, "Meantone, 1/4 Syntonic Comma"),
549 \mean5 -> Tuning.new(#[0, 0.804, 1.944, 3.084, 3.888, 5.028, 5.832, 6.972,
550 7.776, 8.916, 10.056, 10.86], 2, "Meantone, 1/5 Pythagorean Comma"),
551 \mean6 -> Tuning.new(#[0, 0.86, 1.96, 3.06, 3.92, 5.02, 5.88, 6.98, 7.84,
552 8.94, 10.04, 10.9], 2, "Meantone, 1/6 Pythagorean Comma"),
553 \kirnberger -> Tuning.new([1, 256/243, (5.sqrt)/2, 32/27, 5/4, 4/3,
554 45/32, 5 ** 0.25, 128/81, (5 ** 0.75)/2, 16/9, 15/8].ratiomidi, 2,
556 \werckmeister -> Tuning.new(#[0, 0.92, 1.93, 2.94, 3.915, 4.98, 5.9, 6.965,
557 7.93, 8.895, 9.96, 10.935], 2, "Werckmeister III"),
558 \vallotti -> Tuning.new(#[0, 0.94135, 1.9609, 2.98045, 3.92180, 5.01955,
559 5.9218, 6.98045, 7.9609, 8.94135, 10, 10.90225], 2, "Vallotti"),
560 \young -> Tuning.new(#[0, 0.9, 1.96, 2.94, 3.92, 4.98, 5.88, 6.98, 7.92,
561 8.94, 9.96, 10.9], 2, "Young"),
562 \reinhard -> Tuning.new([1, 14/13, 13/12, 16/13, 13/10, 18/13, 13/9,
563 20/13, 13/8, 22/13, 13/7, 208/105].ratiomidi, 2, "Mayumi Reinhard"),
564 \wcHarm -> Tuning.new([1, 17/16, 9/8, 19/16, 5/4, 21/16, 11/8, 3/2, 13/8,
565 27/16, 7/4, 15/8].ratiomidi, 2, "Wendy Carlos Harmonic"),
566 \wcSJ -> Tuning.new([1, 17/16, 9/8, 6/5, 5/4, 4/3, 11/8, 3/2, 13/8, 5/3,
567 7/4, 15/8].ratiomidi, 2, "Wendy Carlos Super Just"),
569 //MORE THAN TWELVE-TONE ET
570 \et19 -> Tuning.new((0 .. 18) * 12/19, 2, "ET19"),
571 \et22 -> Tuning.new((0 .. 21) * 6/11, 2, "ET22"),
572 \et24 -> Tuning.new((0 .. 23) * 0.5, 2, "ET24"),
573 \et31 -> Tuning.new((0 .. 30) * 12/31, 2, "ET31"),
574 \et41 -> Tuning.new((0 .. 40) * 12/41, 2, "ET41"),
575 \et53 -> Tuning.new((0 .. 52) * 12/53, 2, "ET53"),
578 \johnston -> Tuning.new([1, 25/24, 135/128, 16/15, 10/9, 9/8, 75/64, 6/5,
579 5/4, 81/64, 32/25, 4/3, 27/20, 45/32, 36/25, 3/2, 25/16, 8/5, 5/3,
580 27/16, 225/128, 16/9, 9/5, 15/8, 48/25].ratiomidi, 2, "Ben Johnston"),
581 \partch -> Tuning.new([1, 81/80, 33/32, 21/20, 16/15, 12/11, 11/10, 10/9, 9/8,
582 8/7, 7/6, 32/27, 6/5, 11/9, 5/4, 14/11, 9/7, 21/16, 4/3, 27/20, 11/8,
583 7/5, 10/7, 16/11, 40/27, 3/2, 32/21, 14/9, 11/7, 8/5, 18/11, 5/3, 27/16,
584 12/7, 7/4, 16/9, 9/5, 20/11, 11/6, 15/8, 40/21, 64/33, 160/81].ratiomidi, 2,
586 \catler -> Tuning.new([1, 33/32, 16/15, 9/8, 8/7, 7/6, 6/5, 128/105, 16/13,
587 5/4, 21/16, 4/3, 11/8, 45/32, 16/11, 3/2, 8/5, 13/8, 5/3, 27/16, 7/4,
588 16/9, 24/13, 15/8].ratiomidi, 2, "Jon Catler"),
589 \chalmers -> Tuning.new([1, 21/20, 16/15, 9/8, 7/6, 6/5, 5/4, 21/16, 4/3, 7/5,
590 35/24, 3/2, 63/40, 8/5, 5/3, 7/4, 9/5, 28/15, 63/32].ratiomidi, 2,
592 \harrison -> Tuning.new([1, 16/15, 10/9, 8/7, 7/6, 6/5, 5/4, 4/3, 17/12, 3/2,
593 8/5, 5/3, 12/7, 7/4, 9/5, 15/8].ratiomidi, 2, "Lou Harrison"),
594 \sruti -> Tuning.new([1, 256/243, 16/15, 10/9, 9/8, 32/27, 6/5, 5/4, 81/64,
595 4/3, 27/20, 45/32, 729/512, 3/2, 128/81, 8/5, 5/3, 27/16, 16/9, 9/5,
596 15/8, 243/128].ratiomidi, 2, "Sruti"),
598 //HARMONIC SERIES -- length arbitary
599 \harmonic -> Tuning.new((1 .. 24).ratiomidi, 2, "Harmonic Series 24"),
601 //STRETCHED/SHRUNK OCTAVE
603 \bp -> Tuning.new((0 .. 12) * (3.ratiomidi/13), 3.0, "Bohlen-Pierce"),
605 \wcAlpha -> Tuning.new((0 .. 14) * 0.78, (15 * 0.78).midiratio, "Wendy Carlos Alpha"),
606 \wcBeta -> Tuning.new((0 .. 18) * 0.638, (19 * 0.638).midiratio, "Wendy Carlos Beta"),
607 \wcGamma -> Tuning.new((0 .. 33) * 0.351, (34 * 0.351).midiratio,
608 "Wendy Carlos Gamma")
614 *choose { |selectFunc|
615 ^tunings.values.select(selectFunc ? { true }).choose;
619 ^tunings.keys.asArray.sort
623 var res = tunings[key];
624 ^res !? { res.deepCopy };
628 var dirString = tunings.keys.asArray.sort.collect({ |k|
629 "\\" ++ k ++ ": " ++ tunings.at(k).name
633 Document.new("Tuning Directory", dirString)
634 .onClose_({ dirDoc.free; dirDoc = nil });
637 dirDoc.string = dirString;