David Kastrup <d...@gnu.org> writes:

> Dan Eble <d...@faithful.be> writes:
>
>> On Jun 12, 2021, at 18:48, David Kastrup <d...@gnu.org> wrote:
>>> 
>>> So how robust (or not) would be the following approach?  Make it
>>> possible to write in the timing track something like
>>> 
>>> \rit 2/3 { \skip 1*2 }
>>> 
>>> with the effect that some run-always translator keeps adjusting
>>> tempoWholesPerMinute during the \skip (in proportion to where the time
>>> is) until it is at 2/3 the speed at the end when it gets reset.
>>
>> As a user, I think I would rather specify the tempo at the endpoint.
>
> That requires you to remember the tempo at the startpoint if you go for
> a particular kind of slowdown.
>
>> Is there any hope of handling tempo adjustments like dynamic
>> adjustments?
>>
>>     \mf … \< … \f
>>
>>     \tempo 4 = 90 … \startLinearTempoChange … \tempo 4 = 60
>
> Of course the question is what "linear" means with regard to a tempo
> change.  MIDI files measure durations in terms of common-time (the basic
> MIDI clock is 1/24th of a quarter note), so you actually are reduced to
> writing tempo change events (which take the form of specifying µs/♩)
> between note events.  They don't clog up the raw MIDI signal lines
> (those running at 31250bps) since they are "meta events" and converted
> into timing for the "real" events by whatever player/sequencer
> translates the MIDI file into a timed sequence of commands.
>
>> I don't remember very clearly how the dynamic performance looks ahead
>> to manage as it does, but I think it might be that the MIDI generation
>> occurs in a second pass, and a velocity value isn't actually needed
>> until then.  It might be possible to record a piecewise function for
>> the tempo during normal iteration, and then use that to stretch or
>> compress MIDI time as the raw MIDI events are being generated.
>
> We are not outputting a timed sequence of events but MIDI files, so we
> just can intersperse tempo events: the actual timing in the MIDI file is
> being expressed in terms of common-time quarternotes and is unimpressed
> by rit/acc.
>
> Of course that also begs the question of how often to output a tempo
> change: it's conceivable that you run an arranger for accompanying music
> that takes its timing from the generated MIDI file, and when it
> accompanies long notes in a ritardando, the slowdown of the
> accompaniment should likely occur more gradually than one tempo event
> per long note.
>
>> I would love to have this feature.  I'm glad you're considering it.
>
> More thinking about what it would entail than considering it.

I actually don't think that a lot more than the following is needed (by
the way: it is patently ridiculous that it requires \articulate for
getting tomh1:32 rendered as more than one note).

tempoChange =
#(define-music-function (interval endscale thenscale music)
  "Make a gradual tempo change over @var{music}, essentially changing speed after
every duration of @var{interval}, approaching a factor of speed of @var{endscale}
compared to the start.  Afterwards, tempo is switched to @var{endscale} of the
original speed (default 1).  If @var{endscale} is 0, the speed reached at the
end is just maintained and can be overriden with an explicit @samp{\\tempo}
command if required."
   (ly:duration? scale? (scale? 1) ly:music?)
   (define (scaletempo oldscale newscale)
     (make-apply-context
      (lambda (ctx)
	(set! (ly:context-property ctx 'tempoWholesPerMinute)
	 (ly:moment-mul (ly:context-property ctx 'tempoWholesPerMinute)
		 (ly:make-moment (/ newscale oldscale)))))))

   (let* ((muslen (ly:moment-main (ly:music-length music)))
	  (intlen (ly:moment-main (ly:duration-length interval)))
	  (steps (/ muslen intlen))
	  (endfactor (scale->factor endscale))
	  (thenfactor (scale->factor thenscale)))
     (make-simultaneous-music
      (list music
	    (context-spec-music
	     (make-sequential-music
	      (let loop ((rsteplst (iota (1+ steps) endfactor (/ (- 1 endfactor) steps)))
			 (res (if (positive? thenfactor)
				  (list (scaletempo endfactor thenfactor))
				  (list))))
		(if (null? (cdr rsteplst))
		    res
		    (loop (cdr rsteplst)
			  (cons* (scaletempo (cadr rsteplst) (car rsteplst))
				 (make-skip-music (ly:make-duration 0 0 intlen))
				 res)))))
	     'Score)))))

\include "articulate.ly"

\score {
  \articulate
  \drums {
    \tempo 4 = 80
    tomh1:32
    \tempoChange 4 ##e0.6 { tomh1:32 }
    tomh1:32
    \tempoChange 2 ##e0.6 { tomh1:32 }
    tomh1:32
    \tempoChange 32 6/5 ##e0.6 { tomh1:32 }
    tomh1:32
    \tempoChange 32 #(/ #e0.6) 0 { tomh1:32 }
    tomh1:32
  }
  \midi {}
}
  

-- 
David Kastrup

Reply via email to