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

The way I think of an accident type or class is that there is also the possibility of using a “CustomAccidental”. Nothing prevents that. The Notenames will always be the same, even if you choose a different tunning (not A=440hz).

Your example is a good one, and we can find more than one solution to work with that kind of music.

Nowadays we don’t have a problem with representing those symbols in MusicXML or LilyPond. With LilyPond, one can use the ekmelily extension. And Standard Music Font Layout / SMuFL is also quite good, the Bravura font is used by Dorico and other softwares.

1 Like

Maybe that makes a good case to use a small DSL using PreProcessor quark (or something equivalent) if we’re looking for readable and concise code.

1 Like

I haven’t used PreProcessor before but that sounds like a good idea -

I have done a little work with @shiihs scparco quark building parser trees and that might be a helpful tool as well.

3 Likes

Hey @prko

I think MusixXML 4.0 has some options beyond quarter-tones. Take a look:

https://www.w3.org/2021/06/musicxml40/musicxml-reference/data-types/accidental-value/

https://github.com/w3c/musicxml/issues/482

I think some work has been done in this area.

1 Like

Thanks for letting me know! I will try to implement some of them!

1 Like

@smoge
I added eighth-tone accidentals. My system is not any standard accidental system categorised in a particular one in SMuFL. E.g.: Gould arrow quartertone accidentals (24-EDO) · Standard Music Font Layout

It is still a function based on the following post.

This time the Lilypond pitch notation is supported. Below is the revised function:

Below is an example of the code to generate eighth-tone scales:

(
var title = "Eighth-tone Scale";
~score6 = [
	(title: title, composer: 'randomised', right: '©'),
	(
		bar: 1,
		p1: (
			lbl: 'Violin',
			atr: (key: [0, \none], time: [4, 4], staves: 1, clef: [[\g, 2]])
		)
	)
];

(0, 1/4 .. 12).mirror.do { |sixteenth, i|
	var bar = (i / 4).floor + 1;
	~score6 = ~score6.add((bar: bar, p1: (v1: [])));
	~score6[bar][\p1][\v1] = ~score6[bar][\p1][\v1].add([sixteenth + 60]) // correct! thanks @smoge
	// ~score6[bar][\p1][\v1] = ~score6[bar][\p1][\v1].add(sixteenth + 60) // incorrect!
};

~exportXML.(~score6, ("~/Downloads" +/+ title ++".musicxml").standardizePath, 'MuseScore 4');
)

Dorico does not indicate ‘double-sharp-down’. I think this is OK, because I think ‘c with double-sharp-down’ should be notated as ‘d with natural-down’. So my new function will do this automatically when entering pitches by MIDI note pitch numbers, as in the example code above. Please let me know if these notations are acceptable. If not, I could change it, or write a subfunction to decide the enharmonic spelling by looking at the next pitch.


Thanks again! I think writing some classes with methods will not be too difficult once the basic things about pitch notation and rhythmic notation are fixed.

Waiting for more opinions!

1 Like

It works, well done!

It won’t be too hard to rewrite it as a SC class.

Although I think the rhythm part still needs some work to have the basic functionalities as the pitch materials. There’s where some tricky things start to appear.

Let’s keep this conversation going on here or GitHub (or zoom?) with some people that do some work along those lines.

1 Like

Your example has a little bug, sixteenth + 60 needs to be an array. Then it works just fine.

I’m just reading it now and making sense of it. I don’t know anything about MusicXML, to be honest.

I switch to Haskell for my projects (still work with SC for live performances), but now I want to see how far your project goes :slight_smile:


(
var title = "Eighth-tone Scale";
~score6 = [
	(title: title, composer: 'randomised', right: '©'),
	(
		bar: 1,
		p1: (
			lbl: 'Violin',
			atr: (key: [0, \none], time: [4, 4], staves: 1, clef: [[\g, 2]])
		)
	)
];

(0, 1/4 .. 12).mirror.do { |sixteenth, i|
	var bar = (i / 4).floor + 1;
	~score6 = ~score6.add((bar: bar, p1: (v1: [])));
    ~score6[bar][\p1][\v1] = ~score6[bar][\p1][\v1].add([sixteenth + 60])
};

~exportXML.(~score6, ("~/Downloads" +/+ title ++".musicxml").standardizePath, 'MuseScore 4');
)

