Hi David,

thank you for your head start.
See my attached results. I'd be grateful for any comments to improve the coding. One basic question is if it will be possible to extend it with other types (dynamic text spanners etc.) without having to write another engraver with duplicating code. And unfortunately the attached file compiles, while applying it to a real-world file I get an error:

In procedure ly:grob-set-property! in expression (ly:grob-set-property! (car equal-hairpins) (quote color) ...):

/home/uliska/git/bfsc/fried/das-trunkne-lied/library/ly/to-lilylib/remove-double-hairpins-engraver.ily:91:19 <1>: Wrong type argument in position 1 (expecting Grob): (#<Grob Hairpin > #<Grob Hairpin >)


Looks quite similar to the problems I had during development, but I don't see yet what is actually wrong with it.

Best
Urs

Am 11.04.2015 um 16:07 schrieb David Nalesnik:


On Sat, Apr 11, 2015 at 9:01 AM, David Nalesnik <david.nales...@gmail.com <mailto:david.nales...@gmail.com>> wrote:

    Hi Urs,

    On Sat, Apr 11, 2015 at 3:31 AM, Urs Liska <u...@openlilylib.org
    <mailto:u...@openlilylib.org>> wrote:

        Hi,

        this is related to my previous thread and particularly to the
        file attached to
        http://lists.gnu.org/archive/html/lilypond-user/2015-04/msg00263.html

        If I have a Scheme engraver listening to TextScript-s I can
        get a list of entries at the same timestep and then compare
        them for equality.
        This even works without changes for DynamicText because that
        also has a 'text property. But if i have spanners such as
        hairpins it's not that simple anymore. So I'm asking myself if
        I can access the starting and ending timesteps of hairpins
        that are present in such a list. Of course I can collect
        hairpins in a list like I can collect TextScripts (currently
        I'm listening for line-interface). But is it possible to
        retrieve the start *and* end position of such items?

        The goal is to iterate over the list and find matching
        hairpins to remove duplicate ones.


    A simple way to determine when a hairpin starts and ends is by
    using an acknowledger and an end-acknowledger:

     myEngraver =
    #(lambda (context)
         (make-engraver
          (acknowledgers
           ((hairpin-interface engraver grob source-engraver)
            (format #t "My start is at ~a~%"
    (ly:context-current-moment context))))
          (end-acknowledgers
           ((hairpin-interface engraver grob source-engraver)
            (format #t "My end is at ~a~%" (ly:context-current-moment
    context))))
         ))

    \layout {
      \context {
        \Score
        \consists \myEngraver
      }
    }

    {
      c''1~\<
      c''1\!
      c''2.\< c''4\!
      c''1~\>
      \break
      c''2~ c''\!
    }


    If you're collecting the hairpins for processing later, you could
    find the timings of beginnings and endings through the columns at
    their bounds:

    myEngraver =
    #(lambda (context)
       (let ((hairpins '()))
         (make-engraver
          (acknowledgers
           ((hairpin-interface engraver grob source-engraver)
            (set! hairpins (cons grob hairpins))))
          ((finalize trans)
           (for-each
            (lambda (hp)
              (format #t "BEGINNING ~a END: ~a~%"


Not that you will use this method, but the following two lines ought to be


            (grob::when (ly:spanner-bound hp LEFT))
            (grob::when (ly:spanner-bound hp RIGHT))))

                (grob::when (ly:item-get-column (ly:spanner-bound hp
    LEFT)))
                (grob::when (ly:item-get-column (ly:spanner-bound hp
    RIGHT)))))
            hairpins))
          )))

DN

\version "2.19.18"

% Scheme engraver to remove duplicate hairpins (e.g. caused by the partcombiner)
% author: Urs Liska
% source: http://lists.gnu.org/archive/html/lilypond-user/2015-04/msg00276.html
%         (Stub by David Nalesnik)

% String representation of a moment
#(define (moment->string mom)
   (let*
    ((num (ly:moment-main-numerator mom))
     (den (ly:moment-main-denominator mom)))
    (string-append
     (number->string num)
     "-"
     (number->string den))))

% Symbol representation of a moment, suitable as an alist key
#(define (moment->symbol mom)
   (string->symbol (moment->string mom)))

% Symbol representation of a starting point of a hairpin
#(define (hp-start-symbol hp)
   (moment->symbol
    (grob::when (ly:spanner-bound hp LEFT))))

% Symbol representation of a hairpin end
% This is suffixed with a direction indicator
#(define (hp-end-symbol hp)
   (string->symbol
    (string-append
     (moment->string
      (grob::when (ly:spanner-bound hp RIGHT)))
     "-"
     (number->string (ly:grob-property hp 'grow-direction)))))


removeDoubleHairpinsEngraver =
#(lambda (context)
   (let ((all-hairpins '())
         (simultaneous-hairpins '()))

     (make-engraver
      (acknowledgers
       ((hairpin-interface engraver grob source-engraver)
        (set! all-hairpins (cons grob all-hairpins))))

      ((finalize trans)
       (begin

        ;; generate an alist simultaneous-hairpins containing lists
        ;; with all hairpins starting at the same moment
        ;; This discerns between equal and different hairpins
        (for-each
         (lambda (hp)
           (let*
            ;; symbols to act as keys in alists
            ((start-symbol (hp-start-symbol hp))
             (end-symbol (hp-end-symbol hp))
             ;; list of hairpins with the same starting point as the current one
             (hp-siblings (assoc-ref simultaneous-hairpins start-symbol)))
            (if (not hp-siblings)
                ;; no hairpin with the current starting moment yet
                ;; -> initialize node
                (set! simultaneous-hairpins
                      (assoc-set! simultaneous-hairpins start-symbol
                        (list
                         (list end-symbol hp))))
                ;; There is already a hairpin starting at the current moment
                ;; -> check if we have an equal hairpin or not
                (let
                 ;; Equal hairpins are hairpins that also match the end-symbol
                 ((equal-hairpins (assoc-ref hp-siblings end-symbol)))
                 (if equal-hairpins
                     (set! simultaneous-hairpins
                           (assoc-set!
                            simultaneous-hairpins
                            start-symbol
                            (list (list end-symbol (append equal-hairpins (list 
hp)))))))))))
         all-hairpins)

        ;; Walk over the equal hairpins
        (for-each
         (lambda (moment)
           (let ((equal-hairpins (cadadr moment)))
             ;; non-equal hairpins are also passed into this function,
             ;; so we have to skip it
             (if (list? equal-hairpins)
                 (begin
                  ; temporarily color the kept hairpin red
                  (ly:grob-set-property! (car equal-hairpins) 'color red)
                  ;; remove the stencil for all subsequent hairpins
                  (for-each
                   (lambda (duplicate)
                     (ly:grob-set-property! duplicate 'stencil #f))
                   (cdr equal-hairpins))))))
         simultaneous-hairpins))))))


\layout {
  \context {
    \Score
    \consists \removeDoubleHairpinsEngraver
  }
}

music = {
  \partcombineApart
  c''1~\<
  c''1\!
  c''2.\< c''4\!
  c''1~\>
  \break
  c''2~ c''\!
}

\score {
  \new Staff {
    \partcombine
    {
      \music
      c''2 \< c''2 \!
      c''1 \>
      c''1 \>
      c''1 \!
    }
    \transpose c c, {
      \music
      c''1
      c''2 \> c''2 \!
      c''1 \<
      c''1 \!
    }
  }
  \layout {}
}
_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user

Reply via email to