A class or method to convert integer and float to scientific pitch notation?

@nathan @VIRTUALDOG @smoge
Thanks for your valuable opinions. I asked this question to be able to use these classes and methods, if they exist, to create music scores simply by constructing subclasses of the collection class, as introduced in the following post (One problem is that musicXML only seems to support quarter-tones at the moment. This would exclude other microtonal accidentals, although I would like to extend it at least up to sixteenth-tones.):

@semiquaver @jordan @josh

I have updated the methods suggested above a bit, added a new class SPN, and done my best to cover all your opinions as best I can:

  • Now sclang returns pitch names as an array containing all available pitch names. Please let me know if I missed anything.
  • SPN has three options for displaying the pitch name: \lily, \mus, and \ez. The default is \lily.
  • PitchClass is already in @josh’s Ctk Quarks, but my new methods for this class do not conflict with it. Also, my PitchClass supports quartertones. I would appreciate your opinion. I have not made a PR as I think it should be discussed before it is made.

@semiquaver
Thanks for pointing this out!

Yes! Thus, I implemented various notations!

Scientific pitch notation is a verbal expression, so the use of the Roman numeral to indicate the steps of a scale has nothing to do with it.
Anyway, what does 3 mean in .inkey('c#', \minor, 3)? Is it the octave number? Normally, a key name starting with an upper-case letter indicates a major key, and a key name starting with a lower-case letter indicates a minor key. So the second argument in .inkey() is not necessary if .inKey is only related to major-minor tonality. I have not been able to find the .inKey method, so I cannot say more at this time.

Using \a3 in events without .cps is a really good idea.

@jordan

  1. I have included LilyPond’s format for those users who are already used to LilyPond’s notation, although I am not sure how many SC users (especially beginners) are used to LilyPond’s pitch notation. I deliberately did not use LilyPond style pitch notation because it uses multiple characters for one accidental. The English naming system in LilyPond is not intuitive to me. The German naming system in LilyPond is very intuitive to me, but it is too long. The following are my own inventions (they are simpler than the LilyPond style):

    1. Example 1 (currently used):
      • S: double-sharp
      • Q: three quarter-tone raised
      • s: sharp
      • q: quarter-tone raised
      • n: natural ← can be omitted
      • u: quarter-tone lowered is not used
      • f: flat
      • U: three quarter-tone lowered is not used
      • F: double-flat
    2. Example 2:
      • S: double-sharp
      • R: three quarter-tone raised
      • r: sharp
      • n: quarter-tone raised
      • o: natural ← can be omitted
      • l: quarter-tone lowered
      • f: flat
      • L: three quarter-tone lowered
      • F: double-flat
    3. Example 3:
      • S: double-sharp
      • M: three quarter-tone raised
      • s: sharp
      • m: quarter-tone raised
      • o: natural ← can be omitted
      • w: quarter-tone lowered
      • f: flat
      • W: three quarter-tone lowered
      • F: double-flat
    4. Example 4:
      • M: double-sharp
      • m: three quarter-tone raised
      • N: sharp
      • n: quarter-tone raised
      • o: natural ← can be omitted
      • v: quarter-tone lowered
      • V: flat
      • w: three quarter-tone lowered
      • W: double-flat
  2. There are different systems for naming pitches.
    In wslib’s cpsname, the middle A (440 Hz) is A3, while the ‘Scientific Pitch Notation’ defines it as A4. In South Korea, I am used to 440 Hz as A3 with the earlier generations involved in computer music, A4 in the group of musicians and music theorists as well as your generation in the computer music field, and in Germany as a' or a1. I think A4 is generally easier for most musicians, especially in English-speaking cultures and perhaps most of the world. In computer music, A3 seems to have been widely used for 440 Hz before, but I see that many software programs offer both names (A3 and A4) according to the user’s preference. I am also familiar with Helmholz pitch notation, but this would not be considered.

@josh
In the first draft, I omitted all pitch names with flats because they are redundant under some conditions. Under other conditions, however, they are very important. Under other conditions double flats and double sharps, even triple sharps and triple flats should be considered. I just wanted to simplify these things…

I think such pitch names should be added if some users or developers think they should be there. So I did it. If I just add all the flat names, someone might ask how to get double-flatted pitch and double-sharped pitch etc. So I upload a version that includes all possibilities (N.B.: This time I also used musical symbols to improve readability, but I am not sure if it really improves readability.):

Overview of use:
(The definitions of the methods and classes are at the bottom of the post.)

\df4.midi // -> 61.0
\cs4.midi // -> 61.0
\df4.cps  // -> 277.18263097687
\cs4.cps  // -> 277.18263097687

PitchClass.lily[1] // -> [ cs, df, bx ]
PitchClass.mus[1]  // -> [ c♯, d♭, b𝄪 ]
PitchClass.ez[1]   // -> [ cs, df, bS ]
1.pitchClass // -> [ cs, df, bx, c♯, d♭, b𝄪, cs, df, bS ]