Thanks for pointing that out! I will correct my example with a comment and thanks to you!

Glad to hear it.

That is my intention! SC users do not need to know MusicXML. My intention is to let sc-users create their own score using events and arrays according to the notation guidelines. My function (or later my class) will convert it into a musicXML file, and the sc-user can see his score in his preferred notation software!

What I need to hear might be the convention of the notation guideline from different perspectives.

Yes, the rhythmic part should be reworked.
I intend to implement triple dots. (Dots, Double dots are currently implemented.)
I think the easiest way is to write the music in ‘senza-misura’ and then let the notation software rebar the music. Otherwise, the user can copy and paste the music into the bars defined by the time signature.
But simply adding triple dots is not enough!

Could we discuss this on this forum first?
Zoom may not be as productive as my English is not that fluent, especially in listening and speaking. Github is also a good place to do it, but I think a draft of some classes should already be done for it. I will try to attend the next developer meeting, even if my English is not good enough. Let’s talk about moving to gitHub around the next developer meeting! I think a draft of the classes will be ready in a few weeks.

Sure.

I’m busy with other things, but I have fun playing around with similar things in Haskell. I’ve been experimenting with different approaches around the same exact problem you’re working on.

One of the solutions for durations is something like


type Division = Integer
type Dots = Int
type Rq = Rational

data Duration where
  Duration :: {  _division :: Division,
                 _dots :: Dots,
                 _multiplier :: Rational}
                -> Duration
  deriving (Eq, Show)


makeLenses ''Duration

class HasDuration a where
  _duration :: a -> Duration

instance HasDuration Duration where
  _duration = id


dotMultiplier :: Dots -> Rational
dotMultiplier dotCount = n % d
  where
    n = 2 ^ (dotCount + 1) - 1
    d = 2 ^ dotCount


durationToRq :: Duration -> Rq
durationToRq d = (1 % (d ^. division)) * dotMultiplier (d ^. dots) * (d ^. multiplier)

The division is the note value. The number of dots alters the duration according to the dotMultiplier function. _multiplier is there to be used when the duration is contained inside a tuplet.

Logical ties, used to duration such as a quarter-note tied to a 32th-note, for example, is another case we need to take care of.

I’m not 100% sure how tuplets work in MusicXML, but I believe it should have a tag, and would work just like a span, such as a slur. Right? The difference is that it will be a sort of container that will alter the _multiplier for each duration. That’s one of the solutions.

Some fun edge cases are nested tuplets and metric modulations… (Lilypond supports the former nicely but I had to write some functions to display and perform the metric modulations !)

IIRC Lilypond will not automatically break up notes to flow across barlines - if you type a4 a4 a4 a2 for example it won’t split the final half note into two tied quarters.

If you are curious to play around there is an online editor for Lilypond here: https://www.hacklily.org/

Yes, I know that. But it would be nice to come up with a model that will work well with Lily ad musicxml. Maybe Abjad did a mistake mirroring LilyPond data types. As a matter of fact, MusicXML can’t be forgotten.

Right now I’m trying to figure out if MusicXML is capable of doing all those things. It’s a bit arcane and weird, and very messy. But probably not impossible to do it.

Some of my experiments (just the first sketches) are already doing the basic job, but there are always “edge cases” when we mix logical ties and tuplets.

let innerTuplet = createTuplet (2 % 3) [DurationComponent (1 % 8), DurationComponent (1 % 8), DurationComponent (1 % 8)]
        components = [DurationComponent (1 % 8), NestedTupletComponent innerTuplet, DurationComponent (1 % 8), DurationComponent (1 % 8)]
        tuplet = createTuplet (4 % 5) components

