sugarlabs / musicblocks

Music Blocks -- A musical microworld
https://musicblocks.sugarlabs.org/
GNU Affero General Public License v3.0
565 stars 762 forks source link

lilypond has limited understanding of mode #1096

Closed walterbender closed 4 years ago

walterbender commented 6 years ago

I saved a chromatic mode to Lilypond, but \chromatic was not recognized. We support more modes than Lilypond, so we need a plan to handle these unsupported modes in our output

pikurasa commented 6 years ago

I saved a chromatic mode to Lilypond, but \chromatic was not recognized. We support more modes than Lilypond, so we need a plan to handle these unsupported modes in our output

Lilypond is only expecting "how many sharps and how many sharps". Furthermore, anything that is outside of the typical major/minor needs to be specified (e.g. if you want an f sharp and a g shard with no c sharp)

pikurasa commented 6 years ago

(if I am understanding the code correctly) Please remember that the other modes related to the typical Major/Minor can be calculated to have the correct number of sharps/flats.

For example:

B Locrian A Aeolian G Myxolydian F Lydian E Phrygian D Dorian C Major (Ionian)

can all be expressed as C major or A minor, and still result in the correct notation.

(transpose the above to get desired results for all other keys)

Modes outside of these 7 would be unsupported for now.

walterbender commented 6 years ago

We'll need to calculate the proper mapping.

walterbender commented 6 years ago

I added a mode mapper for these common modes into their equivalents in major and minor. I think I got them all mapped correctly, but could well have made a mistake or two here and there. The relevant code is here:

https://github.com/walterbender/musicblocks/blob/master/js/utils/musicutils.js#L1957

@pikurasa Please spot-check when you have a chance.

pikurasa commented 6 years ago

Okay, I am reviewing it. I found a few things.

BTW, is there a convenient way to get # (sharp) and b (flat) symbols? I am just copying and pasting now.

sum2it commented 6 years ago

Can we please keep # for sharp and b for flat? It is much more convenient.

Also, ## for double sharp and bb for double flat?

walterbender commented 6 years ago

There are constants you can use if you want: SHARP, FLAT, etc.

pikurasa commented 6 years ago

@walterbender What is double-sharp and double-flat?

I am working on this. Putting placeholders for now.

quozl commented 6 years ago

In conventional tonality, a double-sharp raises a note by two semitones; a whole tone.

walterbender commented 6 years ago

https://github.com/walterbender/musicblocks/blob/master/js/utils/musicutils.js#L34

pikurasa commented 6 years ago

In conventional tonality, a double-sharp raises a note by two semitones; a whole tone.

@quozl , unless it is already sharped (by the key signature, for example) -- in which it only raises it by one semitone, a half step. :grin:

@walterbender thanks, I see it now. It is DOUBLESHARP and DOUBLEFLAT