PitchClass.lily[\t] // -> [ as, bf, cff ]

PitchClass.lily['t.5'] // -> [ bqf, atqs, ctqf, cffqs ]
PitchClass.lily[\t5]   // -> [ bqf, atqs, ctqf, cffqs ]


0.midispn    // -> [ c-1, bs-2, dff-1 ]
'c-1'.midi   // -> 0.0
\cm1.midi    // -> 0.0
'bs-2'.midi  // -> 0.0
'dff-1'.midi // -> 0.0
\bsm2.midi   // -> 0.0
\dffm1.midi  // -> 0.0

8.1757989156437.cpsspn // -> [ c-1, bs-2, dff-1 ]
'c-1'.cps              // -> 8.1757989156437
\cm1.cps               // -> 8.1757989156437
'bs-2'.cps             // -> 8.1757989156437
'dff-1'.cps            // -> 8.1757989156437
\bsm2.cps              // -> 8.1757989156437
\dffm1.cps             // -> 8.1757989156437

127.midispn        // -> [ g9, fx9, aff9 ]
127.midispn(\lily) // -> [ g9, fx9, aff9 ]
127.midispn(\mus)  // -> [ g♮9, f𝄪9, a𝄫9 ]
127.midispn(\ez)   // -> [ gn9, g9, fS9, aF9 ]

SPN.cps(440)        // -> [ a4, gx4, bff4 ]
SPN.cps(440, \lily) // -> [ a4, gx4, bff4 ]
SPN.cps(440, \mus)  // -> [ a♮4, g𝄪4, b𝄫4 ]
SPN.cps(440, \ez)   // -> [ an4, a4, gS4, bF4 ]

SPN.midi(69)        // -> [ a4, gx4, bff4 ]
SPN.midi(69, \lily) // -> [ a4, gx4, bff4 ]
SPN.midi(69, \mus)  // -> [ a♮4, g𝄪4, b𝄫4 ]
SPN.midi(69, \ez)   // -> [ an4, a4, gS4, bF4 ]

69.5.midispn        // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
69.5.midispn(\lily) // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
69.5.midispn(\mus)  // -> [ a ¼↑ 4, b♭ ¼↓ 4, a♯ ¼↓ 4, g𝄪 ¼↑ 4, b𝄫 ¼↑ 4, c𝄫 ¼↓5 ]
69.5.midispn(\ez)   // -> [ aq4, bU4, gSq4, bFq4, cFu5 ]

452.89298412314.cpsspn        // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
452.89298412314.cpsspn(\lily) // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
452.89298412314.cpsspn(\mus)  // -> [ a ¼↑ 4, b♭ ¼↓ 4, a♯ ¼↓ 4, g𝄪 ¼↑ 4, b𝄫 ¼↑ 4, c𝄫 ¼↓5 ]
452.89298412314.cpsspn(\ez)   // -> [ aq4, bU4, gSq4, bFq4, cFu5 ]

Post <<< PitchClass.lily
PitchClass.lily.class
PitchClass.lily.size
PitchClass.lily.do { |item| item.postln }

Post <<< PitchClass.mus
PitchClass.mus.class
PitchClass.mus.size
PitchClass.mus.do { |item| item.postln }

Post <<< PitchClass.ez
PitchClass.ez.class
PitchClass.ez.size
PitchClass.ez.do { |item| item.postln }

PitchClass.lily[0.0]
PitchClass.lily[0]
PitchClass.lily[0.5]
PitchClass.lily[1]

(
((0, 0.5 .. 9.5) ++ [10.0, \t, 10.5, \t5, 't.5', 11.0, \e, 11.5, \e5, 'e.5'] ++ (0..11)).do { |index|
	(index.asString ++ ":" + PitchClass.lily[index]).postln;
	(index.asString ++ ":" + PitchClass.mus[index]).postln; 
	(index.asString ++ ":" + PitchClass.ez[index]).postln;
	"".postln
}
)

(s.sampleRate / 2).cpsspn
(s.sampleRate / 2).cpsspn(\lily)
(s.sampleRate / 2).cpsspn(\mus)
(s.sampleRate / 2).cpsspn(\ez)

(
(100, 105 .. 230).sort.do { |index|
	(index.asString + "Hz:\tMIDI pitch                -" + index.cpsmidi ++ ";\n\t\tMIDI Pitch rounded at 0.5 -" + index.cpsmidi.round(0.5) + "\n\t\t\t\t   lily (default) -" + SPN.cps(index, \lily)).postln;
	("\t\t\t\t   music          -" + SPN.cps(index, \mus)).postln; 
	("\t\t\t\t   ez             -" + SPN.cps(index, \ez)).postln;
	"".postln
}
)