{-
Tuplet: (ratio: 4 % 5, duration: 1 % 2)
  Duration: 1 % 8
  Tuplet: (ratio: 2 % 3, duration: 1 % 4)
    Duration: 1 % 8
    Duration: 1 % 8
    Duration: 1 % 8
  Duration: 1 % 8
  Duration: 1 % 8
-}
1 Like

This is quite off-topic here, but if you do happen to know both Haskell and Lilypond there is:

https://gitlab.com/rd--/hly

There’s a related tiny essay “Rq Notation: Writing rational durations, reading common music” at:

https://rohandrape.net/?t=hmt-texts&e=lhs/rq-notation.lhs

Ps.

hly requires https://gitlab.com/rd--/hmt, which requires https://gitlab.com/rd--/hmt-base.

Also, if you happen to know both Haskell and MusicXml there is https://gitlab.com/rd--/hts

2 Likes

Wow, that’s fantastic work! How far did you go into more involved music notations with your work?

I will surely enjoy studying your code and have some questions… if you don’t mind receive some. :blush:

Thanks for a lot of information.
I am ashamed that I do not understand Haskell, but I will try to learn what I can take from it.

I feel it somewhat strange that sc-users do not make the libraries to get scores for sclang, but for other languages…

Anyway…

Yes, it is!

I have implemented simple tuplets and nested tuplets. In Dorico and Finale, both are decoded and appear as expected. In MuseScore, nested tuplets are not decoded and displayed correctly.

Below is the updated function:

Below is the test code:

(
~score8 = [
	(   title: 'untitled', composer: 'me', rights: '©'),
	(
		bar: 1,
		p1: (
			lbl: \,
			atr: (
				key: [1, \major],
				time: [4, 4],
				staves: 1,
				clef: [[\g, 2]]
			),
			v1: [
				[\t, 120],
				[\a4, [\e, 3, 2, \e], \p],
				[$|, [[\x, 3, 2, \x]], \f],
				[$|, [[\e, \]], \f],
				[$|, [5, \], \j],               
				[$|, [\De, 6, 4, \x]],
				[$|, [\t], \sf],
				[$|, [\x], \sf],
				[$|, [4, \], \sf, \j],
				[$|, [\de, 5, 4, \x], \J],
				[\aqs4, [\e, \], \sf, \j],
				[$|, [\de, 3, 2, \e], \J],
				[$|, [\t, \], \s2, \j]
			]
		)
	),
	(
		bar: 2,
		p1: (
			v1: [
				[\s1],
				[\aqs4, [\e, 3, 2, \e], \J],
				[$|, [\e]],
				[$|, [5, \]],
				[\a4, [\x, 5, 4, \x]],
				[$|, [\x]],
				[$\\],
				[$|, [[\x, 3, 2, \x]]],
				[$|, [[\x]]],
				[$|, [[\x, \], \]],
				[$|, \dx],
				[$|, \t],
				[$|, \Dx],
				[$|, \i],
				[$|, \Te],
				[$|, \i],			
			]
		)
	)
];

~exportXML.(~score8, "~/Downloads/nested tuplets.musicxml".standardizePath, 'MuseScore 4')
)

The results in Dorico Pro 4, Finale 27 and MuseScore 4 are as follows:



I think the basic features are done, but I am still not sure if the way of notating the score is good enough. I have other simpler ideas to notate them… but still not sure…

1 Like

I started using sclang and lilypond 10 years ago, but never felt the need to expand it into a complete system like music21 and other huge projects. I’ve been also using a pipe between sclang and openmusic, and from there I export music segments and materials into finale. I’ve composed several works this way as well

A piece to illustrate that (I used this process to compose the score, the live-electronics is also supercollider): Bernardo Barros - Attrito [2018] | International Contemporary Ensemble feat. David Fulmer on Vimeo

My experiments with Haskell are kind of recent, I felt that it can offer something different, how to represent it, how I can manipulate the material, and so on, and so on.

The most interesting part, and you should know this, is precisely after that, how to manipulate these materials. I’m always thinking of new ways, it has nothing against the sclang language. )))

2 Likes

Thanks for the great piece!

