lilypond-user
[Top][All Lists]
Advanced

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

Re: `TextSpanner` vs. `DynamicTextSpanner`


From: Jean Abou Samra
Subject: Re: `TextSpanner` vs. `DynamicTextSpanner`
Date: Fri, 4 Mar 2022 09:37:46 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.5.0

Le 04/03/2022 à 05:00, Werner LEMBERG a écrit :
Is there a similar auxiliary grob for `TextSpanner`?
No, since consecutive text spanners are not aligned vertically.

{
   c'1\tweak bound-details.left.text "aaa" \startTextSpan
   c'1\stopTextSpan\tweak bound-details.left.text "aaaa"\startTextSpan
   c'1\stopTextSpan
}


Maybe they should be for tempo indications?
Sometimes, this would be very helpful, yes (see attached image from
the last scene of 'Wozzeck').  I guess a possible work-around would be
to (ab)use `DynamicTextSpanner` for that.



If you don't need dynamic spanners and tempo spanners at the
same time, that will work, yes. There is also this kind of code:

\version "2.22.1"

#(use-modules (ice-9 match)
              (srfi srfi-26))

#(define (define-grob! grob-name grob-entry)
   (set! all-grob-descriptions
         (cons ((@@ (lily) completize-grob-entry)
                (cons grob-name grob-entry))
               all-grob-descriptions)))

#(define-grob!
  'TempoLineSpanner
  `((axes . (,Y))
    (cross-staff . ,ly:side-position-interface::calc-cross-staff)
    (direction . ,UP)
    (minimum-space . 1.2)
    (outside-staff-priority . 250)
    (padding . 0.6)
    (side-axis . ,Y)
    (slur-padding . 0.3)
    (staff-padding . 0.1)
    (vertical-skylines . ,grob::always-vertical-skylines-from-element-stencils)
    (X-extent . ,ly:axis-group-interface::width)
    (Y-extent . ,axis-group-interface::height)
    (Y-offset . ,side-position-interface::y-aligned-side)
    (meta . ((class . Spanner)
             (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)                                   (pure-relevant-grobs . ,ly:axis-group-interface::calc-pure-relevant-grobs)))
             (interfaces . (axis-group-interface
                            outside-staff-interface
                            side-position-interface))))))

#(ly:add-interface 'text-spanner-interface "" '())

#(define (transform-in-path! alist path transformer)
   (match path
     (() (transformer alist))
     ((p . rest) (assq-set! alist p (transform-in-path! (assq-ref alist p)
                                                        rest
transformer)))))

#(set! all-grob-descriptions
       (transform-in-path! all-grob-descriptions
                           '(TextSpanner meta interfaces)
                           (cute cons 'text-spanner-interface <>)))


#(define (Tempo_align_engraver context)
   (let ((baseline #f)
         (tempo-found #f)
         (last-tempo-active #f)
         (direction #f))
     (define (end-baseline!)
       (let ((column (ly:context-property context 'currentMusicalColumn)))
         (ly:spanner-set-bound! baseline RIGHT column)
         (if direction
             (begin
               (ly:grob-set-property! baseline 'direction direction)
               (set! direction #f)))
         (set! baseline #f)))
     (make-engraver
      (acknowledgers
       ((text-spanner-interface engraver grob source-engraver)
          (let ((ev (event-cause grob)))
            (if (ly:event-property ev 'is-tempo #f)
                (let ((d (ly:event-property ev 'direction #f))
                      (column (ly:context-property context 'currentMusicalColumn)))
                  (set! tempo-found #t)
                  (set! last-tempo-active #t)
                  (ly:grob-set-property! grob 'Y-offset 0)
                  (ly:grob-set-nested-property! grob
                                                '(bound-details right attach-dir)
                                                LEFT)
                  (cond
                   ((not baseline)
                    (set! baseline (ly:engraver-make-grob engraver 'TempoLineSpanner grob))
                    (set! direction d)
                    (ly:spanner-set-bound! baseline LEFT column)
                    (ly:axis-group-interface::add-element baseline grob))
                   ((and (not direction)
                         d)
                    ;; Adding spanner with forced direction to baseline
                    ;; without forced direction, forcing the direction
                    ;; of the baseline.
                    (set! direction d)
                    (ly:grob-set-property! baseline 'direction direction)
                    (ly:axis-group-interface::add-element baseline grob))
                   ((not direction)
                    ;; No direction constraints
                    (ly:axis-group-interface::add-element baseline grob))
                   ((or (not d)
                        (eqv? d direction))
                    ;; Baseline has forced direction and the new tempo spanner's
                    ;; is compatible with it.
                    (ly:axis-group-interface::add-element baseline grob))
                   (else
                    ;; Incompatible directions, break baseline.
                    (end-baseline!)
                    (set! baseline (ly:engraver-make-grob engraver 'TempoLineSpanner grob))
                    (set! direction d)
                    (ly:spanner-set-bound! baseline LEFT column)
                    (ly:axis-group-interface::add-element baseline grob))))))))
       (end-acknowledgers
        ((text-spanner-interface engraver grob source-engraver)
           (let ((ev (event-cause grob)))
             (if (ly:event-property ev 'is-tempo #f)
                 (set! last-tempo-active #f)))))
       ((stop-translation-timestep engraver)
          (if (and baseline
                   (not last-tempo-active)
                   (not tempo-found))
              (end-baseline!))
          (set! tempo-found #f))
       ((finalize engraver)
          (if baseline
              (end-baseline!))))))

\layout {
  \context {
    \Global
    \grobdescriptions #all-grob-descriptions
  }
  \context {
    \Staff
    \consists #Tempo_align_engraver
  }
}

startTempoSpan =
#(define-event-function (text) (markup?)
   #{ \withMusicProperty #'is-tempo ##t \tweak bound-details.left.text #text \startTextSpan #})

stopTempoSpan = \stopTextSpan

%%

{
  c'1\startTempoSpan "rit."
  1\stopTempoSpan\startTempoSpan "acc."
  1\stopTempoSpan
  1_\startTempoSpan "rit."
  1\stopTempoSpan \startTempoSpan "acc."
  1\stopTempoSpan
  1\startTempoSpan "rit."
  1\stopTempoSpan_\startTempoSpan "acc."
  1\stopTempoSpan
  1_\startTempoSpan "rit."
  1\stopTempoSpan_\startTempoSpan "acc."
  1\stopTempoSpan
  1^\startTempoSpan "rit."
  1_\startTempoSpan "acc." \stopTempoSpan
  1\stopTempoSpan
}




But then, it's more a matter of adding dedicated grobs since I don't
think it would be desirable to do this for all text spanners --
nothing prevents overlapping text spanners, unlike, say, overlapping
hairpins (in the same voice, that is), so I don't think there is a
reason to make them continuous.
What do you mean with 'dedicated grobs'?



A TempoSpanner and a TempoLineSpanner grob, created by \startTempo
and \stopTempo (or whatever names). See issue #3176.


Jean




reply via email to

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