(
((0..127) ++ (0, 0.5 ..127)).sort.do { |index|
	("MIDI Pitch Number" + index.asString ++ ": (lily, default) -" + SPN.midi(index, \lily)).postln;
	("MIDI Pitch Number" + index.asString ++ ": (music)         -" + SPN.midi(index, \mus)).postln; 
	("MIDI Pitch Number" + index.asString ++ ": (ez)            -" + SPN.midi(index, \ez)).postln;
	"".postln
}
)

SPN.cps(261.6255653006)      // -> [ c4, bs3, dff4 ]
261.6255653006.cpsspn        // -> [ c4, bs3, dff4 ]
261.6255653006.cpsspn(\lily) // -> [ c4, bs3, dff4 ]
261.6255653006.cpsspn(\mus)  // -> [ c♮4, b♯3, d𝄫4 ]
261.6255653006.cpsspn(\ez)   // -> [ cn4, c4, bs3, dF4 ]

SPN.midi(60)           // -> [ c4, bs3, dff4 ]
60.0.midispn           // -> [ c4, bs3, dff4 ]
60.0.midispn(\lily)    // -> [ c4, bs3, dff4 ]
60.0.midispn(\mus)     // -> [ c♮4, b♯3, d𝄫4 ]
60.0.midispn(\ez)      // -> [ cn4, c4, bs3, dF4 ]

261.6255653006.cpsmidi // -> 60.0
\c4.midi               // -> 60.0
\bs3.midi              // -> 60.0
\dff4.midi             // -> 60.0
'c♮4'.midi             // -> 60.0
'b♯3'.midi             // -> 60.0
'd𝄫4'.midi             // -> 60.0
\cn4.midi              // -> 60.0
\c4.midi               // -> 60.0
\bs3.midi              // -> 60.0
\dF4.midi              // -> 60.0

60.midicps // -> 261.6255653006
\c4.cps    // -> 261.6255653006
\bs3.cps   // -> 261.6255653006
\dff4.cps  // -> 261.6255653006
'c♮4'.cps  // -> 261.6255653006
'b♯3'.cps  // -> 261.6255653006
'd𝄫4'.cps  // -> 261.6255653006
\cn4.cps   // -> 261.6255653006

277.18263097687.cpsspn // -> [ cs4, df4, bx3 ]
\cs4.cps               // -> 277.18263097687
\df4.cps               // -> 277.18263097687
\bx3.cps               // -> 277.18263097687

61.0.midispn // -> [ cs4, df4, bx3 ]
\cs4.midi    // -> 61.0
\df4.midi    // -> 61.0
\bx3.midi    // -> 61.0

SPN.midi(69.5)        // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ] 
69.5.midispn          // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
SPN.midi(69.5, \lily) // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
69.5.midispn(\lily)   // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
SPN.midi(69.5, \mus)  // -> [ a ¼↑ 4, b♭ ¼↓ 4, a♯ ¼↓ 4, g𝄪 ¼↑ 4, b𝄫 ¼↑ 4, c𝄫 ¼↓5 ]
69.5.midispn(\mus)    // -> [ a ¼↑ 4, b♭ ¼↓ 4, a♯ ¼↓ 4, g𝄪 ¼↑ 4, b𝄫 ¼↑ 4, c𝄫 ¼↓5 ]
SPN.midi(69.5, \ez)   // -> [ aq4, bU4, gSq4, bFq4, cFu5 ]
69.5.midispn(\ez)     // -> [ aq4, bU4, gSq4, bFq4, cFu5 ]

69.5.midicps                    // -> 452.89298412314
SPN.cps(452.89298412314)        // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
452.8929841231.cpsspn           // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
SPN.cps(452.89298412314, \lily) // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
452.8929841231.cpsspn(\lily)    // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
SPN.cps(452.89298412314, \mus)  // -> [ a ¼↑ 4, b♭ ¼↓ 4, a♯ ¼↓ 4, g𝄪 ¼↑ 4, b𝄫 ¼↑ 4, c𝄫 ¼↓5 ]
452.8929841231.cpsspn(\mus)     // -> [ a ¼↑ 4, b♭ ¼↓ 4, a♯ ¼↓ 4, g𝄪 ¼↑ 4, b𝄫 ¼↑ 4, c𝄫 ¼↓5 ]
SPN.cps(452.89298412314, \ez)   // -> [ aq4, bU4, gSq4, bFq4, cFu5 ]
452.89298412314.cpsspn(\ez)     // -> [ aq4, bU4, gSq4, bFq4, cFu5 ]

A new class with some methods and new methods for some classes:

