1

I recently developed an algorithm in Python that allows me to generate time signatures and metronome markings and output them as LilyPond code. I use metronome indications with up to three decimal places and also irrational time signatures (such as 7/23).

Now, unfortunately, LilyPond is not very reliable when it comes to outputting that code. Sometimes it works, sometimes it doesn't, sometimes it only works up to a certain point and then it doesn't. I believe that this is due to the \scaleDurations function, but I am not sure. What would support this assumption is that if I change the denominator of a fraction where the output stops - for example, 57/40 instead of 57/41 in the last measure of the following example - the output works again.

Perhaps someone knows the cause of the problem?

Here is an example of a musical expression that works for me up to the 12th measure, but no longer works at the 13th:

\version "2.24.2"

musicone = {

%%%%%%%%%%%%%%%%%%%%%%% MEASURE : 1 %%%%%%%%%%%%%%%%%%%%%%%
\scaleDurations 41/47 {
\time 7/22  
\set Staff.timeSignatureFraction = #'(7 . 22)  

\textMark \markup {\left-column {\line { \smaller \general-align #Y #DOWN \note {8} #1 " = 50.0 " } } }

% The music will later be put here. For now, use the \repeat unfold expression
\repeat unfold 7 { c'16 }
|
}

\once \set Staff.whichBar = "|"

%%%%%%%%%%%%%%%%%%%%%%% MEASURE : 2 %%%%%%%%%%%%%%%%%%%%%%%
\scaleDurations 6/5 {
\time 2/8  
\set Staff.timeSignatureFraction = #'(2 . 8)  

% The music will later be put here. For now, use the \repeat unfold expression
\repeat unfold 2 { c'8 }
|
}

\once \set Staff.whichBar = "|"

%%%%%%%%%%%%%%%%%%%%%%% MEASURE : 3 %%%%%%%%%%%%%%%%%%%%%%%
\scaleDurations 6/5 {
\time 2/8  
\set Staff.timeSignatureFraction = #'(2 . 8)  

% The music will later be put here. For now, use the \repeat unfold expression
\repeat unfold 2 { c'8 }
|
}

\once \set Staff.whichBar = "|"

%%%%%%%%%%%%%%%%%%%%%%% MEASURE : 4 %%%%%%%%%%%%%%%%%%%%%%%
\scaleDurations 41/47 {
\time 2/8  
\set Staff.timeSignatureFraction = #'(2 . 8)  

\textMark \markup {\left-column {\line { \smaller \general-align #Y #DOWN \note {8} #1 " = 68.753 " } } }

% The music will later be put here. For now, use the \repeat unfold expression
\repeat unfold 2 { c'8 }
|
}

\once \set Staff.whichBar = "|"

%%%%%%%%%%%%%%%%%%%%%%% MEASURE : 5 %%%%%%%%%%%%%%%%%%%%%%%
\scaleDurations 41/47 {
\time 2/8  
\set Staff.timeSignatureFraction = #'(2 . 8)  

% The music will later be put here. For now, use the \repeat unfold expression
\repeat unfold 2 { c'8 }
|
}

\once \set Staff.whichBar = "|"

%%%%%%%%%%%%%%%%%%%%%%% MEASURE : 6 %%%%%%%%%%%%%%%%%%%%%%%
\scaleDurations 37/28 {
\time 7/16  
\set Staff.timeSignatureFraction = #'(7 . 16)  

\textMark \markup {\left-column {\line { \smaller \general-align #Y #DOWN \note {8} #1 " = 45.4 " } } }

% The music will later be put here. For now, use the \repeat unfold expression
\repeat unfold 7 { c'16 }
|
}

\once \set Staff.whichBar = "|"

%%%%%%%%%%%%%%%%%%%%%%% MEASURE : 7 %%%%%%%%%%%%%%%%%%%%%%%
\scaleDurations 37/28 {
\time 17/64  
\set Staff.timeSignatureFraction = #'(17 . 64)  

% The music will later be put here. For now, use the \repeat unfold expression
\repeat unfold 17 { c'64 }
|
}

\once \set Staff.whichBar = "|"

%%%%%%%%%%%%%%%%%%%%%%% MEASURE : 8 %%%%%%%%%%%%%%%%%%%%%%%
\scaleDurations 38/33 {
\time 5/14  
\set Staff.timeSignatureFraction = #'(5 . 14)  

\textMark \markup {\left-column {\line { \smaller \general-align #Y #DOWN \note {8} #1 " = 59.55 " } } }

% The music will later be put here. For now, use the \repeat unfold expression
\repeat unfold 5 { c'16 }
|
}

\once \set Staff.whichBar = "|"

%%%%%%%%%%%%%%%%%%%%%%% MEASURE : 9 %%%%%%%%%%%%%%%%%%%%%%%
\scaleDurations 1 {
\time 2/8  
\set Staff.timeSignatureFraction = #'(2 . 8)  

% The music will later be put here. For now, use the \repeat unfold expression
\repeat unfold 2 { c'8 }
|
}

\once \set Staff.whichBar = "|"

%%%%%%%%%%%%%%%%%%%%%%% MEASURE : 10 %%%%%%%%%%%%%%%%%%%%%%%
\scaleDurations 1 {
\time 2/8  
\set Staff.timeSignatureFraction = #'(2 . 8)  

% The music will later be put here. For now, use the \repeat unfold expression
\repeat unfold 2 { c'8 }
|
}

\once \set Staff.whichBar = "|"

%%%%%%%%%%%%%%%%%%%%%%% MEASURE : 11 %%%%%%%%%%%%%%%%%%%%%%%
\scaleDurations 59/47 {
\time 15/53  
\set Staff.timeSignatureFraction = #'(15 . 53)  

\textMark \markup {\left-column {\line { \smaller \general-align #Y #DOWN \note {8} #1 " = 57.804 " } } }

% The music will later be put here. For now, use the \repeat unfold expression
\repeat unfold 15 { c'64 }
|
}

\once \set Staff.whichBar = "|"

%%%%%%%%%%%%%%%%%%%%%%% MEASURE : 12 %%%%%%%%%%%%%%%%%%%%%%%
\scaleDurations 27/26 {
\time 2/8  
\set Staff.timeSignatureFraction = #'(2 . 8)  

% The music will later be put here. For now, use the \repeat unfold expression
\repeat unfold 2 { c'8 }
|
}

\once \set Staff.whichBar = "|"

%%%%%%%%%%%%%%%%%%%%%%% MEASURE : 13 %%%%%%%%%%%%%%%%%%%%%%%
\scaleDurations 57/41 {
\time 23/64  
\set Staff.timeSignatureFraction = #'(23 . 64)  

\textMark \markup {\left-column {\line { \smaller \general-align #Y #DOWN \note {8} #1 " = 43.164 " } } }

% The music will later be put here. For now, use the \repeat unfold expression
\repeat unfold 23 { c'64 }
|
}

\once \set Staff.whichBar = "|"

}


 \score { \musicone 
 \layout {
   \context {\Voice
     \remove "Forbid_line_break_engraver"
          }
          \context { \Score  
                     measureBarType=#""
                     proportionalNotationDuration = #(ly:make-moment 1 64) }      
   }
 }
7
  • Can you explain what you're trying to accomplish? Your first measure is 7/22 of a whole note in length per the time signature, but the actual notes in it are (41/47)*(7/16) = 287/752 of a whole note, or 451/376 of a measure. If you make the measures be the notated lengths then you'll probably get better output from LilyPond.
    – benrg
    Commented Oct 16, 2023 at 18:41
  • I guess, I should have mentioned how I calculated the values of \scaleDurations: (notated note value * 60000) / (note value * (metronome marking * 1000)) where - notated note value is the value that is notated when using irrational values (f.e. notating 8th notes when using 12th notes) - note value is the actual note value (e.g. 12th notes) - metronome indication with up to three decimal places. A 7/23 bar with a metronome marking of 8th note = 53.476, if 23rd notes were notated as 16th notes, would thus result in (16*60000) / (23 * (53.476*1000)). Am I making a mistake in thinking?
    – kleinlosen
    Commented Oct 16, 2023 at 19:07
  • The metronome marking shouldn't appear in that formula, since it doesn't affect the measure length in note-value terms (which is tracked internally by LilyPond).
    – benrg
    Commented Oct 16, 2023 at 19:35
  • But it certainly affects the output. A 2/8 measure at tempo 8th note = 60 (\scaleDurations = 8/8) takes only half as much space on paper as a 2/8 measure with \scaleDurations 16/8 at tempo 8th note = 30. (So with my formula, I calculated it like this: (8*60000) / (8*(30*10000)).) Ultimately, I am interested in stacking such time signatures on top of each other in a large orchestral score and notating them proportionally. This all works in principle, but I have these problems in the individual parts (because of the \scaleDurations function). So just don't insert the tempo "by hand" as I did?
    – kleinlosen
    Commented Oct 16, 2023 at 19:51
  • Thanks to the previous answers, it is now much clearer to me how such irrational time signatures can be output in proportional notation. However, the problem with the code not compiling completely was that the denominators of the \scaleDurations values I used were too large. If I reduce them to <=9 (in Python using the limit_denominator(9) method), the output works fine.
    – kleinlosen
    Commented Oct 21, 2023 at 20:49

2 Answers 2

0

\scaleDurations only scales the time used up by notes, but not the actual length of the measure. You’ve actually included the solution already, but you did not apply it properly. It is no use to use \time X/Y in combination with \set Staff.timeSignatureFraction = #'(X . Y), but instead you can set these to different values to have Lilypond handle them appropriately:

\scaleDurations 41/47 {
  \time 287/1034 % = 41/47 * 7/22
  \set Staff.timeSignatureFraction = #'(7 . 22)
  \set baseMoment = #(ly:make-moment 41/47)
  
  \textMark \markup {\left-column {\line { \smaller \general-align #Y #DOWN \note {8} #1 " = 50.0 " } } }
  
  % The music will later be put here. For now, use the \repeat unfold expression
  \repeat unfold 7 { c'16*16/22 }
  |
}

Setting the baseMoment will allow Lilypond to properly handle beaming and Stuff. As you can see I’ve scaled the 16th notes in that example to 22nd notes to actually fit the meter.

Instead of doing text marks for tempo you can also do parallel tempo marks by moving the engraver:

\layout {
  \context {
    \Score
    \remove Metronome_mark_engraver
  }
  \context {
    \Staff
    \consists Metronome_mark_engraver
  }
}

<<
  \new Staff { \tempo 4=60 1 1 1 1 }
  \new Staff { \tempo 4=70 1 1 1 1 }
  \new Staff { \tempo 4=80 1 1 1 1 }
  \new Staff { \tempo 4=90 1 1 1 1 }
>>

The issue with this is that this won’t allow non integer metronome marks, and cannot be easily adapted as this part is handled by the parser.

1
  • @benrg Thank you both, both responses are very helpful! Unfortunately, the problem still exists that I can't output/render the code completely (which really should be error-free now). Somewhere the output of the score always breaks. I think the problem is probably more with Frescobaldi; I'll have a look tomorrow to see if the problem persists on another computer and/or OS (I'm currently using a macOS Ventura 13.4.1).
    – kleinlosen
    Commented Oct 16, 2023 at 22:11
1

I think the issue is that you want different tempos in parallel parts. LilyPond doesn't support that. It internally tracks time in whole notes, not seconds. If the measures in parallel parts are to have the same length (on the page) then they must have the same internal length in wholes.

There are examples in the documentation of what I think you want in the Polymetric notation section. In general, you need to:

  • Pick an "internal tempo", which may match the notated tempo of one or more parts. (The formulas below assume the units for tempos are wholes/minute or similar, so larger is faster.)
  • Write the notated tempo for each part as markup. Since it's uninterpreted by LilyPond, you can write whatever you like, including values rounded to three decimal places.
  • In each part write something like
    \time (notated measure duration * internal tempo / notated tempo)
    \set Staff.timeSignatureFraction = (notated measure duration)
    \scaleDurations (internal tempo / notated tempo) {
      ...
    }

If you want unaligned measure boundaries then you also need \enablePolymeter as shown in the second example in the documentation.

If you want the speed of MIDI output to be correct, add \tempo followed by the internal tempo to the \midi block, or \omit \tempo somewhere in the score. If you don't care about MIDI then it's not necessary.

2
  • Thank you! Actually, what I'm looking for is something like this: discussion.forum.ircam.fr/t/proportional-notation-and-polytempo/… Here, a LilyPond example is posted where polytempic notation actually works. Now, I'm trying to include irrational time signatures/values and metronome markings as floats.
    – kleinlosen
    Commented Oct 16, 2023 at 20:57
  • @kleinlosen I tweaked the formulas in my answer. I think they cover all of these cases.
    – benrg
    Commented Oct 16, 2023 at 21:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.