For example:

    case 'dorian':                                                                                                                      
        switch(key) {
        case 'c' + DOUBLESHARP:
            key = 'b' + SHARP;
            mode = 'major';
            break;

Also, I am willing to put these patch changes in for now, but for the future I think we should try and have the underlying calculation in our code. In the meantime, it is a good challenge for me, and when we do find a better way, we can check our work against this version.

kierenmacmillan commented 6 years ago

Hey there! Lilypond natively understands all the church modes: you can say, e.g., "\key c \locrian". For anything other than the standard church modes, new modes and scales (e.g., \chromatic) can be easily constructed. If this is something you want me to work with you on, let me know!

walterbender commented 6 years ago

If you could point me toward an example of constructing a mode, that'd be a great place to start. Is there a definitive list of the supported modes somewhere?

kierenmacmillan commented 6 years ago

This doc page contains the full list of pre-built modes, and an example of building a new one: http://lilypond.org/doc/v2.19/Documentation/notation/displaying-pitches#key-signature

pikurasa commented 6 years ago

As for constructing key signatures other than our usual suspects for sharps and flats (i.e. going in order FCGDAEB for sharps and BEADGCF for flats), I think we should avoid doing anything special by default as the majority of musicians (even professional musicians) are not used to them. For example, even though a harmonic minor may have a G#, it is typically written with a key signature of no sharps/flats (equal to a minor).

I am not sure if this is what anyone is thinking, but I did want to put the warning out now, before anything is implemented.

kierenmacmillan commented 6 years ago

I agree that the default(s) should only be "standard" key signatures: sharps and flats only (i.e., no double sharps/flats or quarter sharps/flats), in the standard order. But if you are going to offer your users any [non-default] options for creating custom modes (which will almost certainly require custom/non-standard key signatures), I would recommend using Lilypond’s built-in options (see doc link, above) rather than rolling your own.

pikurasa commented 6 years ago

By default, any mode selected should default to one of our (15, I think) common key signatures, as that is the most common practice.

We could add a trigger for custom key signatures in the Lilypond dialogue when saving as Lilypond (i.e. "Do you want custom key signatures"?).

I see a few cases that this implicates:

  1. Literal Signatures for Keys other than major/minor (for example, a key with just G# [instead of F#] as its only sharp)
  2. Keys with double sharps/flats instead of their enharmonic equivalent
  3. Quarter tone <-- this one is implicated by temperament

In terms of priorities, we need to first fix the original problem stated in this issue that funnels the various modes into our most common major/minor possibilities.

Once we do that, we can work toward these special signatures.

Thanks again @kierenmacmillan !

kierenmacmillan commented 6 years ago

As I understand it, the original problem was that you felt the need to create a mapping between your modes and one of the simple major/minor key signatures in Lilypond. (Please correct me if that’s not an accurate interpretation!)

I’m suggesting that you shouldn’t have to create such a mapping, and that indeed that would be suboptimal as a solution. If Music Blocks is using (e.g.) the Locrian mode on C, then the Lilypond output should be

\key c \locrian

No need for any mapping to a "traditional" major/minor key signature required.

The second item — that the "chromatic" mode isn’t recognized — is a separate issue (which, indeed, should be tackled separately and later). Apologies for conflating the two in my comments/answers/suggestions.

pikurasa commented 6 years ago

@kierenmacmillan I think I get it now (I misunderstood what I was seeing in the Lilypond Manual as it addresses a few topics). Yes, \key c \locrian sounds like an easier solution than doing anything on our end. Thanks for pointing it out.

The second item can be addressed in the future. It is not a priority for us now.

walterbender commented 6 years ago

I wrote a patch for the common modes and have some custom modes working as per the instructions in the guide. But is it possible to do, for example chromatic mode? I don't know how it would work on a standard staff.

On Fri, Jun 22, 2018, 2:42 PM Devin Ulibarri notifications@github.com wrote:

@kierenmacmillan https://github.com/kierenmacmillan I think I get it now (I misunderstood what I was seeing in the Lilypond Manual as it addresses a few topics). Yes, \key c \locrian sounds like an easier solution than doing anything on our end. Thanks for pointing it out.

The second item can be addressed in the future. It is not a priority for us now.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/sugarlabs/musicblocks/issues/1096#issuecomment-399541800, or mute the thread https://github.com/notifications/unsubscribe-auth/ADz74RR4CZgr8jTFVhR4pPBf6_K1xH57ks5t_TqlgaJpZM4SGR1P .

walterbender commented 6 years ago

Never mind. I answered my own question. When the mode cannot be represented on the staff, we just mark each note instead.

On Sun, Jul 1, 2018 at 8:50 PM Walter Bender walter.bender@gmail.com wrote:

I wrote a patch for the common modes and have some custom modes working as per the instructions in the guide. But is it possible to do, for example chromatic mode? I don't know how it would work on a standard staff.

On Fri, Jun 22, 2018, 2:42 PM Devin Ulibarri notifications@github.com wrote:

@kierenmacmillan https://github.com/kierenmacmillan I think I get it now (I misunderstood what I was seeing in the Lilypond Manual as it addresses a few topics). Yes, \key c \locrian sounds like an easier solution than doing anything on our end. Thanks for pointing it out.

The second item can be addressed in the future. It is not a priority for us now.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/sugarlabs/musicblocks/issues/1096#issuecomment-399541800, or mute the thread https://github.com/notifications/unsubscribe-auth/ADz74RR4CZgr8jTFVhR4pPBf6_K1xH57ks5t_TqlgaJpZM4SGR1P .

-- Walter Bender Sugar Labs http://www.sugarlabs.org http://www.sugarlabs.org

walterbender commented 6 years ago

I have this mostly working now (on the master branch), but it needs testing.

walterbender commented 6 years ago

What I think is not working -- really a separate issue from this one -- is switching modes within a single voice.

kierenmacmillan commented 6 years ago

Hmm… You mean having individual voices with different modes on a single staff? I'm not sure exactly how that would work (in the Western notation system, not just Lilypond!).

kierenmacmillan commented 6 years ago

How exactly do you define "chromatic mode"? If you just mean that all 12 pitches of the Western scale are valid, then in Lilypond it’s probably best to choose \key c \major, and then use the appropriate accidentalStyle to display/hide accidentals as desired/required.

pikurasa commented 6 years ago

I have this mostly working now (on the master branch), but it needs testing.

I tested Ab and, because it is directly piping a flat symbol to lilyond, that is not working. For example a♭ should be aes. Did not check sharp, but if the same implementation is in place, then please correct there as well.

Also, I second all of @kierenmacmillan 's above comments.

walterbender commented 6 years ago

I am not sure what it is you are testing. This was about defining modes in Lilypond. I don't think I have changed anything that would impact how Ab or a♭ are interpreted.

Can you please attach your test project?

Mine is quite simple:

[[0,["start",{"collapsed":false,"xcor":0,"ycor":0,"heading":0,"color":10,"shade":50,"pensize":5,"grey":100}],640,75,[null,28,null]],[1,["newnote",{}],653.5,178.5,[28,2,5,9]],[2,["divide",{}],749.72119140625,178.5,[1,3,4]],[3,["number",{"value":1}],835.22119140625,178.5,[2]],[4,["number",{"value":4}],835.22119140625,210,[2]],[5,["vspace",{}],667,210,[1,6]],[6,["pitch",{}],667,241.5,[5,7,8,null]],[7,["solfege",{"value":"sol"}],740.5,241.5,[6]],[8,["number",{"value":4}],740.5,273,[6]],[9,["hidden",{}],653.5,336,[1,10]],[10,["newnote",{}],653.5,336,[9,11,14,18]],[11,["divide",{}],749.72119140625,336,[10,12,13]],[12,["number",{"value":1}],835.22119140625,336,[11]],[13,["number",{"value":4}],835.22119140625,367.5,[11]],[14,["vspace",{}],667,367.5,[10,15]],[15,["pitch",{}],667,399,[14,16,17,null]],[16,["solfege",{"value":"mi"}],740.5,399,[15]],[17,["number",{"value":4}],740.5,430.5,[15]],[18,["hidden",{}],653.5,493.5,[10,19]],[19,["newnote",{}],653.5,493.5,[18,20,23,27]],[20,["divide",{}],749.72119140625,493.5,[19,21,22]],[21,["number",{"value":1}],835.22119140625,493.5,[20]],[22,["number",{"value":2}],835.22119140625,525,[20]],[23,["vspace",{}],667,525,[19,24]],[24,["pitch",{}],667,556.5,[23,25,26,null]],[25,["solfege",{"value":"sol"}],740.5,556.5,[24]],[26,["number",{"value":4}],740.5,588,[24]],[27,["hidden",{}],653.5,651,[19,null]],[28,["setkey2",{}],653.5,115.5,[0,29,30,1]],[29,["notename",{"value":"C"}],729.51953125,115.5,[28]],[30,["modename",{"value":"jazz minor"}],729.51953125,147,[28]]]

I switch to different modes and see how Lilypond responses. Seems to basically work.

\version "2.18.2"

% **** % % WHAT IS THIS? -- This is a LilyPond file generated from Music % Blocks software (Read about it at www.musicblocks.net). % % DOWNLOAD LILYPOND -- In order to create notation with this file, % you will need to download and install LilyPond software onto your % computer (http://lilypond.org/download.html). Frescobaldi % software is also handy for editing LilyPond files % (http://frescobaldi.org/download). % % LILYPOND INSTRUCTIONS -- For instructions on how to further % manipulate musical notation using LilyPond software, please % read the Introduction (http://lilypond.org/text-input.html) and % the Manual % (http://lilypond.org/doc/v2.18/Documentation/learning/index.html). % % GLOSSARY -- A glossary with helpful examples may be found here % (http://www.lilypond.org/doc/v2.19/Documentation/music-glossary/). % % MUTOPIA -- You may also benefit from studying scores from the % Mutopia Project website, which has freely sharable music notation % generated with LilyPond (http://www.mutopiaproject.org/). % % LILYBIN -- You can explore your Lilypond output in a web browser at % (http://lilybin.com/). % % COMMENTS -- Some of the code below is commented out. You can % enable it by deleting the % that precedes the text or, in the % case of a commented section, deleting the %{ and %} that surrounds % the section. % % ****

% Please add your own name, the title of your musical creation, % and the intended copyright below. % The copyright is great for sharing (and re-sharing)! % Read more about it here (http://creativecommons.org/licenses/by-sa/4.0/). % Of course, you can use any copyright you like -- you made it! \header { dedication = \markup { \abs-fontsize #8 \sans "Made with LilyPond and Music Blocks" \with-url #"http://musicblocks.sugarlabs.org/" { \abs-fontsize #8 \sans "(http://musicblocks.sugarlabs.org/)" } } title = "My Project" % subtitle = "Subtitle" % instrument = "Instrument" composer = "Walter" % arranger = "Arranger" copyright = "Walter (c) 2017 -- CC-BY-SA" tagline = "Made from Music Blocks v.2.2" footer = \markup { \with-url #"http://musicblocks.sugarlabs.org/" "Made with Music Blocks Software v.2.2" Engraved on \simple #(strftime "%Y-%m-%d" (localtime (current-time))) } currentYear = \markup { \simple #(strftime "%Y" (localtime (current-time))) } copyTag = " free to distribute, modify, and perform" copyType = \markup { \with-url #"http://creativecommons.org/licenses/by-sa/3.0/" "Creative Commons Attribution ShareAlike 3.0 (Unported) License " } copyright = \markup { \override #'(baseline-skip . 0 ) \right-column { \sans \bold \with-url #"http://musicblocks.net" { \abs-fontsize #9 "Music " \concat { \abs-fontsize #12 \with-color #white \char ##x01C0 \abs-fontsize #9 "Blocks " } } } \override #'(baseline-skip . 0 ) \center-column { \abs-fontsize #11.9 \with-color #grey \bold { \char ##x01C0 \char ##x01C0 } } \override #'(baseline-skip . 0 ) \column { \abs-fontsize #8 \sans \concat { " Typeset using " \with-url #"http://www.lilypond.org" "LilyPond software " \char ##x00A9 " " \currentYear " by " \composer " " \char ##x2014 " " \footer } \concat { \concat { \abs-fontsize #8 \sans { " " \copyType \char ##x2014 \copyTag } } \abs-fontsize #13 \with-color #white \char ##x01C0 } } } tagline = ##f }

% To change the meter make adjustments in the following section. % You must also delete the % before \meter everywhere it appears below. meter = { % \time 3/4 % \key c \minor \numericTimeSignature % \partial 4 % \tempo "Andante" 4=90 }

% You can change the MIDI instruments below to anything on this list: % (http://lilypond.org/doc/v2.18/documentation/notation/midi-instruments)

jazz_minor = #`((0 . ,NATURAL) (1 . ,NATURAL) (2 . ,FLAT) (3 . ,NATURAL) (4 . ,NATURAL) (5 . ,NATURAL) (6 . ,NATURAL) ) mouse = { \meter \key c \jazz_minor g'4 e'4 g'2
}

mouseVoice = \new Staff \with { \clef "treble" instrumentName = "mouse" shortInstrumentName = "mo" midiInstrument = "acoustic grand"

} { \clef "treble" \mouse }

\score { << \mouseVoice

% GUITAR TAB SECTION % Delete the %{ and %} below to include guitar tablature output. %{ \new TabStaff = "guitar tab" << \clef moderntab \context TabVoice = "mouse" \mouse

%}

\layout {}

% MIDI SECTION % Delete the %{ and %} below to include MIDI output. %{ \midi { \tempo 4=90 } %}

}

% MUSIC BLOCKS CODE % Below is the code for the Music Blocks project that generated this Lilypond file. %{

[[0,["start",{"collapsed":false,"xcor":0,"ycor":0,"heading":0,"color":0,"shade":50,"pensize":5,"grey":100}],640,75,[null,28,null]], [1,["newnote",{}],653.5,178.5,[28,2,5,9]], [2,["divide",{}],749.72119140625,178.5,[1,3,4]], [3,["number",{"value":1}],835.22119140625,178.5,[2]], [4,["number",{"value":4}],835.22119140625,210,[2]], [5,["vspace",{}],667,210,[1,6]], [6,["pitch",{}],667,241.5,[5,7,8,null]], [7,["solfege",{"value":"sol"}],740.5,241.5,[6]], [8,["number",{"value":4}],740.5,273,[6]], [9,["hidden",{}],653.5,336,[1,10]], [10,["newnote",{}],653.5,336,[9,11,14,18]], [11,["divide",{}],749.72119140625,336,[10,12,13]], [12,["number",{"value":1}],835.22119140625,336,[11]], [13,["number",{"value":4}],835.22119140625,367.5,[11]], [14,["vspace",{}],667,367.5,[10,15]], [15,["pitch",{}],667,399,[14,16,17,null]], [16,["solfege",{"value":"mi"}],740.5,399,[15]], [17,["number",{"value":4}],740.5,430.5,[15]], [18,["hidden",{}],653.5,493.5,[10,19]], [19,["newnote",{}],653.5,493.5,[18,20,23,27]], [20,["divide",{}],749.72119140625,493.5,[19,21,22]], [21,["number",{"value":1}],835.22119140625,493.5,[20]], [22,["number",{"value":2}],835.22119140625,525,[20]], [23,["vspace",{}],667,525,[19,24]], [24,["pitch",{}],667,556.5,[23,25,26,null]], [25,["solfege",{"value":"sol"}],740.5,556.5,[24]], [26,["number",{"value":4}],740.5,588,[24]], [27,["hidden",{}],653.5,651,[19,null]], [28,["setkey2",{}],653.5,115.5,[0,29,30,1]], [29,["notename",{"value":"C"}],729.51953125,115.5,[28]], [30,["modename",{"value":"jazz minor"}],729.51953125,147,[28]]] %}

pikurasa commented 6 years ago

I am not sure what it is you are testing. This was about defining modes in Lilypond. I don't think I have changed anything that would impact how Ab or a♭ are interpreted.

Lilypond, at least my version of Lilypond does not know how to read symbol. Flat is arrived to by adding es at the end of a pitches' letter name. Therefore, Lilypond is throwing an error when I choose a flat key (and thus not generating correct results).

This must be a bug that has been introduced recently as I sremember this working before.

Does this make sense? If not, I will upload my tests with some descriptions, but I need to leave now.

I have not tried your test example yet, but would expect it to work as C is a natural note (no sharp or flat).

walterbender commented 6 years ago

OK. The ♭ bug is an unrelated regression. I'll look into it. What I had been working on was the mode specification (assuming Lilypond would manage the key specification).

walterbender commented 6 years ago

Pushed a fix to the accidental bug when specifying key.

pikurasa commented 6 years ago

Thanks for checking and fixing the ♭ bug!

Test results: I tested all the most common modes for C, and those all work as expected.

As for the non-common modes, the issue that I see with implementing sharp and flat combinations outside of the common maj/min is that most people never learn to read such key signatures. The tradition is to find the nearest common mode (musically), and use that signature. For example, "jazz minor" as in your example above, would be c minor since the sound is mostly minor. (I know you probably need a more clear cut rule for this... I will think about it...)

As for design, I recommend that our lilypond dialogue have a switch that would trigger the functionality as you implemented it for non-common codes.

(for example...)

jazz_minor = #`((0 . ,NATURAL) (1 . ,NATURAL) (2 . ,FLAT) (3 . ,NATURAL) (4 . ,NATURAL) (5 . ,NATURAL) (6 . ,NATURAL) )
mole = {
\meter
 \key c \jazz_minor
g'4  e'4  g'2  
}

...otherwise, the default should be to choose the "nearest" common mode (as a musician would choose them), otherwise the resultant music would be in key signatures that most people are unfamiliar with.

Do not get me wrong--I like this feature (Bartok, for example, uses this method of key signatures in his Mikrokosmos). I just worry that, since it is so unused, it might be offputting to many traditional music teachers.

walterbender commented 6 years ago

Makes sense. I will have to wrap my head around the best way of mapping to the common key -- I suppose some logic similar to what I had been doing for the church modes prior to using the Lilypond built-ins.

kierenmacmillan commented 6 years ago

I agree with the notion that the default should be the "nearest common mode", with an option to avoid that "simplification". (As a composer, I have used "strange" modes myself; e.g. http://kierenmacmillan.info/round-730/ employs a key signature with a Bb and F#.)

The mapping logic seems like a musical problem with a mathematical/combinatorial slant — as someone with peer-reviewed publications in both math and music, that kind of puzzle makes me very happy. ;)

I'll see if I can find the simplest/optimal mapping, and then figure out how easy it would be to accomplish on the Lilypond side (just in case you want to leave that "heavy lifting" up to Lily).

kierenmacmillan commented 6 years ago

Hey! Is the optimal "mapping" any more difficult than this?

  1. Take all sharps in "nonstandard" mode and arrange them in "standard order". Reduce set of possible sharps so there are no "gaps" (e.g., F# G# -> F# only; D# A# -> no sharps).
  2. Do the same with the flats.
  3. Whichever set (flats or sharps) has the most members is the final "standard" key signature.
pikurasa commented 6 years ago

@kierenmacmillan Please walk me through this a little bit more.

What do you mean by "standard order"? Would this be analogous to church modes being set to Ionian position, or more like Alan Forte's prime form, which would have locrian as its prime form for church modes?

How do you arrive at no sharps for D# and A#?

I want to make sure I understand you before commenting.

kierenmacmillan commented 6 years ago

By "standard order", I mean F#-C#-G#-D#-A#-E#-B# for sharps, and Bb-Eb-Ab-Db-Gb-Cb-Fb for flats.

As I understand it, we’re trying to take an arbitrary mode (with its "natural" set of accidentals), and find the "standard" key signature that is the closest fit — which I define as containing the largest number of the accidentals required for the mode.

Example: Kieren Mode is C-Db-Eb-E-F-F#-G#-A-Bb-B. So the "natural" set of accidentals is Db,Eb,F#,G#,Bb. Separating the sharps and flats: F#-G# and Db-Eb-Bb. Ordering them properly: F#-G# and Bb-Eb-Db. That set of sharps has a gap (C#), so we reduce that to just F#; that set of flats has a gap (Ab), so we reduce it to just Bb-Eb. Since the optimal standard flat key signature has 2 flats, and the optimal standard sharp key signature has 1 sharp, we choose the flat key signature as the "closest fit" to Kieren Mode. So Kieren Mode maps to Bb major.

Does that make more sense?

walterbender commented 6 years ago

Makes sense to me. Do you think you could sketch out some pseudo code?

pikurasa commented 6 years ago

@kierenmacmillan Even if your formula is not "perfect", I think it is probably good enough--at least god enough for now. So, bravo!

@walterbender what Kieren has is already a kind of pseudo code.

  1. For mode, Check for sharps; check for flats.
  2. Put sharps and flats in "standard order" (as defined above)
  3. Ask "how many consecutive sharps/flats do we have?
  4. If sharp has consecutively more, then use the sharp key equivalent; if flat has consecutively more, then use flat.
  5. If sharp and flat are equal, use sharp (I suppose... I am just arbitrating here, and arbitrating "sharps" just because I am a plucked string player)
  6. If no consecutive sharps/flats, use natural (C major)

@kierenmacmillan please verify that this is what you have in mind.

pikurasa commented 4 years ago

99% of what was discussed here works.

The only outlying issue is that it would be nice to have a button to choose "the nearest common key" instead of these unfamiliar combinations. I will put that in a separate issue.

@walterbender @kierenmacmillan bravo!

images of the feature below (ignore octave leaps, that is a separate issue)

Locrian Screenshot at 2020-05-08 12:03:23 locrian test

So-called "Jazz Minor" Screenshot at 2020-05-08 12:12:13 Jazz Minro