SPN : Notator {
	*prEzForOctave {
		^PitchClass.prEzOctaveLowerPart
		++ PitchClass.prEzCommonPart
		++ PitchClass.prEzOctaveHigherPart
	}
	*prLilyForOctave {
		^PitchClass.prLilyOctaveLowerPart
		++ PitchClass.prLilyCommonPart
		++ PitchClass.prLilyOctaveHigherPart
	}
	*prMusForOctave {
		^PitchClass.prMusicSymbolOctaveLowerPart
		++ PitchClass.prMusicSymbolCommonPart
		++ PitchClass.prMusicSymbolOctaveHigherPart
	}
	*prParseOctave {
		arg aPitchClassAsSymbol, octave;
		var aPitchClassAsString, result;
		aPitchClassAsString = aPitchClassAsSymbol.asString;
		result = if (aPitchClassAsString[aPitchClassAsString.size - 1] == $h) {
			aPitchClassAsString[.. aPitchClassAsString.size - 2] ++ (octave.asInteger + 1)
		} {
			if (aPitchClassAsString[aPitchClassAsString.size - 1] == $l) {
				aPitchClassAsString[.. aPitchClassAsString.size - 2] ++ (octave.asInteger - 1)
			}
			{
				aPitchClassAsSymbol ++ octave.asInteger
			}
		};
		^result
	}
	*prMapToOctave {
		arg enharmonicQuarterToneDictionaryOfPitchClasses, midiPitch;
		var octave = (midiPitch / 12).floor - 1;
		^enharmonicQuarterToneDictionaryOfPitchClasses.collect { |aPitchClassAsSymbol|
			SPN.prParseOctave(aPitchClassAsSymbol, octave)
		}
	}
	*prDetectBInLowerOctave {
		arg pitchClass, octave;
		octave = if ("bs|bQ|bSu|bS|bSq|bs|btqs|bxqf|bx|bxqs|b♯|b♯ ¼↑|b𝄪 ¼↓|b𝄪|b𝄪 ¼↑".matchRegexp(pitchClass.asString)) {
			octave + 1
		} {
			octave
		};
		^octave
	}
	*prDetectPitchClassOctave {
		arg pitchName;
		var pitchNameAsString, size, pitchClass, octave;
		pitchNameAsString = pitchName.asString;
		size = pitchNameAsString.size;
		# pitchClass, octave = if (pitchNameAsString[size - 2] == $- || (pitchNameAsString[size - 2] == $m)) {

			[pitchNameAsString[0 .. size - 3].asSymbol, pitchNameAsString[size -1].asString.asInteger * -1]
		} {
			[pitchNameAsString[0 .. size - 2].asSymbol, pitchNameAsString[size -1].asString.asInteger]
		}
		^[pitchClass, SPN.prDetectBInLowerOctave(pitchClass, octave)]
	}
	*getValue {
		arg which, mappingSwitch;
		var pitchClass, octave, pitchClassSets, pitchClassKey, midiPitchNumber;
		pitchClassSets = PitchClass.lily.collect { |item, index|
			item ++ PitchClass.ez[index] ++ PitchClass.mus[index] };
		# pitchClass, octave = SPN.prDetectPitchClassOctave(which);
		pitchClassSets.do { |pitchClassSet|
			if (pitchClassSet.includes(pitchClass)) {
				pitchClassKey = pitchClassSets.findKeyForValue(pitchClassSet).asString.replace("t", "10").replace("e", "11").interpret
			}
		};
		midiPitchNumber = (octave + 1) * 12 + pitchClassKey;
		^switch(mappingSwitch,
			\cps, { midiPitchNumber.midicps },
			\midi, { midiPitchNumber.asFloat }
		)
	}
	*prStyle { arg style;
		^switch(style,
			\ez, { SPN.prEzForOctave },
			\lily, { SPN.prLilyForOctave },
			\mus, { SPN.prMusForOctave }
		)
	}
	*midi {
		arg midiPitch, style = \lily;
		var enharmonicQuarterToneDictionaryOfPitchClasses = SPN.prStyle(style)[midiPitch.round(0.5) * 2 % 24];
		^SPN.prMapToOctave(enharmonicQuarterToneDictionaryOfPitchClasses, midiPitch)
	}
	*cps {
		arg freq, style = \lily;
		var enharmonicQuarterToneDictionaryOfPitchClasses = SPN.prStyle(style)[freq.cpsmidi.round(0.5) * 2 % 24];
		^SPN.prMapToOctave(enharmonicQuarterToneDictionaryOfPitchClasses, freq.cpsmidi)
	}
}

+ PitchClass {
	*prMake {
		arg quarterToneScale;
		var result;
		result = quarterToneScale.collectAs({ |pitchClass, index|
			var key, keyAsString, keySizeAsString;
			key = index / 2;
			key-> pitchClass }, IdentityDictionary);

		// adding integer
		(0..11).do { |i|
			result.add(i -> result[i.asFloat]);
		};

		// adding \t, \t5, 't.5', \e, \e5 and 'e.5'
		result.add(\t -> result[10]);
		result.add('t.5' -> result[10.5]);
		result.add(\t5 -> result[10.5]);
		result.add(\e -> result[11]);
		result.add('e.5' -> result[11.5]);
		result.add(\e5 -> result[11.5]);
		^result // 24 + 12 + 6 = 42
	}
	*prEzCommonPart {
		^[
			['dn',		'd',											'cS',		'eF'	],
			['dq',					'eU',					'fFu',		'cSq',		'eFq'	],
			['ds',		'ef',								'fF'							],
			['eu',					'dQ',		'fU',		'fFq'							],
			['en',		'e',		'ff',								'dS'				],
			['eq',		'fu',								'dSq',		'gFu'				],
			['fn',		'f',		'es',								'gF'				],
			['fq',		'eQ',					'gU',		'gFq',		'eSu'				],
			['fs',		'gf',								'eS'							],
			['gu',		'fQ',								'eSq',		'fSu',		'aFu'	],
			['gn',		'g',											'fS',		'aF'	],
			['gq',		'aU',								'fSq',		'aFq'				],
			['gs',		'af'																],
			['au',		'gQ',								'gSu',		'bFu'				],
			['an',		'a',											'gS',		'bF'	]
		]
	}
	*prEzClassLowerPart {
		^[
			['cn',		'c',		'bs',								'dF'				],
			['cq',					'bQ',		'dU',		'dFq',		'bSu'				],
			['cs',		'df',								'bS'							],
			['du',					'cQ',					'bSq',		'cSu',		'eFu'	]
		]
	}
	*prEzClassHigherPart {
		^[
			['aq',		'bU',								'gSq',		'bFq',		'cFu'	],
			['as',		'bf',								'cF'							],
			['bu',		'aQ',					'cU',		'cFq'							],
			['bn',		'b',											'aS',		'cf'	],
			['bq',		'cu',								'aSq',		'dFu'				]
		]
	}
	*prEzOctaveLowerPart	{
		^[
			['cn',		'c',		'bsl',								'dF'				],
			['cq',					'bQl',		'dU',		'dFq',		'bSul'				],
			['cs',		'df',								'bSl'							],
			['du',					'cQ',					'bSql',		'cSu',		'eFu'	]
		]
	}
	*prEzOctaveHigherPart{
		^[
			['aq',		'bU',								'gSq',		'bFq',		'cFuh'	],
			['as',		'bf',								'cFh'							],
			['bu',		'aQ',					'cUh',		'cFqh'							],
			['bn',		'b',											'aS',		'cfh'	],
			['bq',		'cuh',								'aSq',		'dFuh'				]
		]
	}
	*ez {
		var quarterToneScale;
		quarterToneScale = PitchClass.prEzClassLowerPart
		++ PitchClass.prEzCommonPart
		++ PitchClass.prEzClassHigherPart;
		^PitchClass.prMake(quarterToneScale)
	}
	*prLilyCommonPart {
		^[
			['d',											'cx',		'eff'				],
			['dqs',					'etqf',					'fffqf',	'cxqs',		'effqs'	],
			['ds',		'ef',								'fff'							],
			['eqf',					'dtqs',		'ftqf',		'fffqs'							],
			['e',		'ff',								'dx'							],
			['eqs',		'fqf',								'dxqs',		'gffqf'				],
			['f',		'es',								'gff'							],
			['fqs',		'etqs',					'gtqf',		'gffqs',	'exqf'				],
			['fs',		'gf',								'ex'							],
			['gqf',		'ftqs',								'exqs',		'fxqf',		'affqf'	],
			['g',											'fx',		'aff'				],
			['gqs',		'atqf',								'fxqs',		'affqs'				],
			['gs',		'af'																],
			['aqf',		'gtqs',								'gxqf',		'bffqf'				],
			['a',											'gx',		'bff'				]
		]
	}
	*prLilyClassLowerPart {
		^[
			['c',		'bs',								'dff'							],
			['cqs',					'btqs',		'dtqf',		'dffqs',	'bxqf'				],
			['cs',		'df',								'bx'							],
			['dqf',					'ctqs',					'bxqs',		'cxqf',		'effqf'	]
		]
	}
	*prLilyClassHigherPart {
		^[
			['aqs',		'btqf',								'gxqs',		'bffqs',	'cffqf'	],
			['as',		'bf',								'cff'							],
			['bqf',		'atqs',					'ctqf',		'cffqs'							],
			['b',											'ax',		'cf'				],
			['bqs',		'cqf',								'axqs',		'dffqf'				]
		]
	}
	*prLilyOctaveLowerPart {
		^[
			['c',		'bsl',								'dff'							],
			['cqs',					'btqsl',	'dtqf',		'dffqs',		'bxqfl'			],
			['cs',		'df',								'bxl'							],
			['dqf',					'ctqs',					'bxqsl',	'cxqf',		'effqf'	]
		]
	}
	*prLilyOctaveHigherPart {
		^[
			['aqs',		'btqf',								'gxqs',		'bffqs',	'cffqfh'],
			['as',		'bf',								'cffh'							],
			['bqf',		'atqs',					'ctqfh',	'cffqsh'						],
			['b',											'ax',		'cfh'				],
			['bqs',		'cqfh',								'axqs',		'dffqfh'			]
		]
	}
	*lily {
		var quarterToneScale;
		quarterToneScale = PitchClass.prLilyClassLowerPart
		++ PitchClass.prLilyCommonPart
		++ PitchClass.prLilyClassHigherPart;
		^PitchClass.prMake(quarterToneScale)
	}
	*prMusicSymbolCommonPart {
		^[
			['d♮',								'c𝄪',		'e𝄫'							],
			['d ¼↑ ',	'd♯ ¼↓ ',	'e♭ ¼↓ ',				'f𝄫 ¼↓ ',	'c𝄪 ¼↑ ',		'e𝄫 ¼↑ '	],
			['d♯',		'e♭',								'f𝄫'							],
			['e♮ ¼↓ ',	'e♭ ¼↑ ',	'd♯ ¼↑ ',	'f♭ ¼↓ '	,	'f𝄫 ¼↑ '							],
			['e♮',		'f♭',								'd𝄪'								],
			['e ¼↑ ',	'f ¼↓ ', 	'f♭ ¼↑ ',	'e♯ ¼↓ ',	'd𝄪 ¼↑ ',		'g𝄫 ¼↓ '				],
			['f♮',		'e♯',								'g𝄫'							],
			['f ¼↑ ',	'e♯ ¼↑ ',	'f♯ ¼↓ ',	'g♭ ¼↓ ',	'g𝄫 ¼↑ ',	'e𝄪 ¼↓ '				],
			['f♯',		'g♭',								'e𝄪'								],
			['g ¼↓ ',	'f♯ ¼↑ ',	'g♭ ¼↑ ',	'e𝄪 ¼↑ ',		'f𝄪 ¼↓ ',		'a𝄫 ¼↓ '				],
			['g♮',											'f𝄪',		'a𝄫'				],
			['g ¼↑ ',	'a♭ ¼↓ ',	'g♯ ¼↓ ',							'f𝄪 ¼↑ ',		'a𝄫 ¼↑ '	],
			['g♯',		'a♭'																],
			['a ¼↓ ',	'g♯ ¼↑ ',	'a♭ ¼↑ ',				'g𝄪 ¼↓ ',		'b𝄫 ¼↓ '				],
			['a♮',											'g𝄪',		'b𝄫'				]
		]
	}
	*prMusicSymbolClassLowerPart {
		^[
			['c♮',		'b♯',								'd𝄫'							],
			['c ¼↑ ',	'c♯ ¼↓ ',	'b♯ ¼↑ ',	'd♭ ¼↓ ',	'd𝄫 ¼↑ ',	'b𝄪 ¼↓ '				],
			['c♯',		'd♭',								'b𝄪'								],
			['d ¼↓ ',	'd♭ ¼↑ ',	'c♯ ¼↑ ',				'b𝄪 ¼↑ ',		'c𝄪 ¼↓ ',		'e𝄫 ¼↓ '	]
		]
	}
	*prMusicSymbolClassHigherPart {
		^[
			['a ¼↑ ',	'b♭ ¼↓ ',	'a♯ ¼↓ ',	'g𝄪 ¼↑ ',		'b𝄫 ¼↑ ',	'c𝄫 ¼↓ '				],
			['a♯',		'b♭',								'c𝄫'							],
			['b ¼↓ ',	'a♯ ¼↑ ',	'b♭ ¼↑ ',	'c♭ ¼↓ ',	'c𝄫 ¼↑ '							],
			['b♮',											'a𝄪',		'c♭'				],
			['b ¼↑ ',	'c ¼↓ ',		'c♭ ¼↑ ',	'b♯ ¼↓ ',	'a𝄪 ¼↑ ',		'd𝄫 ¼↓ '				]
		]
	}
	*prMusicSymbolOctaveLowerPart {
		^[
			['c♮',		'b♯l',								'd𝄫'							],
			['c ¼↑ ',	'c♯ ¼↓ ',	'b♯ ¼↑l',	'd♭ ¼↓ ',	'd𝄫 ¼↑ ',	'b𝄪 ¼↓l'				],
			['c♯',		'd♭',								'b𝄪l'							],
			['d ¼↓ ',	'd♭ ¼↑ ',	'c♯ ¼↑ ',				'b𝄪 ¼↑l',	'c𝄪 ¼↓ ',		'e𝄫 ¼↓ '	]
		]
	}
	*prMusicSymbolOctaveHigherPart {
		^[
			['a ¼↑ ',	'b♭ ¼↓ ',	'a♯ ¼↓ ',	'g𝄪 ¼↑ ',		'b𝄫 ¼↑ ',	'c𝄫 ¼↓h'			],
			['a♯',		'b♭',								'c𝄫h'							],
			['b ¼↓ ',	'a♯ ¼↑ ',	'b♭ ¼↑ ',	'c♭ ¼↓h',	'c𝄫 ¼↑h'						],
			['b♮',											'a𝄪',		'c♭h'				],
			['b ¼↑ ',	'c ¼↓h',	'c♭ ¼↑h',	'b♯ ¼↓ ',	'a𝄪 ¼↑ ',		'd𝄫 ¼↓h'			]
		]
	}
	*mus {
		var quarterToneScale;
		quarterToneScale = PitchClass.prMusicSymbolClassLowerPart
		++ PitchClass.prMusicSymbolCommonPart
		++ PitchClass.prMusicSymbolClassHigherPart;
		^PitchClass.prMake(quarterToneScale)
	}
	*getName {
		arg which;
		var pitchClassSets, pitchClassKey;
		pitchClassSets = PitchClass.lily.collect { |item, index|
			item ++ PitchClass.mus[index] ++ PitchClass.ez[index] };
		^pitchClassSets[which]
	}

}

