lilypond-devel
[Top][All Lists]
Advanced

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

Re: MIDI rendition of things like rall./acc./rit./fermata


From: David Kastrup
Subject: Re: MIDI rendition of things like rall./acc./rit./fermata
Date: Sun, 13 Jun 2021 18:36:06 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux)

David Kastrup <dak@gnu.org> writes:

> Dan Eble <dan@faithful.be> writes:
>
>> On Jun 12, 2021, at 18:48, David Kastrup <dak@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

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