To be honest, I have not seriously used computer-aided algorithmic composition in my work, although many parts of my work tend to have an algorithmic character.
I did try something in OpenMusic, but that was just an experiment.

I did it several times for research, and the following is one of them: hommage à l'impressionnisme
In these experiments, I thought it would be nice if I could get a score from these codes instead of a spectrum in an audio file editor.

The reason I want to implement this in sclang at the moment is firstly for my students who are not musicians.

When I finish implementing the musicXML file creator for sclang, I will be able to use powerful algorithmic composition for my own work!

I have used MIDI to transfer musical information, but I think musicXML is better.

1 Like

Thank you for listening!

)))

Now the following notation is accepted. This new notation is a bit similar to Panola by @shiihs.

(
~score9 = [
	(   title: 'untitled', composer: 'me', rights: '©'),
	(
		bar: 1,
		p1: (
			lbl: \,
			atr: (
				key: [1, \major],
				time: [4, 4],
				staves: 1,
				clef: [[\g, 2]]
			),
			v1: [
				"t 120",
				"a4 /e/3/2/e p (", // /: tuplet; (: slur start
				"| //x/3/2/x f",   // |: the same pitch(es) as before //: nested tuplet
				"| //e/ f",        // //e/: nested tuplet end
				"| /5/ j",         // /5/: tuplet end
				"| /e../6/4/x",    // e.. double-dotted eighth
				"| /t sf",
				"| /x s2",
				"| /4/ sf j",      // j: tie start
				"| /e./5/4/x J",   // J: tie end
				"aqs4 /e/ sf j",
				"| /e./3/2/e J",
				"| /t/ ff j"
			]
		)
	),
	(
		bar: 2,
		p1: (
			v1: [
				\s1,
				'aqs4 /e/3/2/e J',
				'| /e',
				'| /5/',
				'a4 /x/5/4/x',
				'| /x',
				'\\', // the repetition of the same entry
				'| //x/3/2/x',
				'| //x',
				'| //x//',
				'| x.',
				'| t',
				'| x..',
				'| i',
				'| e...',
				'| i )' // slur end
			]
		)
	)
];

~exportXML.(~score9, "~/Downloads/nested tuplets string or symbol.musicxml".standardizePath, 'MuseScore 4')
)

If you think the abbreviation is not good, I will change the rhythmic part to be the same as in lilypond.
I find it confusing that the accidental notation follows lilypond, but the octave notation follows scientific pitch notation.
I have also looked at lilypond notation, guido notation and abc notation. None of them use scientific pitch notation octave numbers. I have no problem using Helmholtz pitch notation, but feel a bit strange using it with an English based programming language like sclang.

Now the following notation is accepted:

(
~score10 = [
	(   title: 'untitled', composer: 'me', rights: '©'),
	(
		bar: 1,
		p1: (
			lbl: \,
			atr: (
				key: [1, \major],
				time: [4, 4],
				staves: 1,
				clef: [[\g, 2]]
			),
			v1: "
t=120
<a4=e5=a5>=/e/3/2/e=p=(
|=//x/3/2/x=f
|=//e/=f
|=/5/=j
|=/e../6/4/x
|=/t=sf
|=/x=s2
|=/4/=sf=j
|=/e./5/4/x=J
aqs4=/e/=sf=j
|=/e./3/2/e=J
|=/t/=ff=j
"
		)
	),
	(
		bar: 2,
		p1: (
			v1: "
s1
aqs4=/e/3/2/e=J |=/e |=/5/ 
a4=/x/5/4/x |=/x \\ |=//x/3/2/x |=//x |=//x// 
|=x. |=t |=x.. 
|=i |=e... |=i=)
"
		)
	)
];

~exportXML.(~score10, "~/Downloads/nested tuplets string.musicxml".standardizePath, 'MuseScore 4')
)

I am not sure if = used for combining duration, articulation etc. to the pitches is good…
Moreorver, q, e, x, t and i for rhythmic value do not seem to be understandable as 4, 8, 16, 32 and 64…

Any opinions?

1 Like