+ Float {
	cpsspn {
		arg style = \lily;
		^SPN.midi(this.cpsmidi.round(0.5), style)
	}
	midispn {
		arg style = \lily;
		^SPN.midi(this.round(0.5), style)
	}
	pitchClass {
		^PitchClass.getName(this)
	}
}

+ Integer {
	cpsspn {
		arg style = \lily;
		^SPN.midi(this.cpsmidi.round(0.5), style)
	}
	midispn {
		arg style = \lily;
		^SPN.midi(this.round(0.5), style)
	}
	pitchClass {
		^PitchClass.getName(this.asFloat)
	}
}

+ Symbol {
	cps {
		^SPN.getValue(this, \cps)
	}
	midi {
		^SPN.getValue(this, \midi)
	}
}

Here are more test codes with results in the Post window:

\d4.cps                 // -> 293.66476791741
\d4.midi                // -> 62.0
\dn4.cps                // -> 293.66476791741
\dn4.midi               // -> 62.0

\df4.cps                // -> 277.18263097687
\df4.midi               // -> 61.0
61.midispn              // -> [ cs4, df4, bx3 ]
61.midispn(\lily)       // -> [ cs4, df4, bx3 ]
61.midispn(\mus)        // -> [ c♯4, d♭4, b𝄪3 ]
277.18263097687.cpsspn  // -> [ cs4, df4, bx3 ]
277.cpsspn(\lily)       // -> [ cs4, df4, bx3 ]
278.cpsspn(\mus)        // -> [ c♯4, d♭4, b𝄪3 ]

