lilypond-devel
[Top][All Lists]
Advanced

[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

reply via email to

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