Simon, you wrote Friday, September 02, 2016 1:34 AM

Hi Simon,

>On 24.08.2016 11:51, Trevor Daniels wrote:
>> David Kastrup wrote Wednesday, August 24, 2016 7:48 AM
>>> "Trevor Daniels"<t.dani...@treda.co.uk>  writes:
>>>> Prompted by the recent discussion on lute tablature, I tried coding a
>>>> Scheme engraver to create the duration grobs but quickly ran into a
>>>> problem.  I need to collect information from both a Listener and an
>>>> Acknowledger so the obvious place to build the grob is in
>>>> stop-translator-timestep,
>>> No, no, no.  stop-translator-timestep really is only for cleanup work.
>>> Stuff is no longer in working order then.  You want process-acknowledged
>>> here I think.
>>>
>>> There will always be a call to process-acknowledged whenever grobs have
>>> been created, and_reading_  stuff from grobs should be delayed until
>>> then since other acknowledgers might_write_  stuff into a grob even
>>> after your personal acknowledger has been called.  So the basic workflow
>>> is to use the various acknowledgers to_record_  the grobs you are
>>> interested in and_write_  stuff into them (or do read/write stuff that
>>> more or less is accumulative and/or really unrelated to other
>>> engravers), and then use the process-acknowledged hook for processing
>>> (including_reading_) the grobs you had recorded.
>>>
>>> You can create new grobs in process-acknowledged.  That will lead to a
>>> new cycle of acknowledger calls followed by process-acknowledged.  Only
>>> when all those cycles are over is stop-translator-timestep called, and
>>> then creating grobs is no longer an option.
>>
>> Thanks David.  That's beautifully clear.
>
> I just caught up with all the mailing lists, being back from holiday, 
> and I’d be interested in a working example for this solution. Would you 
> mind sharing it?

There already is a helpful working example in the code base.  See

input/regression/scheme-engraver.ly

This doesn't go as far as creating new grobs, so I've attached a
simple example that does.  This is a bit of a hack, used as part of
a learning process, and a bit messy as it evolved from an earlier
attempt, but it illustrates one way.

Actually, comments from the experts on this would be very helpful.

Trevor
\version "2.19.40"

% Example of using Scheme engraver to add markup based on note duration

% Avoids repeated durations on both chords and consecutive notes

%{
TODO
  Handle notes with different durations at one musical moment better
  Add dots
  Add bass courses
%}

#(define (t->m t)
   "Return the current moment of translator object @var{t}."
   (ly:context-current-moment (ly:translator-context t)))

% persistent variables for Lute_tab_duration_engraver
#(define previous-duration-log #f)	% to supress repeated durations
#(define ev #f)		% event
#(define en #f)		% engraver

Lute_tab_duration_engraver =
#(make-engraver
   ((initialize translator)
    (format 1 "\n\n~16a: (initialize)\n" (t->m translator)))
   ((start-translation-timestep translator)
    (set! ev #f)
    (set! en #f)
    (format 1 "~16a: (start-translation-timestep)\n" (t->m translator)))
   (listeners
     ((note-event engraver event)
      ; Save just the last event at each timestep
      ;TODO save shortest duration event?
      (set! ev event)
      (set! en engraver)
      (format 1 "~16a: detected this note event: ~a\n "
                (t->m engraver) event)))
   (acknowledgers
     ((note-head-interface engraver grob source-engraver)
      (format 1 "~16a: saw ~a coming from ~a\n"
              (t->m engraver) grob source-engraver)))
   (end-acknowledgers
     ((beam-interface engraver grob source-engraver)
      (format 1 "~16a: saw end of ~a coming from ~a\n"
              (t->m engraver) grob source-engraver)))
   ((process-music translator)
    (format 1 "~16a: (process-music)\n" (t->m translator))
    (if ev
      (let ((duration-log
             (ly:duration-log (ly:event-property ev 'duration))))
        (display duration-log)
        (if (not (equal? duration-log previous-duration-log))
            (let ((grob (ly:engraver-make-grob en 'TextScript ev)))
              (set! previous-duration-log duration-log)
              (ly:grob-set-property! grob 'direction UP)
              (ly:grob-set-property! grob 'text
                (case duration-log
                  ((2) (markup (#:musicglyph "rests.M2mensural")))
                  ((3) (markup (#:musicglyph "flags.mensuralu03")))
                  ((4) (markup (#:musicglyph "flags.mensuralu04")))
                  ((5) (markup (#:musicglyph "flags.mensuralu05")))
                  ((6) (markup (#:musicglyph "flags.mensuralu06")))
                  (else (markup " ")))))))))
   ((process-acknowledged translator)
    (format 1 "~16a: (process-acknowledged)\n" (t->m translator)))
   ((stop-translation-timestep translator)
    (format 1 "~16a: (stop-translation-timestep)\n" (t->m translator)))
   ((finalize translator)
    (format 1 "~16a: (finalize)\n" (t->m translator))))

notes = \relative c'' {
        \time 3/4
        \partial 4.
	a8 r a |
	<f d>4. f8 <g e>4 |
	\break
        \time 4/4
	c1 |
        cis2 d4 ees8 e16 f32 fis64 g64 |
        gis16 a16 bes8 c cis d ees e f |
        fis g gis a bes b c cis |
}

\score {
 <<
  \new Staff {
    \new Voice {
      \notes
    }
  }
  \new TabStaff
  \with {
    % Use letters to indicate frets
    tablatureFormat = #fret-letter-tablature-format
    % Usual string tuning for 6-course Baroque lute
    stringTunings = #`(,(ly:make-pitch 1 3 NATURAL)
                       ,(ly:make-pitch 1 1 NATURAL)
                       ,(ly:make-pitch 0 5 NATURAL)
                       ,(ly:make-pitch 0 3 NATURAL)
                       ,(ly:make-pitch 0 1 NATURAL)
                       ,(ly:make-pitch -1 5 NATURAL))
    % Choose a suitable font for fret letters
    \override TabNoteHead.font-name = #"Fronimo Gavotta"
    \override Flag.style = #'straight
    \revert TextScript.stencil
  }
  {
    \new TabVoice
    \with {
      % Baroque tab uses slurs
      \consists "Fingering_engraver"
      \consists "New_fingering_engraver"
      \consists \Lute_tab_duration_engraver
      \revert Slur.stencil
    }
    {
      \textLengthOn
%      \applyMusic #(lambda (x) (music-map add-duration x))
      \notes
    }
  }
 >>
}



%{
convert-ly.py (GNU LilyPond) 2.19.43  convert-ly.py: Processing `'...
Applying conversion: 2.13.10, 2.13.16, 2.13.18, 2.13.20, 2.13.27,
2.13.29, 2.13.31, 2.13.36, 2.13.39, 2.13.40, 2.13.42, 2.13.44,
2.13.46, 2.13.48, 2.13.51, 2.14.0, 2.15.7, 2.15.9, 2.15.10, 2.15.16,
2.15.17, 2.15.18, 2.15.19, 2.15.20, 2.15.25, 2.15.32, 2.15.39,
2.15.40, 2.15.42, 2.15.43, 2.16.0, 2.17.0, 2.17.4, 2.17.5, 2.17.6,
2.17.11, 2.17.14, 2.17.15, 2.17.18, 2.17.19, 2.17.20, 2.17.25,
2.17.27, 2.17.29, 2.17.97, 2.18.0, 2.19.2, 2.19.7, 2.19.11, 2.19.16,
2.19.22, 2.19.24, 2.19.28, 2.19.29, 2.19.32, 2.19.40
%}
_______________________________________________
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel

Reply via email to