lilypond-user
[Top][All Lists]
Advanced

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

Re: improving Janek's \dynamic function (for combo dynamics)


From: Thomas Morley
Subject: Re: improving Janek's \dynamic function (for combo dynamics)
Date: Sat, 26 Aug 2017 15:13:08 +0200

2017-08-25 0:01 GMT+02:00 Kieren MacMillan <address@hidden>:
> Hi Saul,
>
>> Personally, I think the behavior would be better if it aligned on the first 
>> dynamic to appear in the markup, rather than default to left.
>
> Perhaps better if this is a preference/parameter, with the default being 
> *left-aligned* not *dynamic-aligned*.
> (I would personally keep it left-aligned, and then use the edition-engraver 
> to tweak the position of the rare "outliers".)
>
>> With something like "poco f", it can be visually unclear where the f is 
>> supposed to begin — at the beginning of "poco" or at the "f"? That's a bit 
>> clearer of the dynamic itself is always the alignment point (though I prefer 
>> to always have the dynamic first for maximum clarity).
>
> Gould (pg. 107) addresses this. There are definitely more ambiguities and 
> potential problems with dynamic-aligning such texts than there are "safe 
> situations" (e.g., with preceding rests) — which is why, like you, I always 
> prefer to have the dynamic first (when possible).
>
> Cheers,
> Kieren.

Hi all,

the here so far proposed codes fail, if punctuation comes into the game.
\new Staff { c''\dynamic  "poco f, but p sub. ma non troppo" }

Thus I based my own code on the previous work of Valentin Villenave:
https://codereview.appspot.com/2220041/
https://codereview.appspot.com/20660044/

One problem for the event-function persists:
To get the first dynamic-word center-aligned under the NoteColumn you
need to do some calculations for tweaking X-offset or
self-alignment-X. (I choosed X-offset because the calculation is a
little easier ...)
Whatever you choose, a certain tweak is hardcoded now. And further
tweaking after applying the event-function will at first not work:
Having set a hardcoded tweak for X-offset makes it impossible to get a
tweak for self-alignment-X to work, neither would an additional
X-offset-tweak work. If I would have gone for self-alignment-X in the
event-function further tweaks of the same property would not work
either.

I think that's what David K explained here:
http://lists.gnu.org/archive/html/lilypond-user/2017-08/msg00194.html

Thus I coded a possibilty to lookup for an additional X-offset-tweak,
which will add it's value to the setting caused by the event-function.
Theoretically this could be done with self-alignment-X as well, but I
regarded the results from a users points of view too unpredictable.

Here's the code:


\version "2.19.64"

#(define (char-punctuation? ch)
  (char-set-contains? char-set:punctuation ch))

#(define char-set:dynamics
  (char-set #\f #\m #\p #\r #\s #\z))

#(define composite-chars
  (char-set-union char-set:dynamics char-set:punctuation))

#(define-markup-command (dynamic-text layout props str) (string?)
  "Takes a string, puts out a line-markup.
Parts of @var{strg} containing only characters used for dynamics are printed
using \\dynamic (punctuation-signs are disregarded.
Other parts are printed \\italic.

@lilypond[verbatim,quote]
\\markup {
  \\dynamic-text #\"poco f, but p sub. ma non troppo\"
}
@end lilypond
"
  (let* ((str-list (string-split str #\space))
         (text-markup
           (lambda (s) (make-normal-text-markup (make-italic-markup s)))))
    (interpret-markup layout props
      (make-line-markup
        ;; iterate over 'str-list'
        ;; - parts only containing dynamics/punctuation are splitted.
        ;;   dynamics are printed \dynamic, others \italic
        ;;   and finally \concat is applied
        ;; - others are printed \italic
        (map
          (lambda (word)
            (if (string-every composite-chars word)
                (let ((word-lst (string->list word)))
                  (make-concat-markup
                    (map
                      (lambda (ch)
                        (let ((print-ch (string ch)))
                          (if (char-punctuation? ch)
                              (text-markup print-ch)
                              (make-dynamic-markup print-ch))))
                      word-lst)))
                (text-markup word)))
          str-list)))))

dynamicH =
#(define-event-function (strg) (string?)
"Takes a string and puts out a (composed) dynamic script.
If the first word of the composed string is a dynamic sign, the ready dynamic-
script center-aligns this word at the parent-grob.
Further adapting the result with additional tweaks for X-offset are possible.
"
  (let* ((first-word (car (string-split strg #\space)))
         ;; don't take punctuation into account
         (trimmed-first-word (string-trim-both first-word char-set:punctuation))
         (offset
           (lambda (grob)
             (let* (;; get previous tweaks for X-offset and add their values
                    ;; they are added to the final result
                    (x-offset-tweaks
                      (filter
                        (lambda (tw)
                          (and (number? (cdr tw)) (eq? (car tw) 'X-offset)))
                        (ly:prob-property
                          (ly:grob-property grob 'cause)
                          'tweaks)))
                    (x-off (apply + (map cdr x-offset-tweaks))))
               ;; if 'first-word' is a dynamic, calculate it's x-extent and
               ;; return half of it's value
               ;; always take 'x-off' into account
               (if (string-every composite-chars first-word)
                   (let* ((layout (ly:grob-layout grob))
                          (props
                            (ly:grob-alist-chain grob
                              (ly:output-def-lookup
                                layout
                                'text-font-defaults)))
                          (first-word-stil
                            (interpret-markup layout props
                              (make-dynamic-text-markup trimmed-first-word)))
                          (first-word-stil-center
                            (interval-center
                              (ly:stencil-extent first-word-stil X))))
                     (+ x-off (- first-word-stil-center)))
                    ;; adding -1 is my choice
                    (+ x-off -1))))))

    #{
      -\tweak X-offset $offset
      #(make-dynamic-script (make-dynamic-text-markup strg))
    #}))

%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% EXAMPLE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\new StaffGroup <<
  \new Staff { c''\dynamicH "fffff dramatically" }
  \new Staff { c''-\tweak X-offset -1 -\dynamicH "fffff dramatically" }
  \new Staff { c''-\tweak X-offset 1 -\dynamicH "fffff dramatically" }
  \new Staff { c''\dynamicH "fffff,,,,,,,,,, dramatically" }
  \new Staff { c''\dynamicH  "poco f, but p sub. ma non troppo" }
  \new Staff { c''\dynamicH "slightly more pp" }
>>


Though, because of the problems mentioned above I'm not sure whether
putting dynamic-script-creation _and_ settings for aligning it into
the same function.
The possibility to create dynamic-scripts on the fly and have them
aligned properly while having a nice user interface is nice, ofcourse,
but one needs to set more or less hardcoded defaults which then are
not changeable easily anymore, if at all.

HTH,
  Harm



reply via email to

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