lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Metronome marking with non-integer value


From: Lib Lists
Subject: Re: Metronome marking with non-integer value
Date: Sun, 25 Jun 2023 15:59:30 +0300

Hi Valentin,
thank you so much for your time, it works perfectly and the detailed
explanation is really helpful and welcome (now I need to experiment
more on my own to fully understand everything).
Interestingly, and this would have been the topic of my next message,
the resulting MIDI output is always correct whatever \tempo I put (it
can be the same \tempo for all staves). In the example below the top
staff is always set to 4 = 120 and the other staves correctly follow.
I'm wondering if this is because \scaleDurations overrides any \tempo
indication, or because of \cadenzaOn. But it's not a problem, as it
works as it should.

In any case, here below an example that uses your 'Weird tempo'
marking. Also I added a rounding function found on Stack Overflow to
avoid a visually too long decimal. However, the resulting MIDI file
doesn't show any visible rounding issue.

Thank you again,
Lib

P.S. Rational / decimal metronome markings can be useful for
analytical purposes (performance studies, or rhythmically complex /
generative music such as Nancarrow etc.). Also for music to be
performed if the piece has i.e. (multiple) click tracks or conductors,
or if it is music written for mechanical instruments. I agree though
that in the big scheme of things those are quite unusual cases :-)

\version "2.25.5"
#(ly:set-option 'midi-extension "mid")

voiceAmount = 7
% round-off taken from:
https://stackoverflow.com/questions/16302038/float-precision-and-removing-rounding-errors-in-scheme
#(define (round-off z n)
  (let ((power (expt 10 n)))
    (/ (round (* power z)) power)))

\score {
  \new StaffGroup  <<
    #@(map (lambda (i)
    #{
      \new Staff {
        \scaleDurations #(cons voiceAmount i) {
          #(make-music
    'TempoChangeEvent
    'metronome-count
    (round-off (* i (/ 120.0 voiceAmount )) 2)
    'tempo-unit
    (ly:make-duration 2)
    )
          \relative c'' \repeat unfold #i {{c c c c }} \bar "||"
        }
      }
      #})
    (iota voiceAmount voiceAmount -1))
  >>

  \layout {
    \context {
      \Score
      \remove Metronome_mark_engraver
      \cadenzaOn
    }
    \context {
      \Staff
      \remove Time_signature_engraver
      \consists Metronome_mark_engraver
    }
  }
  \midi { }
}



On Sun, 25 Jun 2023 at 14:13, Valentin Petzel <valentin@petzel.at> wrote:
>
> Hello Lib,
>
> this is a limitation of the Lilypond parser which implements the syntax
>
> \tempo [text] [duration = ...]
>
> Here it assumes that ... is an unsigned integer. This I think is not
> unreasonable, if you tell a musician to play something in MM 72.4 he will
> probably be a bit confused.
>
> Anyway, the solution to the problem would be to simply not use this parser
> feature. \tempo is only a parser feature and not a music function as a music
> functions do not allow the 4 = 120 syntax and does not allow having two
> arguments both of which can be optional but one being mandatory.
>
> But in the end \tempo ... still evaluates to a music event, as you can see if
> you do
>
> \displayMusic \tempo "some text" 4 = 120
>
> This creates two music events:
>
> (make-music
>   'TempoChangeEvent
>   'metronome-count
>   120
>   'tempo-unit
>   (ly:make-duration 2)
>   'text
>   "some text")
>
> is the event that is responsible for creating the tempo mark and
>
> (make-music
>   'ContextSpeccedMusic
>   'context-type
>   'Score
>   'element
>   (make-music
>     'PropertySet
>     'value
>     (ly:make-moment 30)
>     'symbol
>     'tempoWholesPerMinute))
>
> is what makes midi tempo work (it basically sets Score.tempoWholesPerMinute to
> a moment of duration metronome marking * metronome base length, so in our case
> 120 * 1/4 = 30.
>
> So what you need to do to get non integral is to manually create the first
> thing:
>
> {
>   #(make-music
>     'TempoChangeEvent
>     'metronome-count
>     72.4
>     'tempo-unit
>     (ly:make-duration 2)
>     'text
>     "Weird tempo")
>   c
> }
>
> To get midi to work you’ll also need to do
>
> \score {
>   {
>     #(make-music
>       'TempoChangeEvent
>       'metronome-count
>       72.4
>       'tempo-unit
>       (ly:make-duration 2)
>       'text
>       "Weird tempo")
>     \set Score.tempoWholesPerMinute = #(ly:make-moment (* 724/10 1/4))
>     c
>   }
>   \layout { }
>   \midi { }
> }
>
> If you do not what to do the conversion to rationals 72.4 → 724/10 yourself
> you can use (inexact->exact ...), but keep in mind that this will include
> rounding errors:
>
> (inexact->exact 72.4) -> 2547348539231437/35184372088832
>
> which is the representation of 72.4 with binary digits with machine precision
> (the denominator is 2^45).
>
> Cheers,
> Valentin
>
> Am Sonntag, 25. Juni 2023, 11:44:59 CEST schrieb Lib Lists:
> > Hello,
> >
> > I realised that Lilypond doesn't like it if the metronome value is a
> > non-integer. In the example below, assigning 7 to the voiceAmount
> > variable triggers a 'error: not an unsigned integer'. I tried to
> > construct the metronome number marking as a markup, but without
> > success.
> >
> > Any suggestions? The idea is to have the metronome markings values
> > automatically generated, starting from 4 = 120 in the upper staff.
> > Below both a M(non-)WE and the complete example
> >
> > Thank you in advance for any help!
> >
> > Cheers,
> > Lib
> >
> > %%% MWE %%%
> > \version "2.25.5"
> > \score {
> >   \new Staff {
> >     \tempo 4 = #(* 1 (/ 120 7 ))
> >     { c' }
> >   }
> > }
> > %%%
> >
> >
> > %%% COMPLETE EXAMPLE %%%
> > \version "2.25.5"
> >
> > voiceAmount = 7
> >
> > \score {
> >   \new StaffGroup  <<
> >     #@(map (lambda (i)
> >     #{
> >       \new Staff {
> >         \scaleDurations #(cons voiceAmount i) {
> >           \tempo 4 = #(* i (/ 120 voiceAmount ))
> >           \relative c'' \repeat unfold #i {{c c c c }} \bar "||"
> >         }
> >       }
> >       #})
> >     (iota voiceAmount voiceAmount -1))
> >
> >
> >   \layout {
> >     \context {
> >       \Score
> >       \remove Metronome_mark_engraver
> >       \cadenzaOn
> >     }
> >     \context {
> >       \Staff
> >       \remove Time_signature_engraver
> >       \consists Metronome_mark_engraver
> >     }
> >   }
> > }
> > %%%
>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]