I've implemented for me a relative tempo change for "l'istesso tempo"
in the past by using \applyContext. And now reading issue 3428 (where
\articulate did not notice the tempo set in the midi block and did
apply a wrong tempo for "rit" and "a tempo") I think, a general
implementation of relative tempo changes in LILYPOND would be a good
toolbox to solve such issues.
My current test implementations of such a SCHEME procedure uses three
new context properties today.
The first one is simply to consolidate multiple applyContext calls
(usually form different voices/staves inside the score) by processing
only the first one at any #(ly:moment-main (ly:context-current-moment
... )).
In the two other properties I store the current tempoWholesPerMinute
value, one prop for 'BasicTempo' (e.g. for "Tempo primo") and one prop
for 'OriginalTempo' (e.g. for "a tempo" after "retenuto", "ritardando"
and so on.)
The actions that might be executed by the "relative tempo change
applyContext call" are.
a) save the current 'tempoWholesPerMinute' to a context property for
later use.
b) Read either the current 'tempoWholesPerMinute' or one of the context
properties you saved the value before, then multiply it with a rational
factor you specified, and set this result to be the new
tempoWholesPerMinute.
c) clear one of the context properties you've saved
'tempoWholesPerMinute' before.
The textual or symbolic information printed on the music sheet mostly
paired to these relative tempo changes are at the moment out of scope
for me. They belong to a level above, to a practical user interface.
Some examples:
save for later "Tempo primo":
task a: save to BasicTempo; no task b; no task c
Tempo primo"
no task a; BasicTempo * 1; no task c
l'istesso tempo form \time 4/4 to \time 12/8, typical text is \markup {
\note {4} #UP "=" \note {4.} #UP} (where the mid-staff occurreces
should center the "=" sign above the bar line) would be:
no task a; task b: current tempoWholesPerMinute * 3/2; no task c
ritenuto with slowing down 30 % might be:
task a: Save to OriginalTempo; task b: current tempoWholesPerMinute *
7/10; no task c
the following "a tempo" will be then:
no task a; task b: OriginalTempo * 1; task c: clear OriginalTempo
Another function may create a sequential music for "tempo ramps", you
specify the total duration (e.g. 4 measures), the frequency (e.g. each
quarter an update) and the relative final tempo (e.g. 2/3), and you can
place the resulting sequential music (which only contains
relativeTempoChanges and skips) parallel to your existing music.
Here an example for such a sequence:
{ relativeTempo(save OriginalTempo; alter to current * 47/48; no clear)
s4
relativeTempo(no save; alter to OriginalTempo * 46/48; no clear)
s4
relativeTempo(no save; alter to OriginalTempo * 45/48; no clear)
...
relativeTempo(no save; alter to OriginalTempo * 32/48; no clear)
s4
}
Is this concept worth to dig more into the details (and possible
problems)?
ArnoldTheresius