PitchClass.lily[\t]     // -> [ as, bf, cff ]
PitchClass.lily['t.5']  // -> [ bqf, atqs, ctqf, cffqs ]
PitchClass.lily[\t5]    // -> [ bqf, atqs, ctqf, cffqs ]
PitchClass.lily[\e]     // -> [ b, ax, cf ]
PitchClass.lily[\e5]    // -> [ bqs, cqf, axqs, dffqf ]
PitchClass.lily['e.5']  // -> [ bqs, cqf, axqs, dffqf ]

SPN.midi(69)    // -> [ a4, gx4, bff4 ]
SPN.midi(69.2)  // -> [ a4, gx4, bff4 ]
SPN.midi(69.3)  // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
SPN.midi(69.5)  // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
SPN.midi(69.6)  // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
SPN.midi(69.9)  // -> [ as4, bf4, cff5 ]
SPN.midi(70.0)  // -> [ as4, bf4, cff5 ]

SPN.midi(69, \mus)    // -> [ a♮4, g𝄪4, b𝄫4 ]
SPN.midi(69.1, \mus)  // -> [ a♮4, g𝄪4, b𝄫4 ]
SPN.midi(69.4, \mus)  // -> [ a ¼↑ 4, b♭ ¼↓ 4, a♯ ¼↓ 4, g𝄪 ¼↑ 4, b𝄫 ¼↑ 4, c𝄫 ¼↓5 ]
SPN.midi(69.5, \mus)  // -> [ a ¼↑ 4, b♭ ¼↓ 4, a♯ ¼↓ 4, g𝄪 ¼↑ 4, b𝄫 ¼↑ 4, c𝄫 ¼↓5 ]
SPN.midi(69.6, \mus)  // -> [ a ¼↑ 4, b♭ ¼↓ 4, a♯ ¼↓ 4, g𝄪 ¼↑ 4, b𝄫 ¼↑ 4, c𝄫 ¼↓5 ]
SPN.midi(69.9, \mus)  // -> [ a♯4, b♭4, c𝄫5 ]
SPN.midi(70.0, \mus)  // -> [ a♯4, b♭4, c𝄫5 ]

SPN.midi(72)          // -> [ c5, bs4, dff5 ]
SPN.midi(72, \mus)    // -> [ c♮5, b♯4, d𝄫5 ]

