lilypond-devel
[Top][All Lists]
Advanced

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

Re: Scheme performers/translators


From: David Kastrup
Subject: Re: Scheme performers/translators
Date: Wed, 29 Sep 2021 21:39:26 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux)

David Kastrup <dak@gnu.org> writes:

> So I tried the following
>
> Stress_performer =
> #(define-scheme-function (strong weak) (index? index?)
>    (lambda (ctx)
>      (define fired #f)
>      (define (emit weight)
>        (ly:broadcast (ly:event-source ctx)
>                    (ly:make-stream-event
>                     (ly:make-event-class 'articulation-event)
>                     `((articulation-type . "accent")
>                       (midi-extra-velocity . ,weight)))))
>      (make-engraver
>       ((stop-translation-timestep c) (set! fired #f))
>        ; TODO: don't go against syncopation: if there has been an
>        ; explicit accent less than a beat ago, don't do anything
>       (listeners ((note-event performer event)
>                 (if (not fired)
>                     (let ((mp (ly:context-property ctx 'measurePosition))
>                           (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)))
>                       (set! fired #t)
>                       (and (zero? (ly:moment-grace mp))
>                            (zero? (ly:moment-main (ly:moment-mod mp bm)))
>                            (let loop ((mp (ly:moment-main mp)) (bs bs) (w 
> strong))
>                              (cond ((zero? mp) (emit w))
>                                    ((positive? mp)
>                                     (if (pair? bs)
>                                         (loop (- mp (* bm (car bs))) (cdr bs) 
> weak)
>                                         (loop (- mp bm) bs weak)))))))))))))
>
>
> and it did nothing when used via
>
> \midi { \context { \DrumVoice \consists \Stress_performer 20 10 } }
>
> when the intent was that there should be additional midi velocity on the
> start of the bar and then on each beat.  Now the code, not having run,
> may very well be defective still.  But the point is that it doesn't even
> get called because a Scheme_engraver is an engraver and engravers are
> not getting called in \midi.
>
> This actually does nothing that couldn't be done in general by any
> translator: it doesn't even require to specifically be an engraver or
> performer.
>
> I am somewhat loth to just copy scheme-engraver.{cc,hh} to
> scheme-performer.{cc,hh}, throw out everything Engraver-specific
> (basically acknowledgers and possibly the associated processing phases)
> and get something pretty much the same for now.
>
> Does anybody have a better proposal?

Ok, I now fixed the performer for basic use:

Stress_performer =
#(define-scheme-function (strong weak) (index? index?)
   (lambda (ctx)
     (define fired #f)
     (define (emit weight)
       (ly:broadcast (ly:context-event-source ctx)
                     (ly:make-stream-event
                      (ly:make-event-class 'articulation-event)
                      `((articulation-type . "accent")
                        (midi-extra-velocity . ,weight)))))
     (make-engraver
      ((stop-translation-timestep c) (set! fired #f))
       ; TODO: don't go against syncopation: if there has been an
       ; explicit accent less than a beat ago, don't do anything
      (listeners ((note-event performer event)
                  (if (not fired)
                      (let* ((mp (ly:context-property ctx 'measurePosition))
                             (mpm (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)))
                        (set! fired #t)
                        (and (zero? (ly:moment-grace mp))
                             (integer? (/ mpm bm))
                             (let loop ((mp mpm) (bs bs) (w strong))
                               (cond ((zero? mp) (emit w))
                                     ((positive? mp)
                                      (if (pair? bs)
                                          (loop (- mp (* bm (car bs))) (cdr bs) 
weak)
                                          (loop (- mp bm) bs weak)))))))))))))

And it works as

  \midi {
    \context { \DrumVoice
               \consists \Stress_performer 20 10
             }
  }

as long as I apply the following simplistic patch:

diff --git a/lily/translator-group.cc b/lily/translator-group.cc
index 07ba2f0395..4447747b73 100644
--- a/lily/translator-group.cc
+++ b/lily/translator-group.cc
@@ -156,7 +156,9 @@ Translator_group::create_child_translator (SCM sev)
   if (dynamic_cast<Engraver_group *> (g))
     trans_list.remove_if ([] (SCM s) { return unsmob<Performer> (s); });
   else if (dynamic_cast<Performer_group *> (g))
-    trans_list.remove_if ([] (SCM s) { return unsmob<Engraver> (s); });
+    trans_list.remove_if ([] (SCM s) {
+      return unsmob<Engraver> (s)
+        && !unsmob<Scheme_engraver> (s); });
   g->simple_trans_list_ = trans_list.begin_scm ();
 
   // TODO: scrap Context::implementation

The question is whether we should do something like this as default,
possibly conditioned on whether any acknowledgers are present?  Because
even if we cannot react to Midi data structures (since they are not
Scheme-accessible for now), sometimes a translator may be enough to do
the trick.

-- 
David Kastrup



reply via email to

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