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

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

What do you think about the following hierarchy and structure of notes and rests?
I think it would be better to remove SPN and PitchClass from the notation scheme I am proposing…

Notation: a subclass of the class Object, and an abstract parent class for ‘Notation Library’.
Attribute: an abstract parent class for its subclasses
╎ ├ Staff
╎ ├ Clef
╎ ├ Tempo
╎ ├ TimeSignature
╎ └ KeySignature
Entry: an abstract parent class for its subclasses
╎ ├ Intensity: a class that creates an instance of an Intensity class
╎ ├ I: the abbreviation of Intensity
╎ ├ Hairpin: a class that creates an instance of a hairpin
╎ ├ H: the abbreviation of Hairpin
╎ ├ Rest: a class that creates an instance of a rest
╎ ├ R: the abbreviation of Rest
╎ ├ Note: an abstract class for each pitch class name and the attachment to the note instance:
╎ ╎├ A: a class that creates an instance of note utilising the pitch class a
╎ ╎├ B: a class that creates an instance of note utilising the pitch class b
╎ ╎├ C: a class that creates an instance of note utilising the pitch class c
╎ ╎├ D: a class that creates an instance of note utilising the pitch class d
╎ ╎├ E: a class that creates an instance of note utilising the pitch class e
╎ ╎├ F: a class that creates an instance of note utilising the pitch class f
╎ ╎├ G: a class that creates an instance of note utilising the pitch class g
╎ ╎├ Articulation: a class that creates an instance of articulation for an instance of note
╎ ╎├ U: the abbreviation of Articulation
╎ ╎├ Tie: a class that creates an instance of tie for an instance of note
╎ ╎├ T: the abbreviation of Tie
╎ ╎├ Slur: a class that creates an instance of slur for an instance of note
╎ ╎└ S: the abbreviation of Slur
etc.

An instance of Rest can be created as follows:

  • R.4: rest 1/4 ← It is currently not possible in sclang.
  • R.c: rest 1/4 (crochet rest)
  • R.q: rest 1/4 (quarter rest)
  • R.4d: rest dotted 1/4 ← It is currently not possible in sclang.
  • R.cd: rest dotted 1/4 (dotted crochet rest)
  • R.qd: rest dotted 1/4 (dotted quarter rest)
  • R.8: rest 1/8 ← It is currently not possible in sclang.
  • R.v: rest 1/8 (quaver rest)
  • R.e: rest 1/8 (eighth rest)
  • R.8d: rest dotted 1/8 ← It is currently not possible in sclang.
  • R.vd: rest dotted 1/8 (dotted crochet rest)
  • R.ed: rest dotted 1/8 (dotted quarter rest)
  • etc.

An instance of Note can be created as follows:
(All methods starting with integer are currently not possible in sclang.)

  • A.n.4.4: a quarter note of the A natural in octave 4. MIDI pitch number 69.

  • g.x.4.c: a quarter note of the G double sharps in octave 4. MIDI pitch number 69.

  • B.ff.4.q: a quarter note of the B double flats in octave 4. MIDI pitch number 69.

  • A.qs.4.4d: a dotted quarter note of a quarter-tone higher than A in octave 4. MIDI pitch number 69.5.

  • B.tqf.4.cd: a dotted quarter note of three quarter-tone lower than B in octave 4. MIDI pitch number 69.5.

  • A.s.4.4dd: a double-dotted quarter note of the A sharp in octave 4. MIDI pitch number 70.

  • B.f.4.cdd: a double-dotted quarter note of the B flat in octave 4. MIDI pitch number 70.

  • C.ff.5.qdd: a double-dotted quarter note of the C double flat in octave 5. MIDI pitch number 70.

  • etc.

This will change the notation of a musical notation in my another post: Musical Notation in SC using musicXML - #17 by prko

  • an entry with full options in my initial idea:
[68, \e, \s2, \S, \r, \u] // midinote: 68, duration: 1/8, dynamic marking: strong2 i.e. ff, articulation: staccatissimo, tie: laissez vibrer, slur: start
  • the same entry changed version:
[A.f.4.e, Intensity.ff, Articulation.x, Tie.r, Slur.s] // A pitch and duration are combined to form a note.

or

[A.f.4.e, I.ff, U.x, T.r, S.s] // A pitch and duration are combined to form a note.

Which example is practical for reading and writing?

1 Like

Your new system allows you to do things like

[A, C, E,].collect( _.4.e)
or [A, C, E].collect{|i| i.(4.rrand(6))}

Which is interesting.

I find this:

a lttlle hard to read though - my eye goes to the capital letters before the salient part which here is the method. But maybe that’s ok.

If I were building this I would keep my eye on Lilypond export - so for example in Lilypond you can send a dynamic marking above the staff by adding ^ so \^ff - a nice thing about having Intensity objects is that you can add properties like \above and \below to them later as opposed to your initial idea.

I would perhaps use the more conventional term Dynamic though perhaps?

2 Likes