Hi Kieren,

sorry for the late reply.

Am So., 8. Sept. 2019 um 21:29 Uhr schrieb Kieren MacMillan
<kieren_macmil...@sympatico.ca>:
>
> Hi Harm,
>
> Three questions on this [seemingly-ancient!] thread about your (wonderful) 
> "dynamics on the fly" function:

You likely mean this thread:
http://lilypond.1069038.n5.nabble.com/improving-Janek-s-dynamic-function-for-combo-dynamics-td205071.html

>
> 1. Have you, as you implied might happen, found better ways to do the same 
> thing(s) in light of recent development efforts in the basecode?

As you may have imagined from the delayed response I hardly find time
to work with or on LilyPond these days.
Attached you'll find the file which I used for some serious
typesetting work (thus the file-name).
Not sure how much it goes beyond what I already had posted.
But it contains no really new approach.
There are explanations in the file, mostly in the comments in \layout
of the example and in the doc-string of `dynamicH´

>
> 2. How can I eliminate the resulting grob from quoted material? The normal 
> attempts (e.g., \omit DynamicText) don’t seem to work all the time.

Could you post a minimal?

>
> 3. When the custom dynamic consists of a dynamic text and normal text, I’d 
> like to add a tiny bit more space/padding between them. Where in the function 
> can I do this? And would it be possible to adjust the kerning depending on 
> which dynamic text is present?

The spacing between dynamic and normal text could be set in the
attached file with
DynamicText.details.outer-x-space

Not sure what you mean with your last question. Could you give an example?


I general I'm not sure when I'll find the time to look at it again.
But you never know ...

Best,
  Harm
%%%% written for 2.19.65


%% To test the example below uncomment:
%\include "etym-III-scheme.ly"

#(define (note-column::main-extent grob)
"Return extent of the noteheads in the 'main column', (i.e. excluding any
suspended noteheads), or extent of the rest (if there are no heads)."
  (let* ((note-heads (ly:grob-object grob 'note-heads))
         (stem (ly:grob-object grob 'stem))
         (rest (ly:grob-object grob 'rest)))
    (cond ((ly:grob-array? note-heads)
           (let (;; get the cdr from all note-heads-extents, where the car
                 ;; is zero
                 (n-h-right-coords
                   (filter-map
                     (lambda (n-h)
                       (let ((ext (ly:grob-extent n-h grob X)))
                          (and (= (car ext) 0) (cdr ext))))
                     (ly:grob-array->list note-heads))))
             ;; better be paranoid, find the max of n-h-right-coords and return
             ;; a pair with (cons 0 <max>)
             (cons 0.0 (reduce max 0 n-h-right-coords))))
          ((ly:grob? rest)
           (ly:grob-extent rest grob X))
          ;; better be paranoid
          (else '(0 . 0)))))
          
#(define remove-empty
  ;; Remove empty strings and empty lists from the given list 'lst'
  (lambda (lst)
    (remove
      (lambda (e)
        (or
          (and (string? e) (string-null? e))
          (and (list? e) (null? e))))
      lst)))
      
#(define char-set:dynamics
  (char-set #\f #\m #\p #\r #\s #\z))

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% DynamicText, created on the fly
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Reads
%%%%  DynamicText.details.separator-pair
%%%%  DynamicText.details.dyn-rest-font-sizes
%%%%  DynamicText.details.markup-commands
%%%%  DynamicText.details.inner-x-space
%%%%  DynamicText.details.outer-x-space


#(use-modules (srfi srfi-11))
#(use-modules (ice-9 regex))

#(define (make-reg-exp separator-pair)
  (format #f "\\~a[^~a~a]*\\~a"
    (car separator-pair)
    (car separator-pair)
    (cdr separator-pair)
    (cdr separator-pair)))

#(define (dynamics-list separator-pair strg)
  (let ((reg-exp (make-reg-exp separator-pair))
        (separators (char-set (car separator-pair) (cdr separator-pair))))
    (map
      (lambda (s)
        (let* ((match (string-match reg-exp s)))
           (if match
               (let* ((poss-dyn (match:substring match))
                      (cand (string-trim-both poss-dyn separators)))
                 (if (string-every char-set:dynamics cand)
                       (list
                         (match:prefix match)
                         cand
                         (match:suffix match))
                     s))
               s)))
      (string-split strg #\space))))

#(define (dynamic-text::format-text
           fontsizes inner-kern outer-kern text-markup-command lst)
  (let* ((mrkp-cmnd
           (lambda (arg) (make-normal-text-markup (text-markup-command arg))))
         (txt-font-size (if (pair? fontsizes) (cdr fontsizes) #f))
         (txt-mrkp-cmnd
           (lambda (txt)
             (if (number? txt-font-size)
                 (make-fontsize-markup txt-font-size (mrkp-cmnd txt))
                 (mrkp-cmnd txt))))
         (left-out (if (pair? outer-kern) (car outer-kern) #f))
         (left-inner (if (pair? inner-kern) (car inner-kern) #f))
         (right-inner (if (pair? inner-kern) (cdr inner-kern) #f))
         (right-out (if (pair? outer-kern) (cdr outer-kern) #f))
         (space-mrkp-cmd
           (lambda (space)
             (if (number? space)
                 (txt-mrkp-cmnd (make-hspace-markup space))
                 ""))))
    (map
      (lambda (e)
        (if (list? e)
            (remove-empty
              (list
                (cond ((and (string-null? (car e)) (equal? e (car lst))) '())
                      ((string-null? (car e))
                        (space-mrkp-cmd left-out))
                      ((and (not (string-null? (car e))) (equal? e (car lst)))
                        (make-concat-markup
                        (remove-empty
                          (list
                            (txt-mrkp-cmnd (car e))
                            (space-mrkp-cmd left-inner)))))
                      (else
                        (make-concat-markup
                        (remove-empty
                          (list
                            (space-mrkp-cmd left-out)
                            (txt-mrkp-cmnd (car e))
                            (space-mrkp-cmd left-inner))))))
                (second e)
                (cond ((and (string-null? (last e)) (equal? e (last lst))) '())
                      ((string-null? (last e))
                        (space-mrkp-cmd right-out))
                      ((and (not (string-null? (last e)))
                            (equal? e (last lst)))
                        (make-concat-markup
                        (remove-empty
                          (list
                            (space-mrkp-cmd right-inner)
                            (txt-mrkp-cmnd (last e))))))
                      (else
                        (make-concat-markup
                        (remove-empty
                          (list
                            (space-mrkp-cmd right-inner)
                            (txt-mrkp-cmnd (last e))
                            (space-mrkp-cmd right-out))))))))
            (make-line-markup (list (txt-mrkp-cmnd e)))))
      lst)))

#(define (get-string-indices lst)
  (filter-map
    (lambda (e c) (if (string? e) c #f))
    lst
    (iota (length lst))))

#(define (dynamic-text::structered-list
           separators fontsizes inner-kern outer-kern markup-commands idx strg)
  (let* ((ls (dynamics-list separators strg))
         (dynamic-fontsize (if (pair? fontsizes) (car fontsizes) #f))
         (dyn-mrkp-cmnd (car markup-commands))
         (dynamic-mrkp-cmnd
           (lambda (txt)
             (if (number? dynamic-fontsize)
                 (make-fontsize-markup dynamic-fontsize
                   (make-normal-text-markup (dyn-mrkp-cmnd txt)))
                 (make-normal-text-markup (dyn-mrkp-cmnd txt)))))
         (formated-dyns
           (dynamic-text::format-text
             fontsizes
             inner-kern
             outer-kern
             (cdr markup-commands)
             ls))
         (spaced-formated-dyns
           (list-insert-separator formated-dyns (make-simple-markup " ")))
         (spaced-plain
           (append-map
             (lambda (y) (if (markup-list? y) y (list y)))
             spaced-formated-dyns))
         (spaced-with-dyn
           (map
             (lambda (e)
               (if (string? e)
                   (dynamic-mrkp-cmnd e)
                   e))
             spaced-plain))
         (string-spaced-indices (get-string-indices spaced-plain))
         ;; if idx exceeds, print a warning and use first possible
         ;; dynamic
         ;; if idx is negative, due to (1- idx) in the function-body of dynamicH
         ;; return #f, same for if (null? string-spaced-indices). Meaning no
         ;; dynamics are indicated.
         ;; This will finally return (with dynamicH) a left align dynamic.
         (dyn-pos
           (cond ((or (negative? idx) (null? string-spaced-indices)) #f)
                 ((>= idx (length string-spaced-indices))
                   (begin
                     (ly:warning
                       "requested dynamic to align does not exist, ignoring")
                     (car string-spaced-indices)))
                 (else (list-ref string-spaced-indices idx))))
         ;(foo (format #t "##########: ~a\n"  dyn-pos))
         ;; NB: values!
         (splitted-at-dyn-index
           (if dyn-pos
               (split-at spaced-with-dyn dyn-pos)
               spaced-with-dyn)))
    (if (list? splitted-at-dyn-index)
        splitted-at-dyn-index
        (let-values (((before dyn&else) splitted-at-dyn-index))
          (cons*
             before
             (if (pair? dyn&else)
                 (list (car dyn&else) (cdr dyn&else))
                 dyn&else))))))

dynamicH =
#(define-event-function (parser location idx strg)
  ((index? 1) string?)
  "Returns customized DynamicText derived from @var{strg}.
Parts which should be rendered with as dynamics should be entered by
surrounding them with the elements of @code{details.separator-pair}, default is
@code{(cons #\\{ #\\})}.
The output is done by using the procedures from @code{details.markup-commands},
defaulting to @code{(cons make-dynamic-markup make-italic-markup)}.
Further customizing is possible by using
@code{details.dyn-rest-font-sizes}, needs a pair, default is unset
@code{details.inner-x-space}, needs a pair, default is unset
@code{details.outer-x-space}, needs a pair, default is is unset
The optional @var{idx} determines which dynamic part is centered under the
NoteColumn (in case @var{strg} contains multiple dynamics).
"
  (let* ((dynamic (make-music 'AbsoluteDynamicEvent))
         (tweak-proc
           (lambda (grob)
             (let* (
                    (separator-pair
                      (assoc-get
                        'separator-pair
                        (ly:grob-property grob 'details)
                        (cons #\{ #\})))
                    ;; get the fontsizes to use from the relevant
                    ;; details-sub-property, i.e. 'dyn-rest-font-sizes
                    (dyn-rest-font-sizes
                      (assoc-get
                        'dyn-rest-font-sizes
                        (ly:grob-property grob 'details)))
                    ;; get the markup-commands to use from the relevant
                    ;; details-sub-property, i.e. 'markup-commands, a pair
                    ;; car for dynamic, cdr for the rest
                    (markup-commands
                      (assoc-get
                        'markup-commands
                        (ly:grob-property grob 'details)
                        (cons make-dynamic-markup make-italic-markup)))
                    ;; get the pair-value to use for inserting some space to the
                    ;; left and/or right of the dynamic, usefull for bracketed
                    ;; dynamics or dynamics with punctuations
                    (inner-kern
                      (assoc-get
                        'inner-x-space
                        (ly:grob-property grob 'details)))
                    ;; get the pair-value to use for inserting some space
                    ;; between the dynamic expression and other text.
                    (outer-kern
                      (assoc-get
                        'outer-x-space
                        (ly:grob-property grob 'details)))
                    (stil-candidates
                      (dynamic-text::structered-list
                        separator-pair
                        dyn-rest-font-sizes
                        inner-kern
                        outer-kern
                        markup-commands
                        (1- idx)
                        strg))
                    (all-stils
                      (map
                        (lambda (mrkp)
                          (if (null? mrkp)
                              empty-stencil
                              (grob-interpret-markup grob
                                (if (markup-list? mrkp)
                                    (make-concat-markup mrkp)
                                    mrkp))))
                          stil-candidates))
                    (prev-self-alignment-X-tweaks
                      (filter
                        (lambda (tw)
                          (eq? (car tw) 'self-alignment-X))
                        (ly:prob-property
                          (ly:grob-property grob 'cause)
                          'tweaks))))

             (begin
               ;; Next line should be used for 2.19.65 and above
               ;(ly:grob-set-property! grob 'stencil
               ;  (stack-stencils X RIGHT 0 all-stils))
               ;; This line is for 2.18.2, though sometimes the offset in x-axis
               ;; is a little off
               (ly:grob-set-property! grob 'text
                 (make-stencil-markup (stack-stencils X RIGHT 0 all-stils)))
               ;; if previous tweak for self-alignment-X is present return '()
               (if (pair? prev-self-alignment-X-tweaks)
                   '()
                   (ly:grob-set-property! grob 'X-offset
                     (let* ((x-exts
                              (map
                                (lambda (stil) (ly:stencil-extent stil X))
                                (take all-stils 2)))
                            (x-par (ly:grob-parent grob X))
                            (parent-x-ext-center
                              (interval-center
                                (if (ly:grob-property grob
                                      'X-align-on-main-noteheads)
                                    (note-column::main-extent x-par)
                                    (ly:grob-extent x-par x-par X))))
                            ;; Get previous tweaks for X-offset and add their
                            ;; values
                            ;; They are added to the final result
                            (prev-x-offset-tweaks
                              (filter
                                (lambda (tw)
                                  (and (number? (cdr tw))
                                       (eq? (car tw) 'X-offset)))
                                (ly:prob-property
                                  (ly:grob-property grob 'cause)
                                  'tweaks)))
                            (prev-x-off
                              (apply + (map cdr prev-x-offset-tweaks))))
                       (if (markup-list? stil-candidates)
                           ;; For text only or if idx is set zero: align center.
                           ;; Also possible would be to left align, by switching
                           ;; to zero.
                           (ly:grob-property grob 'X-offset)
                           ;
                           (+
                              prev-x-off
                              (-
                                 parent-x-ext-center
                                 (interval-length (car x-exts))
                                 (/ (interval-length (second x-exts)) 2)
                                 (cond ((and (ly:stencil-empty? (car all-stils))
                                          (negative? (car (second x-exts))))
                                        (car (second x-exts)))
                                       ((negative? (car (first x-exts)))
                                        (car (first x-exts)))
                                       (else 0)))))))))))))

    (set! (ly:music-property dynamic 'tweaks)
          (acons 'before-line-breaking
                 tweak-proc
                 (ly:music-property dynamic 'tweaks)))
    dynamic))


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% EXAMPLES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% {

\version "2.19.65"
tst = "foo {mf} poco, poco ---{f}- piu, {p}! {f} {p} {ff} {ppp}"
%tst = "{mf} poco, poco -{f}- piu ,{p}! {f} {p} {ff} {ppp}"
%tst = "some text only"

\score {
  <<
  \new Staff \with { instrumentName = "\\dynamicH" }
    { c'1\dynamicH 2 \tst }
  \new Staff \with { instrumentName = "default" }
    { c'1 -$(make-dynamic-script
              (make-normal-text-markup
                (make-italic-markup "some text only"))) }
  \new Staff \with { instrumentName = "default" }
    { c'1 \mf }
  \new Staff \with { instrumentName = "default" }
    { c'1 \f }
  \new Staff \with { instrumentName = "default" }
    { c'1 \p }
  %% helper for better viewing
  \addlyrics % \with { \override LyricText.parent-alignment-X = #LEFT }
    { \markup \with-dimensions #'(0 . 0) #'(0 . 0) \draw-line #'(0 . 300) }
  >>
  \layout {
    %% DynamicText may be customized with overrides like below
    %% Currently given are the defaults
    
    %% Text which should be printed using `char-set:dynamics´ needs to be 
    %% wrapped into therefore reserved characters. Below the suggested default.
    \override DynamicText.details.separator-pair = #(cons #\{ #\})
    
    %% The subproperty `details.markup-commands´ determines which 
    %% markup-commands should be used:
    %% first value of the pair used to render dynamics, second for other text
    %% Below the suggested default.
    \override DynamicText.details.markup-commands =
    #(cons make-dynamic-markup make-italic-markup)
    %% Other coding-examples for `details.markup-commands´:

    %\override DynamicText.details.markup-commands =
    %  #(cons
    %    (lambda (arg) (make-normal-text-markup (make-box-markup arg)))
    %    make-underline-markup)
    
    %\override DynamicText.details.markup-commands =
    %  #(cons
    %     (lambda (arg)
    %       (markup
    %         #:normal-text
    %         #:override '(box-padding . 0.5)
    %         #:override '(thickness . 3)
    %         #:box
    %         #:bold
    %         #:override '(font-name . "LilyJazz")
    %         arg))
    %     (lambda (arg)
    %       (markup
    %         ;; Limitation:
    %         ;; underline returns a nice output by accident!
    %         ;; undertie not
    %         ;; Reason: every single part of the text markup needs to be
    %         ;; processed separately, otherwise the offsetting calculation will
    %         ;; be broken
    %         #:underline
    %         #:override '(font-name . "Purisa")
    %         arg)))
    
    %% Dynamics and other texts may have different fontsize via an override
    %% for `details.dyn-rest-font-sizes´
    %% First value of the pair used to determine fontsize of dynamics, second
    %% for other text. 
    %% Unset per default, in this case the value from `DynamicText.font-size´ is
    %% taken.
    %% If set value from `DynamicText.font-size´ is added.
    %\override DynamicText.details.dyn-rest-font-sizes = #'(10 . -5)
    
    %% The space left and right from a dynamic is customizable:
    %% If the input-string contains something like "--{p}--", then the space 
    %% between left/right "--" and "p" is settable by `details.inner-x-space´
    %% Unset per default
    %\override DynamicText.details.inner-x-space = #'(0 . 0)
    
    %% Adds space around the whole dynamic text-part:
    %\override DynamicText.details.outer-x-space = #'(4 . 4)
    
    %% Both together work like:
    %% <outer-x-space>"--"<inner-x-space>"p"<inner-x-space>"--"<outer-x-space>
    %% Only here for conveniant viewing:
    \override DynamicText.after-line-breaking =
      #(lambda (grob)
        (ly:grob-set-property! grob 'stencil
          (box-stencil
            (ly:grob-property grob 'stencil)
            0
            0)))
  }
}
%}


_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user

Reply via email to