[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Code pointer from end-BarLine to previous NoteHead.?
From: |
Jean Abou Samra |
Subject: |
Re: Code pointer from end-BarLine to previous NoteHead.? |
Date: |
Sat, 16 Jul 2022 23:12:18 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.11.0 |
Le 16/07/2022 à 20:47, Thomas Morley a écrit :
Hi Jean,
thanks for the hint.
Alas, the code below _ensures_ the NoteHead _before_ the BarLine is
taken (if I'm wrong here, I am completely lost), and again the
override for BarLine.Y-offset fails.
Ah, yes, sigh. This is caused by prebreak substitution.
You likely know about break substitution, and even if you
didn't know that term, you definitely know about the concept.
<https://extending-lilypond.readthedocs.io/en/latest/backend.html#grob-pointers>
(What I call) "prebreak substitution" is exactly the same,
but happening right after translation, _before_ line breaking.
It's done one items only, and uses break directions as the
criterion for replacing grobs instead of systems. Concretely,
the grob pointers in each item are scanned for other items;
let's assume a pointer to J is found in I. Then J is replaced
by its broken piece having the same break direction of I.
If it doesn't exist, the value is removed if it's in a grob
array, or otherwise replaced with *unspecified*.
I've never been a fan of this, TBH. For example, it doesn't
play so well with the actual break substitution. If item I
with break direction LEFT refers to J which is on the non-musical
column at a line break, then prebreak substitution will replace
J with its LEFT broken piece, but if I ends up on the system
just after the line break where J is located, then break
substitution will again replace that pointer, this time with
the RIGHT broken piece.
End of line
|| <- NonMusicalPaperColumn
||
J <- Item J, LEFT version
-- line break
Beginning of line End of line
|| ||
|| ||
J, RIGHT version Item I, LEFT break dir, with
pointer to J
=> with prebreak substitution,
pointer replaced
with LEFT J above (same break
dir)
=> with break substitution,
replaced with
RIGHT J (same system)
Maybe this is something to raise on the bug tracker.
Meanwhile, you can work around it by using a regular
property (ly:grob-property etc) instead of a pointer
(ly:grob-object etc).
Some code comments:
tst =
#(lambda (ctx)
(let ((nhds '())
(bar #f))
(make-engraver
(acknowledgers
((bar-line-interface engraver grob source-engraver)
(set! bar grob))
((note-head-interface engraver grob source-engraver)
(set! nhds (cons (cons (ly:context-current-moment ctx) grob) nhds))))
((stop-translation-timestep engraver)
(let* ((curr (ly:context-current-moment ctx))
(nhds-to-consider
(remove
(lambda (x)
(equal? (car x) curr))
nhds))
(sorted-nhds
(reverse
(sort
nhds-to-consider
(lambda (x y)
(ly:moment<? (car x) (car y)))))))
(if (and (ly:grob? bar) (pair? nhds))
(pair? sorted-nhds) rather. Otherwise, you have a bug where
you take the car of the empty list if nhds only contains note
heads from the current moment.
(begin
(ly:grob-set-property! (cdr (car sorted-nhds)) 'color red)
(ly:grob-set-object! bar 'element (car sorted-nhds))
(set! bar #f))))))))
The last line has a bug, the (set! ...) should be outside
the (if ...), or the bar line will take note heads after it
if there are only skips before it.
Furthermore, you have quadratic behavior because you sort the
whole list of note heads at every timestep. Overall, I'd write
this engraver more simply -- and efficiently -- as this:
\version "2.23.11"
tst =
#(lambda (ctx)
(let ((nhd #f)
(previous-nhd #f)
(bar #f))
(make-engraver
(acknowledgers
((bar-line-interface engraver grob source-engraver)
(set! bar grob))
((note-head-interface engraver grob source-engraver)
(set! nhd grob)))
((stop-translation-timestep engraver)
(when (and bar previous-nhd)
;; for debugging
(ly:grob-set-property! previous-nhd 'color red)
(set! (ly:grob-property bar 'details)
(acons 'previous-note-head
previous-nhd
(ly:grob-property bar 'details))))
(when nhd
;; Move the next line out of (when ...) if you only want the
;; note head from the time step right before, and not the last
;; note head seen before the bar line.
(set! previous-nhd nhd)
(set! nhd #f))
(set! bar #f)))))
moveBarLineToPrevHead = {
\override Staff.BarLine.Y-offset =
#(lambda (grob)
(let* ((prev-head (assq-ref (ly:grob-property grob 'details)
'previous-note-head))
(staff-pos (and prev-head (ly:grob-property prev-head
'staff-position))))
(/ (or staff-pos 0) 2)))
}
\layout {
\context {
\Staff
\consists \tst
\moveBarLineToPrevHead
}
}
\new Staff { s4 s \bar "." b s c' d' e' f' g' a' b' c'' \bar "|." }
As you can see, using regular properties cures the problem.
Of course, you'll need to adapt if you want to account for chords.
Best,
Jean
- Code pointer from end-BarLine to previous NoteHead.?, Thomas Morley, 2022/07/16
- Re: Code pointer from end-BarLine to previous NoteHead.?, Jean Abou Samra, 2022/07/16
- Re: Code pointer from end-BarLine to previous NoteHead.?, Thomas Morley, 2022/07/16
- Re: Code pointer from end-BarLine to previous NoteHead.?,
Jean Abou Samra <=
- Re: Code pointer from end-BarLine to previous NoteHead.?, Thomas Morley, 2022/07/16
- Re: Code pointer from end-BarLine to previous NoteHead.?, Jean Abou Samra, 2022/07/17
- Re: Code pointer from end-BarLine to previous NoteHead.?, Thomas Morley, 2022/07/17
- Re: Code pointer from end-BarLine to previous NoteHead.?, Thomas Morley, 2022/07/17
- Re: Code pointer from end-BarLine to previous NoteHead.?, Jean Abou Samra, 2022/07/17
- Re: Code pointer from end-BarLine to previous NoteHead.?, David Kastrup, 2022/07/17
- Re: Code pointer from end-BarLine to previous NoteHead.?, Jean Abou Samra, 2022/07/17
- Re: Code pointer from end-BarLine to previous NoteHead.?, David Kastrup, 2022/07/17
- Re: Code pointer from end-BarLine to previous NoteHead.?, Jean Abou Samra, 2022/07/18
- Re: Code pointer from end-BarLine to previous NoteHead.?, David Kastrup, 2022/07/18