[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
What I needed Scheme MIDI performers for...
From: |
David Kastrup |
Subject: |
What I needed Scheme MIDI performers for... |
Date: |
Thu, 07 Oct 2021 02:57:41 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) |
\include "articulate.ly"
Beat_performer =
#(define-scheme-function (strong weak) ((index? 25) (index?))
"Return a performer intended for instantiation in @samp{Voice}-like
contexts. @var{strong} indicates an additional MIDI velocity to be
applied on the first beat of the measure, @var{weak} applies on the
other beats, taking @code{beatStructure} into account where
applicable.
If @var{weak} is skipped by writing @code{\\default}, it is assumed
to be 60% of @var{strong}. If both are skipped, @var{strong} is taken
as @code{25}.
Off-beat manual use of @code{\\accent} or @code{\\marcato} causes
autogeneration of the next on-beat accent to be skipped."
(define (closest-beat ctx mp)
;; return the first on-beat measure position not before mp
(let* ((mp (ly:moment-main mp))
(tf (ly:context-property ctx 'timeSignatureFraction '(4 . 4)))
(bmm (ly:context-property ctx 'baseMoment))
(bm (if (ly:moment? bmm)
(ly:moment-main bmm)
(/ (cdr tf))))
(bs (ly:context-property ctx 'beatStructure)))
(let loop ((pos 0) (bs bs))
(cond ((>= pos mp) (ly:make-moment pos))
((pair? bs)
(loop (+ pos (* bm (car bs))) (cdr bs)))
(else
(loop (+ pos bm) bs))))))
(if (not weak)
(set! weak (floor (* #e0.6 strong))))
(lambda (ctx)
(define fired #f)
(define timeout #f)
(define (emit strong?)
(set! fired
(ly:make-stream-event
(ly:make-event-class 'articulation-event)
`(
;; We differentiate the "visuals" of the generated
;; events for debugging purposes: the performer is not
;; intended to be used while typesetting, but a
;; wrapper may add an "is-layout" property
(articulation-type . ,(if strong? "marcato" "accent"))
(midi-extra-velocity . ,(if strong? strong weak)))))
(ly:broadcast (ly:context-event-source ctx) fired))
(make-performer
((stop-translation-timestep c) (set! fired #f))
((process-music performer)
;; No syncope tracking across cadenze
(and timeout (not (ly:context-property ctx 'timing))
(set! timeout #f)))
(listeners
;; we have a listener for explicit articulation events in order
;; to let syncopated accents silence the next "regular" stress
((articulation-event performer event)
(cond ((eq? fired event)) ; ignore our own events
((member (ly:event-property event 'articulation-type)
'("accent" "marcato"))
(let ((mp (ly:context-property ctx
'measurePosition ZERO-MOMENT))
(now (ly:context-current-moment ctx)))
(set! timeout (ly:moment-add (closest-beat ctx mp)
(ly:moment-sub now mp)))))))
;; Listener for note events.
((note-event performer event)
(and (not fired)
(ly:context-property ctx 'timing)
(not (and timeout (moment<=? (ly:context-current-moment ctx)
timeout)))
(let ((mp (ly:context-property ctx 'measurePosition ZERO-MOMENT)))
(if (equal? mp (closest-beat ctx mp))
(emit (equal? mp ZERO-MOMENT))))))))))
\score {
\articulate
\drums
{
sn1:32 | 1:32 | 1:32 | 1 |
8 \repeat unfold 3 { <>-> 4:32 } <>-> 8:32 | 1:32 | 1:32 | 1 |
}
\midi {
\tempo 4=80
\context {
\DrumVoice
\consists \Beat_performer \default
}
}
\layout {
\context {
\DrumVoice
\consists #(lambda (c) `((is-layout . #t) ,@((Beat_performer
*unspecified*) c)))
}
}
}
I am typing some drum parts for our accordion orchestra into MIDI, and
multi-measure drum rolls become completely incoherent (or rather
completely coherent) without this. Try leaving off the performer...
--
David Kastrup
- What I needed Scheme MIDI performers for...,
David Kastrup <=