SPN.cps(110)          // -> [ a2, gx2, bff2 ]
SPN.cps(111.0, \mus)  // -> [ a♮2, g𝄪2, b𝄫2 ]
SPN.cps(112.0)        // -> [ aqs2, btqf2, gxqs2, bffqs2, cffqf3 ]
SPN.cps(113, \mus)    // [ a ¼↑ 2, b♭ ¼↓ 2, a♯ ¼↓ 2, g𝄪 ¼↑ 2, b𝄫 ¼↑ 2, c𝄫 ¼↓3 ]
SPN.cps(114.0)        // -> [ aqs2, btqf2, gxqs2, bffqs2, cffqf3 ]
SPN.cps(115, \mus)    // -> [ a♯2, b♭2, c𝄫3 ]
SPN.cps(116.0)        // -> [ as2, bf2, cff3 ]
SPN.cps(117.0, \mus)  // -> [ a♯2, b♭2, c𝄫3 ]
SPN.cps(118)          // -> [ as2, bf2, cff3 ]
SPN.cps(119, \mus)    // -> [ b ¼↓ 2, a♯ ¼↑ 2, b♭ ¼↑ 2, c♭ ¼↓3, c𝄫 ¼↑3 ]
SPN.cps(120)          // -> [ bqf2, atqs2, ctqf3, cffqs3 ]


\a2.cps               // -> 110.0
110.0.cpsspn          // -> [ a2, gx2, bff2 ]
111.0.cpsspn(\mus)    // -> [ a♮2, g𝄪2, b𝄫2 ]
110.cpsspn            // -> [ a2, gx2, bff2 ]
111.cpsspn(\mus)      // -> [ a♮2, g𝄪2, b𝄫2 ]

\aq2.cps              // -> 113.22324603078
112.cpsspn            // -> [ aqs2, btqf2, gxqs2, bffqs2, cffqf3 ]
113.0.cpsspn          // -> [ aqs2, btqf2, gxqs2, bffqs2, cffqf3 ]
114.cpsspn            // -> [ aqs2, btqf2, gxqs2, bffqs2, cffqf3 ]

\as2.cps              // -> 116.54094037952
115.cpsspn            // -> [ as2, bf2, cff3 ]
116.cpsspn            // -> [ as2, bf2, cff3 ]
117.cpsspn            // -> [ as2, bf2, cff3 ]
118.cpsspn            // -> [ as2, bf2, cff3 ]

\aQ2.cps              // -> 119.95585059318
119.cpsspn            // -> [ bqf2, atqs2, ctqf3, cffqs3 ]
120.cpsspn            // -> [ bqf2, atqs2, ctqf3, cffqs3 ] 
121.cpsspn            // -> [ bqf2, atqs2, ctqf3, cffqs3 ]

\b2.cps          // -> 123.47082531403
122.cpsspn       // -> [ b2, ax2, cf3 ]
122.cpsspn(\mus) // -> [ b♮2, a𝄪2, c♭3 ]

\a4.cps
\a4.midi
69.midispn           // -> [ a4, gx4, bff4 ]
69.0.midispn(\lily)  // -> [ a4, gx4, bff4 ]
69.1.midispn(\mus)   // -> [ a♮4, g𝄪4, b𝄫4 ]
69.2.midispn(\mus)   // -> [ a♮4, g𝄪4, b𝄫4 ]
69.3.midispn(\mus)   // -> [ a ¼↑ 4, b♭ ¼↓ 4, a♯ ¼↓ 4, g𝄪 ¼↑ 4, b𝄫 ¼↑ 4, c𝄫 ¼↓5 ]
69.4.midispn         // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
69.5.midispn         // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
69.6.midispn         // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
69.7.midispn         // -> [ aqs4, btqf4, gxqs4, bffqs4, cffqf5 ]
69.8.midispn         // -> [ as4, bf4, cff5 ]
69.9.midispn         // -> [ as4, bf4, cff5 ]
70.midispn           // -> [ as4, bf4, cff5 ]
70.0.midispn         // -> [ as4, bf4, cff5 ]
70.1.midispn         // -> [ as4, bf4, cff5 ]
70.2.midispn         // -> [ as4, bf4, cff5 ]
70.3.midispn         // -> [ bqf4, atqs4, ctqf5, cffqs5 ]
70.4.midispn         // -> [ bqf4, atqs4, ctqf5, cffqs5 ]
70.5.midispn         // -> [ bqf4, atqs4, ctqf5, cffqs5 ]
70.6.midispn         // -> [ bqf4, atqs4, ctqf5, cffqs5 ]
70.7.midispn         // -> [ bqf4, atqs4, ctqf5, cffqs5 ]
70.8.midispn         // -> [ b4, ax4, cf5 ]
70.9.midispn         // -> [ b4, ax4, cf5 ]
71.midispn           // -> [ b4, ax4, cf5 ]
1 Like