[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