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

Hi there,
Is there a way to convert integer and float to scientific pitch notation?
I have coded a function to do a similar thing as follows, but I would like to know if there is another way supported by sclang primitives or other quarks.

(
~midispn = { |aNumber|
	var midispn = ();
	(0, 0.5 .. 127).do { |quarterStep|
		var quarterToneStep, octave;
		quarterToneStep = [
			\c, 'a quarter-tone raised c', 'c#', 'a quarter-tone raised c#',
			\d, 'a quarter-tone raised d', 'd#', 'a quarter-tone raised d#',
			\e, 'a quarter-tone raised e',
			\f, 'a quarter-tone raised f', 'f#', 'a quarter-tone raised f#',
			\g, 'a quarter-tone raised g', 'g#', 'a quarter-tone raised g#',
			\a, 'a quarter-tone raised a', 'a#', 'a quarter-tone raised a#',
			\b, 'a quarter-tone raised b'
		][quarterStep * 2 % 24];
		octave = (quarterStep / 12).floor - 1;
		midispn.put(quarterStep.asSymbol, quarterToneStep ++ octave.asInteger)
	};
	midispn[aNumber.asFloat.asSymbol]
}
)
~midispn.(60)

~midispn.(69)

~midispn.(60.5)

~midispn.(61.5)

I’m not aware of anything that supports microtones. To be honest, I’m not aware of the existence of a scientific pitch notation to describe microtones and microtonal accidentals. Given the vast range of tuning systems (not all of which repeat at the octave), it seems like a daunting task.

