[prev in list] [next in list] [prev in thread] [next in thread] 

List:       lilypond-user
Subject:    Issue with make-dead-when (divisi, hara_kiri)
From:       Saul Tobin <saul.james.tobin () gmail ! com>
Date:       2018-10-28 21:22:22
Message-ID: CAPF+3FF=i58C16Px2igbQB6P4jw9R1MRNnDg_1tRS8uTaUx_=Q () mail ! gmail ! com
[Download RAW message or body]

[Attachment #2 (multipart/alternative)]


Hi all,

Not sure if this should be on the User mailing list or one of the others.

The attached code replicates a strange behavior I have encountered several
different times, where seemingly random and irrelevant musical details
cause staves to incorrectly disappear when using the divisi snippet I
posted a few months ago. I also tested this with variants of Thomas
Morley's version of the snippet, so I'm convinced it's not anything to do
with the snippet itself.

In my attached example, notice that the Oboe 2 staff disappears when it
shouldn't, but if you remove the hairpin from the flute part, the Oboe 2
staff reappears. I believe that this is caused by the Oboe 2 staff having
'make-dead-when set to the combined staff, which itself has 'make-dead-when
set to Oboe 1. Hara_kiri_group_spanner::request_suicide checks each foe
staff for is_live and request_suicide_alone, but not request_suicide (to
avoid infinite loops, I guess). So if Oboe1+2 becomes dead due to
'make-dead-when, when on its own it would have stayed alive, it may either
appear alive or dead to Oboe 2, depending on which staff happens to be
evaluated first.

To avoid this race condition, one has to avoid setting 'keep-dead-when to
point to other staves that themselves have 'keep-dead-when set. In other
words, for some staves to be masters, others to be slaves. Which is
probably a good idea anyway, but it leaves a gap in functionality when it
comes to 3+ stave divisi. For 3 staves, you have:

1+2+3:  Alive if BOTH 1 and 3 are dead
1+2: Alive if 1 is dead AND 3 is alive
2+3: Alive if 1 is alive AND 3 is dead
1: Master staff
2: Alive if BOTH 1 and 3 are alive
3: Master staff

With the semantics of the existing 'make-dead-when interface, this is
doable by making, for instance, 1+2 and 2+3 dead whenever 1+2+3 is alive,
but as I noticed, this type of inter-dependency leads to unpredictable
behavior. A better way forward would be to expand the 'make-dead-when
mechanism to support a complete variety of logical conditions, such as ALL
vs. ANY and combinations of alive and dead conditions.

Saul

[Attachment #5 (text/html)]

<div dir="ltr"><div dir="ltr">Hi all,</div><div dir="ltr"><br></div><div \
dir="ltr">Not sure if this should be on the User mailing list or one of the \
others.<br><div><br></div><div>The attached code replicates a strange behavior I have \
encountered several different times, where seemingly random and irrelevant musical \
details cause staves to incorrectly disappear when using the divisi snippet I posted \
a few months ago. I also tested this with variants of Thomas Morley&#39;s version of \
the snippet, so I&#39;m convinced it&#39;s not anything to do with the snippet \
itself.</div><div><br></div><div>In my attached example, notice that the Oboe 2 staff \
disappears when it shouldn&#39;t, but if you remove the hairpin from the flute part, \
the Oboe 2 staff reappears. I believe that this is caused by the Oboe 2 staff having \
&#39;make-dead-when set to the combined staff, which itself has &#39;make-dead-when \
set to Oboe 1. Hara_kiri_group_spanner::request_suicide checks each foe staff for \
is_live and request_suicide_alone, but not request_suicide (to avoid infinite loops, \
I guess). So if Oboe1+2 becomes dead due to &#39;make-dead-when, when on its own it \
would have stayed alive, it may either appear alive or dead to Oboe 2, depending on \
which staff happens to be evaluated first.</div><div><br></div><div>To avoid this \
race condition, one has to avoid setting &#39;keep-dead-when to point to other staves \
that themselves have &#39;keep-dead-when set. In other words, for some staves to be \
masters, others to be slaves. Which is probably a good idea anyway, but it leaves a \
gap in functionality when it comes to 3+ stave divisi. For 3 staves, you \
have:</div><div><br></div><div>1+2+3:   Alive if BOTH 1 and 3 are dead</div><div>1+2: \
Alive if 1 is dead AND 3 is alive</div><div>2+3: Alive if 1 is alive AND 3 is \
dead</div><div>1: Master staff</div><div>2: Alive if BOTH 1 and 3 are \
alive</div><div>3: Master staff</div><div><br></div><div>With the semantics of the \
existing &#39;make-dead-when interface, this is doable by making, for instance, 1+2 \
and 2+3 dead whenever 1+2+3 is alive, but as I noticed, this type of inter-dependency \
leads to unpredictable behavior. A better way forward would be to expand the \
&#39;make-dead-when mechanism to support a complete variety of logical conditions, \
such as ALL vs. ANY and combinations of alive and dead \
conditions.</div><div><br></div><div>Saul</div></div></div>

--000000000000f79d880579508c8b--


["bugtest.ly" (text/lilypond-source)]

\version "2.19.82"
\language "english"

remove-if-sibling = #(define-scheme-function (offsets) (list?)
           (lambda (grob)
             (let* (
                     ;; The parent of a VerticalAxisGroup is a VerticalAlignment
                     (parent (ly:grob-parent grob 1))
                     ;; Get the children VerticalAxisGroups of the parent
                     (siblings (ly:grob-object parent 'elements))
                     (siblings-list
                      (if (ly:grob-array? siblings)
                          (ly:grob-array->list siblings)
                          '()))
                     ;; Find the siblings above or below me by offsets
                     (my-vindex (ly:grob-get-vertical-axis-group-index grob))
                     (enemy-indices (map (lambda (offset) (+ offset my-vindex)) offsets))
                     (enemy-vaxis? (lambda (v) (member (ly:grob-get-vertical-axis-group-index v)
                                                 enemy-indices)))
                     (enemy-vaxes
                      (filter enemy-vaxis? siblings-list))
                     )
               ;; Suicide if an enemy sibling is alive
               (map
                (lambda (enemy-vaxis)
                  (ly:pointer-group-interface::add-grob grob 'make-dead-when enemy-vaxis))
                enemy-vaxes)
               )
             )
           )

global = {
  s1
  \break
  s1*3
  \break
  s1
  \bar "||"
}

flute = {
  \clef treble
  \set Voice.midiInstrument = "flute"
  R1*3 |
  % Notice that without the hairpin, the Ob. 2 staff doesn't disappear
  c''1\< |
  c''1 <>\! |
}

oboeI = {
  \clef treble
  \set Voice.midiInstrument = "oboe"
  \context Staff = "Ob1" { \unset Staff.keepAliveInterfaces }
  R1 |
  c''1 |
  R1 |
  \context Staff = "Ob1" { \set Staff.keepAliveInterfaces = #'() }
  R1*2 |
}

oboeII = {
  \clef treble
  \set Voice.midiInstrument = "oboe"
  R1*2 |
  c'1 |
  R1*2 |
}

\score {
  <<
    \new Staff = "Fl1" \with {
      instrumentName = "Flute"
      shortInstrumentName = "Fl."
    } << \global \flute >>
    \new StaffGroup \with {
      instrumentName = "Oboe"
      shortInstrumentName = "Ob."
      systemStartDelimiter = #'SystemStartSquare
      \override SystemStartSquare.collapse-height = #5
    } <<
      \new Staff = "Ob1+2" \with {
        instrumentName = \markup\right-column {"1" "2"}
        shortInstrumentName = \markup\right-column {"1" "2"}
        \override VerticalAxisGroup.before-line-breaking = \remove-if-sibling #'(1)
      } { <> << \global \partcombine \oboeI \oboeII >> }
      \new Staff = "Ob1" \with {
        instrumentName = "1"
        shortInstrumentName = "1"
        \override VerticalAxisGroup.remove-empty = ##t
        \override VerticalAxisGroup.remove-first = ##t
      } << \global \oboeI >>
      \new Staff = "Ob2" \with {
        instrumentName = "2"
        shortInstrumentName = "2"
        \override VerticalAxisGroup.before-line-breaking = \remove-if-sibling #'(-2)
      } << \global \oboeII >>
    >>
  >>
  \layout {
    \context {
      \Score
      \override InstrumentName.self-alignment-X = #1
      \override InstrumentName.padding = #3
    }
    \context {
      \Staff
      \override InstrumentName.padding = 0.3
    }
  }
}


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


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic