[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Code pointer from end-BarLine to previous NoteHead.?
From: |
Thomas Morley |
Subject: |
Re: Code pointer from end-BarLine to previous NoteHead.? |
Date: |
Sun, 17 Jul 2022 01:25:57 +0200 |
Am Sa., 16. Juli 2022 um 23:12 Uhr schrieb Jean Abou Samra <jean@abou-samra.fr>:
>
> 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)
>
Thanks for your explanations, right now I had only a quick glance over them.
I'll hopefully have some time soon to dive into it...
Nevertheless, before I posted the problem I searched for an
'original'-BarLine-grob, as we have for broken spanners.
For (maybe broken) spanners I sometimes switch to that
'original'-grob, would it improve the situation if we had some
'original' for items as well?
>
>
> 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:
Thanks for them!
Though, the posted engraver was heavily simplied, I didn't care about
foreseeable bugs or efficiency, it should demonstrate the probelm
nothing else :)
>
> > 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)
Below is the most interesting part.
I never thought about putting a selected grob into a grob-property of
a different one.
I'm aware we do so with context-properties...
> (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.
Actually I need the behaviour above for end repeat bars.
The position of an starting repeat bar will rely on the staff-position
of the following rhythmic event.
And yes, I need it for single notes, event-chords and rests.
And ofcourse I need to decide what to do for multiple voices in same Staff.
Many thanks!!
Best,
Harm
- 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, 2022/07/16
- Re: Code pointer from end-BarLine to previous NoteHead.?,
Thomas Morley <=
- 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
- Re: Code pointer from end-BarLine to previous NoteHead.?, Lukas-Fabian Moser, 2022/07/18