Just freewheeling a bit here (and I 'd be surprised if nothing like this actually existed, somewhere, but I’m not aware of it):

A pragmatic approach might be to use an integer “scale degree” which is mapped to an actual frequency using a scala definition ( Scala scale file (.scl) format ). Accidentals then can be some fractional modifier which modifies the scale degree, and which logarithmically interpolate between the frequencies specified in the scala file.

E.g. consider this scala definition which defines a scale of 5 degrees, which repeat at the octave.

! 05-24.scl
!
5 out of 24-tET, symmetrical
 5
!
 100.00000
 550.00000
 650.00000
 1100.00000
 2/1

Each of the numbers above represent pitch modifiers (to be applied to a root frequency which, sadly, is not specified in scala) in cents (100 cents corresponds to a semi-tone in conventional 12 EDO tuning). This would give rise to a system of 5 “pitches”: “0”, “1”, “2”, “3”, “4”. (pitch 0 corresponds to a modifier of 0 cents, which is not explicitly listed in the scala definition)

The scala format does not define how the pitches relate to octave number but as a convention one might assign octave 0 to whatever is used as “root frequency”.

To denote a pitch 2 in the third octave, one could e.g. imagine writing “2(3)”. To denote a pitch halfway pitch 2 and 3 in the third octave, one could e.g. modify this into “2(3)(+0.5)”. Such notation can only be translated into frequencies in combination with a scala definition that describes what “2” means. The +0.5 fraction interpolates “logarithmically” (i.e. halfway in pitch space, not in frequency space) between the frequencies represented by “2(3)” and “3(3)”. Similarly, 2(3)(-0.75) would result in a pitches 3-quarters between pitches represented by 2(3) and 1(3). To avoid floating point accuracy issues, perhaps similar to scala, the fractional part could also be represented as a rational number: 2(3)(-3/4).

In case of scales that do not repeat at the octave (e.g. Bohlen-Pierce tuning divides a ratio 3:1 into equal parts instead of the normal 2:1), the name “octave number” is not accurate, but a number similar in spirit could be used, maybe one could call it the “interval number” instead of “octave number”.

If this seems like a reasonable approach, I think it should be possible to write a quark that, given a scala definition and a root frequency, can convert both ways between “scientific notation” and “frequency”.

2 Likes

Naming pitches and associating (or mapping) those pitches to specific frequencies are two different things, I think.

You mentioned scales spanning an octave. This is theoretically possible, but human pitch recognition is based on ‘octave equivalence’, regardless of culture, as far as I know. (I think ‘octave equivalence’ applies to all species of animals that can hear sound, but let’s stick with humans). The all-pitch naming system I know of is based on octave equivalence, and I think this approach is practically reasonable.

My question was simply how to translate integer and float for music notation. I limited the range to quarter notes because musicxml only allows 24 EDO notation. I would use 1/16, but this does not seem to work with the current version of musicxml.

And thanks for mentioning the Scala language. I will look into it when I can.

1 Like

I fully agree.

There’s a potential for misunderstanding here: I’m not referring to the Scala programming language, I’m referring to the scala program for microtonal music. See: https://www.huygens-fokker.org/scala/

Actually, in the world of microtonal music it is quite common to define scales that do not repeat at the octave. Perhaps the most widely used tuning to do so is the Bohlen-Pierce tuning (you can find a significant amount of Bohlen-Pierce music on youtube… here’s one I made a few years ago) which is based on a “tritave” (“3:1” ratio) as opposed to the octave (“2:1”).

I would actually like to make something like what I’ve described above (or perhaps something like a “microtonal version of Panola”), so I can play a bit with it, even if only as a proof of concept.

2 Likes

And as a detail - pianos are conventionally tuned with a small amount of “stretch” - so their octaves are often a little larger than 2:1…

1 Like

Hi I don’t think you need to build the big Event - how about simply

(
~midispn = {  |quarterStep|
		var quarterToneStep, octave;
		quarterToneStep = [
			\c, 'a quarter-tone raised c', 'c#', 'a quarter-tone raised c#',
			\d, 'a quarter-tone raised d', 'd#', 'a quarter-tone raised d#',
			\e, 'a quarter-tone raised e',
			\f, 'a quarter-tone raised f', 'f#', 'a quarter-tone raised f#',
			\g, 'a quarter-tone raised g', 'g#', 'a quarter-tone raised g#',
			\a, 'a quarter-tone raised a', 'a#', 'a quarter-tone raised a#',
			\b, 'a quarter-tone raised b'
		][quarterStep * 2 % 24];
		octave = (quarterStep / 12).floor - 1;
        quarterToneStep ++ octave.asInteger
}
)
1 Like

Yes, your suggestion is simpler and even better. I thought it should react to the number from 0 to 127, but with your logic it could go beyond that range. Great!

I have made some method discussed here and in the following threads:

The method definitions are as follows:

+ Integer {

	midispn {
		var quarterToneStep, octave;
		quarterToneStep = [
			\c, 'a quarter-tone raised c', 'c#', 'a quarter-tone raised c#',
			\d, 'a quarter-tone raised d', 'd#', 'a quarter-tone raised d#',
			\e, 'a quarter-tone raised e',
			\f, 'a quarter-tone raised f', 'f#', 'a quarter-tone raised f#',
			\g, 'a quarter-tone raised g', 'g#', 'a quarter-tone raised g#',
			\a, 'a quarter-tone raised a', 'a#', 'a quarter-tone raised a#',
			\b, 'a quarter-tone raised b'
		][this * 2 % 24];
		octave = (this / 12).floor - 1;
		^quarterToneStep ++ octave.asInteger
	}

	cpsspn {
		var quarterToneStep, octave;
		quarterToneStep = [
			\c, 'a quarter-tone raised c', 'c#', 'a quarter-tone raised c#',
			\d, 'a quarter-tone raised d', 'd#', 'a quarter-tone raised d#',
			\e, 'a quarter-tone raised e',
			\f, 'a quarter-tone raised f', 'f#', 'a quarter-tone raised f#',
			\g, 'a quarter-tone raised g', 'g#', 'a quarter-tone raised g#',
			\a, 'a quarter-tone raised a', 'a#', 'a quarter-tone raised a#',
			\b, 'a quarter-tone raised b'
		][this.cpsmidi.round(0.5) * 2 % 24];
		octave = (this.cpsmidi / 12).floor - 1;
		^quarterToneStep ++ octave.asInteger
	}
}

+ Float {

	midispn {
		var quarterToneStep, octave;
		quarterToneStep = [
			\c, 'a quarter-tone raised c', 'c#', 'a quarter-tone raised c#',
			\d, 'a quarter-tone raised d', 'd#', 'a quarter-tone raised d#',
			\e, 'a quarter-tone raised e',
			\f, 'a quarter-tone raised f', 'f#', 'a quarter-tone raised f#',
			\g, 'a quarter-tone raised g', 'g#', 'a quarter-tone raised g#',
			\a, 'a quarter-tone raised a', 'a#', 'a quarter-tone raised a#',
			\b, 'a quarter-tone raised b'
		][this.round(0.5) * 2 % 24];
		octave = (this / 12).floor - 1;
		^quarterToneStep ++ octave.asInteger
	}

	cpsspn {
		var quarterToneStep, octave;
		quarterToneStep = [
			\c, 'a quarter-tone raised c', 'c#', 'a quarter-tone raised c#',
			\d, 'a quarter-tone raised d', 'd#', 'a quarter-tone raised d#',
			\e, 'a quarter-tone raised e',
			\f, 'a quarter-tone raised f', 'f#', 'a quarter-tone raised f#',
			\g, 'a quarter-tone raised g', 'g#', 'a quarter-tone raised g#',
			\a, 'a quarter-tone raised a', 'a#', 'a quarter-tone raised a#',
			\b, 'a quarter-tone raised b'
		][this.cpsmidi.round(0.5) * 2 % 24];
		octave = (this.cpsmidi / 12).floor - 1;
		^quarterToneStep ++ octave.asInteger
	}
}

+ Symbol {

	midi {
		var quarterToneStep, octave;
		quarterToneStep = (
			[
				(-11 .. 12).collect { |octave|
					var pitchClasses = [
						\c, \cq, \cs, \cQ,
						\d, \dq, \ds, \dQ,
						\e, \eq,
						\f, \fq, \fs, \fQ,
						\g, \gq, \gs, \gQ,
						\a, \aq, \as, \aQ,
						\b, \bq
					];
					pitchClasses.collect { |pitchclass|
						(pitchclass ++ octave).asSymbol
					}
				}.flat,
				(-120, -119.5 .. 156)
			].flop
			.collect { |item|
				item[0] -> item[1]
			}.asEvent
		);
		^quarterToneStep[this]
	}
	cps {
		var quarterToneStep, octave;
		quarterToneStep = (
			[
				(-11 .. 12).collect { |octave|
					var pitchClasses = [
						\c, \cq, \cs, \cQ,
						\d, \dq, \ds, \dQ,
						\e, \eq,
						\f, \fq, \fs, \fQ,
						\g, \gq, \gs, \gQ,
						\a, \aq, \as, \aQ,
						\b, \bq
					];
					pitchClasses.collect { |pitchclass|
						(pitchclass ++ octave).asSymbol
					}
				}.flat,
				(-120, -119.5 .. 156)
			].flop
			.collect { |item|
				item[0] -> item[1].midicps
			}.asEvent
		);
		^quarterToneStep[this]
	}
}

The test results are as follows:

\a2.cps    // -> 110.0
110.cpsspn // -> a2
111.cpsspn // -> a2

\aq2.cps   // -> 113.22324603078
112.cpsspn // -> a quarter-tone raised a2
113.cpsspn // -> a quarter-tone raised a2
114.cpsspn // -> a quarter-tone raised a2

\as2.cps   // -> 116.54094037952
115.cpsspn // -> a#2
116.cpsspn // -> a#2
117.cpsspn // -> a#2
118.cpsspn // -> a#2

\aQ2.cps   // -> 119.95585059318
119.cpsspn // -> a quarter-tone raised a#2
120.cpsspn // -> a quarter-tone raised a#2
121.cpsspn // -> a quarter-tone raised a#2

\b2.cps    // -> 123.47082531403
122.cpsspn // -> b2

\a4.midi
69.midispn   // -> a4
69.1.midispn // -> a4
69.2.midispn // -> a4
69.3.midispn // -> a quarter-tone raised a4
69.4.midispn // -> a quarter-tone raised a4
69.5.midispn // -> a quarter-tone raised a4
69.6.midispn // -> a quarter-tone raised a4
69.7.midispn // -> a quarter-tone raised a4
69.8.midispn // -> a#4
69.9.midispn // -> a#4
70.midispn   // -> a#4
70.0.midispn // -> a#4
70.1.midispn // -> a#4
70.2.midispn // -> a#4
70.3.midispn // -> a quarter-tone raised a#4
70.4.midispn // -> a quarter-tone raised a#4
70.5.midispn // -> a quarter-tone raised a#4
70.6.midispn // -> a quarter-tone raised a#4
70.7.midispn // -> a quarter-tone raised a#4
70.8.midispn // -> b4
70.9.midispn // -> b4
71.midispn   // -> b4

I think it is not good enough to make a PR because there are duplicate variable definitions in the different methods in a class such as pitchClasses as well as in the different classes such as quarterToneStep.

How do I get d-flat?

If this is just for you then ignore this, but since you mentioned a PR…

Have you considered using Lilypond’s format for pitch names to avoid reinventing the wheel

as - a sharp
af - a flat
bff - b double flat
bss - b double sharp
fqs - f quarter sharp
gtqf - g three quarter flat

When you convert from a number, the result shows a# which might be a little confusing as previously we have been writing it as as.

There is nothing ‘scientific’ about the naming here. Its just note names.

What does .cpsspn mean? Why not, .cpsname as wslib does? Speaking of, have you looked at the stuff from wslib, like Note and the .cpsname method? It doesn’t quite do what you want but you could easily alter it.

It looks like “scientific notation” is a thing: Scientific pitch notation - Wikipedia

it just means the combination of note names with numbers as opposed to using tick marks - so a6 as opposed to a’’

I personally find blocks of note names not so readable ie “c# e g#” - I prefer to see notes in terms of harmonic function - so [1, 3, 5].inKey(‘c#’, \minor, 3).

I do see the utility in having \a3 as a thing, ultimately I found it more useful to separate the octave - so it is good also to have \a mean the pitch class ‘a’ (the equivalent of note: -2 in the default Event)

I could imagine for example students using patterns enjoying writing (note:\a, octave:3) or (freq: \a3) or (degree: [1, 3, 4, 6], root: \a)

As a follow-up to my promise, I have now made a new quark “mitola” = microtonal language, a variant of panola for microtonal music.

Code on GitHub - shimpe/mitola: supercollider quark for microtonal music composition; microtonal counterpart to panola.

It depends on another quark for parser generation GitHub - shimpe/scparco: Quark providing parser combinators for supercollider.

Here’s a wacky chip tune I quickly made with it in (part of the examples of mitola): Vocaroo | Online voice recorder.

And here’s a “hello world” score to play a chromatic scale in 13 equal divisions of the octave.
The degrees in the score are 1-based.

(
s.waitForBoot({
	var tuning = [
		"! 13EDO.scl",
		"!",
		"13 EDO",
		" 13",        // number of degrees in this tuning
		"!",
		" | 1/13 >",  // degree 2, degree 1 is not explicitly listed in .scl format as it corresponds to 0 cents
		" | 2/13 >",  // degree 3 in prime vector notation = 2^(2/13)
		" | 3/13 >",  // degree 4
		" | 4/13 >",  // degree 5
		" | 5/13 >",  // degree 6
		" | 6/13 >",  // degree 7
		" | 7/13 >",  // degree 8
		" | 8/13 >",  // degree 9
		" | 9/13 >",  // degree 10
		" | 10/13 >",  // degree 11
		" | 11/13 >",  // degree 12
		" | 12/13 >",  // degree 13
		" 2/1" // equivalence interval ("octave")
	].join("\n");
	var score = Mitola("1[4]_16 2 3 4 5 6 7 8 9 10 11 12 13 1[5]", tuning);
	var r = RootFrequencyCalculator(tuning);
	// calculate root frequency to fix 10th degree in fourth equave (think "octave") in 13 EDO to 432Hz:
	var root_freq = r.get_root_frequency("10[4]", 432);
	var pattern = score.as_pbind(instrument:\default, root_frequency:root_freq);
	var player = pattern.play;
});
)

I used to use “+” and “-” for quarter tones. “C#+” or “D-” for example. Easy to use and remember!

Recently I did a little test run for a system with all accidentals for ET-72 and eight-tone in haskell. It covers a lot of note names, but it’s maybe a bit too much for most things.

accidentals :: [Accidental]
accidentals =
  [ Accidental Flat "f" Nothing ((-1) % 1),
    Accidental Natural "" Nothing (0 % 1),
    Accidental Sharp "s" Nothing (1 % 1),
    Accidental QuarterFlat "qf" Nothing ((-1) % 2),
    Accidental QuarterSharp "qs" Nothing (1 % 2),
    Accidental ThreeQuartersFlat "tqf" Nothing ((-3) % 2),
    Accidental ThreeQuartersSharp "tqs" Nothing (3 % 2),
    Accidental DoubleSharp "ss" Nothing (2 % 1),
    Accidental DoubleFlat "ff" Nothing ((-2) % 1),
    Accidental ThirdSharp "rs" Nothing (2 % 3),
    Accidental ThirdFlat "rf" Nothing ((-2) % 3),
    Accidental SixthSharp "xs" Nothing (1 % 3),
    Accidental SixthFlat "xf" Nothing ((-1) % 3),
    Accidental TwelfthSharp "ts" Nothing (1 % 6),
    Accidental TwelfthFlat "tf" Nothing ((-1) % 6),
    Accidental EighthSharp "es" Nothing (1 % 4),
    Accidental EighthFlat "ef" Nothing ((-1) % 4),
    Accidental FiveTwelfthsSharp "fts" Nothing (5 % 6),
    Accidental FiveTwelfthsFlat "ftf" Nothing ((-5) % 6),
    Accidental SevenTwelfthsSharp "sts" Nothing (7 % 6),
    Accidental SevenTwelfthsFlat "stf" Nothing ((-7) % 6),
    Accidental FiveSixthsSharp "fxs" Nothing (5 % 3),
    Accidental FiveSixthsFlat "fxf" Nothing ((-5) % 3),
    Accidental ElevenTwelfthsSharp "ets" Nothing (11 % 6),
    Accidental ElevenTwelfthsFlat "etf" Nothing ((-11) % 6),
    Accidental TwoThirdsFlat "trf" Nothing ((-4) % 3),
    Accidental TwoThirdsSharp "trf" Nothing (4 % 3),
    Accidental ThreeEighthsSharp "tes" Nothing (3 % 4),
    Accidental ThreeEighthsFlat "tef" Nothing ((-3) % 4)
  ]

noteNameToRational :: [RationalNote]
noteNameToRational =
  [ (C, 0 % 1),
    (D, 2 % 1),
    (E, 4 % 1),
    (F, 5 % 1),
    (G, 7 % 1),
    (A, 9 % 1),
    (B, 11 % 1)
  ]

findClosestAccidental :: Rational -> Accidental
findClosestAccidental r =
  let (name, thisShift) = minimumBy (compare `on` (abs . (r -) . snd)) accidentals
  in Accidental name thisShift

findClosestNote :: Rational -> Rational
findClosestNote r =
  snd $ minimumBy (compare `on` (abs . (r -) . snd)) noteNameToRational

calculateDifference :: Rational -> Rational
calculateDifference r = r - findClosestNote r

getClosestNoteAndAccidental :: Rational -> (NoteName, Accidental)
getClosestNoteAndAccidental r =
  let closestNoteRational = findClosestNote mod12
      closestNote = fst $ head $ filter ((==closestNoteRational) . snd) noteNameToRational
      closestAccidental = findClosestAccidental (calculateDifference mod12)
      mod12 = rationalModulo12 r
  in (closestNote, closestAccidental)

It is great!
I have never used Haskel before. Can Haskel output sheet music? It seems good!

Anyway, + and - should be enclosed in " or ’ in sclang.

  • typing two ‘’ or two “” is not pleasant when typing.
  • It reduces readability when reading.
    Thus, I think the notation should start with ,

One mature but inactive (only bugfixes) music library in Haskell is: https://www.euterpea.com/

2 Likes

Euterpea is a great source to learn, the book is also very good. But unfortunately, it would not be trivial to implement any kind of microtones with it.

1 Like

Yeah too bad. Mainly sharing because it’s related to Haskell & notation. It’s been ages since I used it. Maybe some of the higher level types are polymorphic enough to reuse?

1 Like

It’s not too hard to build a parser that converts note names into frequencies or ratios. But at some point, someone’s probably going to want to transpose notes and convert them back to music notation while handling accidentals correctly (both for readability in sheet music and correctness in case of non-12edo tunings), so you’ll need a pitch encoding layer in between note name strings and frequencies. There are multiple microtonal paradigms, so that pitch encoding layer may need to be extensible and modular depending on your needs.

I hope this doesn’t come off as condescending but I’ve worked on a (now defunct) music notation project and had many conversations with the Abjad guys, and in my experience music encoding is a challenging field. Be aware of what you’re getting into when designing these systems. Good luck!

2 Likes

Yes, I think there are many great ideas there. The :+: and :=: operators are interesting, since they construct a kind of tree data type, with vertical and horizontal leaves. It’s very appropriate to represent music scores.

data Orientation = H | V
  deriving (Show)

data OrientedTree a
  = Val a
  | Group Orientation [OrientedTree a]
  deriving (Show, Functor)

But the pitch level has a more simple approach. For example, the relation between pitches and intervals would fit very well with a vector space type.

2 Likes

@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