Re: Cross-staff stem engraver (was: New frog in an empty pond?)

2012-03-09 Thread Pavel Roskin

Quoting Carl Sorensen :


Ordinarily something like this would go in the regression tests:

input/regression/cross-staff-stem-engraver.ly

And then you would add it to your git repository, and post it on Rietveld
for a review.


OK, I'll do it.

--
Regards,
Pavel Roskin

___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel


Re: Cross-staff stem engraver (was: New frog in an empty pond?)

2012-03-08 Thread Carl Sorensen
On 3/8/12 2:44 PM, "Pavel Roskin"  wrote:

>Hello, Janek!
>
>Quoting Janek Warchoł :
>
>>> I'm attaching the Scheme code with a convoluted example (3 staves with
>>> 3 voices on each).
>>
>> I don't have the time to dive into details, but the output looks good!
>> Be sure to post it on Rietveld for a review when you come back.
>
>Thank you for your appreciation!  Sorry for delay - too little time
>and slow Internet here.  Could you please explain how I can put a
>standalone file to Rietveld?  I guess you mean that it should be added
>to Lilypond source?  You mean the ly directory or some place in the
>documentation?

Ordinarily something like this would go in the regression tests:

input/regression/cross-staff-stem-engraver.ly

And then you would add it to your git repository, and post it on Rietveld
for a review.

HTH,

Carl


___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel


Re: Cross-staff stem engraver (was: New frog in an empty pond?)

2012-03-08 Thread Pavel Roskin

Hello, Janek!

Quoting Janek Warchoł :


I'm attaching the Scheme code with a convoluted example (3 staves with
3 voices on each).


I don't have the time to dive into details, but the output looks good!
Be sure to post it on Rietveld for a review when you come back.


Thank you for your appreciation!  Sorry for delay - too little time  
and slow Internet here.  Could you please explain how I can put a  
standalone file to Rietveld?  I guess you mean that it should be added  
to Lilypond source?  You mean the ly directory or some place in the  
documentation?


--
Regards,
Pavel Roskin

___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel


Re: Cross-staff stem engraver (was: New frog in an empty pond?)

2012-03-06 Thread Janek Warchoł
On Sat, Mar 3, 2012 at 5:26 AM, Pavel Roskin  wrote:
> Hello!
>
> On Tue, 28 Feb 2012 15:14:29 -0800
> Joe Neeman  wrote:
>
>> Don't use ly:axis-group-interface::add-element, because stems don't
>> implement the axis-group-interface. (Removing this will also remove
>> the axes warning.) Instead, use ly:grob-set-parent!. You'll probably
>> want to set both the X parent and the Y parent. Then the X and Y
>> offsets of new-stem will be measured relative to stem (instead of
>> relative to the whole system, which is the default).
>
> OK, this is what I have now.  I think it's a pretty good solution.
>
> The code is capable of creating multiple cross-staff stems per moment.
> It's possible to connect more than two stems as long as they lie on the
> same line.  There is a workaround for a problem with Lilypond 2.14 that
> has a flag as part of the stem.
>
> I spent way too much time on the issue, but it helped me learn
> Scheme and Lilypond.
>
> I'll be on vacation next two weeks, so I'm not sure I'll be able to
> work on Lilypond.  So I want to post my results.
>
> I tried posting this on LSR, but it won't accept it.  I get a popup
> message saying "empty output from Lilypond" or something like that.  I
> guess it's because LSR still runs Lilypond 2.12.x.  Unfortunately, I
> have no time for backports.
>
> I'm attaching the Scheme code with a convoluted example (3 staves with
> 3 voices on each).

I don't have the time to dive into details, but the output looks good!
Be sure to post it on Rietveld for a review when you come back.

cheers,
Janek

___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel


Re: Cross-staff stem engraver (was: New frog in an empty pond?)

2012-03-03 Thread Joe Neeman
On Fri, Mar 2, 2012 at 8:26 PM, Pavel Roskin  wrote:

> Hello!
>
> On Tue, 28 Feb 2012 15:14:29 -0800
> Joe Neeman  wrote:
>
> > Don't use ly:axis-group-interface::add-element, because stems don't
> > implement the axis-group-interface. (Removing this will also remove
> > the axes warning.) Instead, use ly:grob-set-parent!. You'll probably
> > want to set both the X parent and the Y parent. Then the X and Y
> > offsets of new-stem will be measured relative to stem (instead of
> > relative to the whole system, which is the default).
>
> OK, this is what I have now.  I think it's a pretty good solution.
>

Looks good!


>
> The code is capable of creating multiple cross-staff stems per moment.
> It's possible to connect more than two stems as long as they lie on the
> same line.  There is a workaround for a problem with Lilypond 2.14 that
> has a flag as part of the stem.
>
> I spent way too much time on the issue, but it helped me learn
> Scheme and Lilypond.
>

That's ok; now that you're an expert, your next feature will be much
easier...

Cheers,
Joe
___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel


Re: Cross-staff stem engraver (was: New frog in an empty pond?)

2012-03-02 Thread Pavel Roskin
Hello!

On Tue, 28 Feb 2012 15:14:29 -0800
Joe Neeman  wrote:

> Don't use ly:axis-group-interface::add-element, because stems don't
> implement the axis-group-interface. (Removing this will also remove
> the axes warning.) Instead, use ly:grob-set-parent!. You'll probably
> want to set both the X parent and the Y parent. Then the X and Y
> offsets of new-stem will be measured relative to stem (instead of
> relative to the whole system, which is the default).

OK, this is what I have now.  I think it's a pretty good solution.

The code is capable of creating multiple cross-staff stems per moment.
It's possible to connect more than two stems as long as they lie on the
same line.  There is a workaround for a problem with Lilypond 2.14 that
has a flag as part of the stem.

I spent way too much time on the issue, but it helped me learn
Scheme and Lilypond.

I'll be on vacation next two weeks, so I'm not sure I'll be able to
work on Lilypond.  So I want to post my results.

I tried posting this on LSR, but it won't accept it.  I get a popup
message saying "empty output from Lilypond" or something like that.  I
guess it's because LSR still runs Lilypond 2.12.x.  Unfortunately, I
have no time for backports.

I'm attaching the Scheme code with a convoluted example (3 staves with
3 voices on each).

The Scheme part is already used here:
https://gitorious.org/lilypond-music/lilypond-music/blobs/master/Schubert/Die_Forelle.ly

-- 
Regards,
Pavel Roskin
\version "2.14.2"

% Values are close enough to ignore the difference
#(define (close-enough? x y)
   (< (abs (- x y)) 0.0001))

% Combine a list of extents
#(define (extent-combine extents)
   (if (pair? (cdr extents))
   (interval-union (car extents) (extent-combine (cdr extents)))
   (car extents)))

% Workaround for Lilypond 2.14 - calculate X-extent without the flag
#(define (stem-x-extent stem)
   (let* ((extent (ly:grob-extent stem stem X))
  (layout (ly:grob-layout stem))
  (thickness (ly:grob-property stem 'thickness))
  (thickness-unit (ly:output-def-lookup layout 'line-thickness)))
 (cons (car extent) (+ (car extent) (* thickness thickness-unit)

% Check if the stem is connectable to the stem span
#(define ((stem-connectable? ref anchor) stem)
   (cond
((inf? (car (ly:grob-extent stem ref X))) #f)
((not (close-enough? (car (ly:grob-extent anchor ref X))
(car (ly:grob-extent stem ref X #f)
((< 0 (* (ly:grob-property anchor 'direction)
(- (car (ly:grob-extent anchor ref Y))
  (car (ly:grob-extent stem ref Y) #f)
(else #t)))

% Connect stems if we have at least two visible stems and the anchor stem
% is one of them
#(define (stem-span-stencil span)
   (let* ((system (ly:grob-system span))
  (anchor (ly:grob-parent span X))
  (stems (filter (stem-connectable? system anchor)
 (ly:grob-object span 'stems
 (if (and (pair? stems)
  (pair? (cdr stems))
  (memq anchor stems))
 (let* ((yextents (map (lambda (st)
 (ly:grob-extent st system Y)) stems))
(yextent (extent-combine yextents))
(layout (ly:grob-layout anchor))
(blot (ly:output-def-lookup layout 'blot-diameter)))
   ; Hide spanned stems, but only if it won't hide flags
   (map (lambda (st)
  (if (close-enough? (cdr (stem-x-extent st))
(cdr (ly:grob-extent st st X)))
  (set! (ly:grob-property st 'transparent) #t)))
 stems)
   (ly:round-filled-box (stem-x-extent anchor) yextent blot))
 #f)))

% Create a stem span as a child of the cross-staff stem (the anchor)
#(define ((make-stem-span! stems trans) anchor)
   (let* ((span (ly:engraver-make-grob trans 'Stem '(
 (ly:grob-set-parent! span X anchor)
 (set! (ly:grob-object span 'stems) stems)
 (set! (ly:grob-property span 'X-offset) 0)
 (set! (ly:grob-property span 'stencil) stem-span-stencil)))

% Create stem spans for cross-staff stems
#(define (make-stem-spans! ctx stems trans)
   (if (and (pair? stems)
(pair? (cdr stems)))
   (let* ((anchors (filter (lambda (st)
 (ly:grob-property st 'cross-staff)) stems)))
 (map (make-stem-span! stems trans) anchors

% Connect cross-staff stems to the stems above in the system
#(define (Span_stem_engraver ctx)
   (let ((stems '()))
 `((acknowledgers
(stem-interface
 . ,(lambda (trans grob source)
  (set! stems (cons grob stems)
   (process-acknowledged
. ,(lambda (trans)
 (make-stem-spans! ctx stems trans)
 (set! stems '()))

\layout {
  \context {
\StaffGroup
\consists #Span_stem_engraver
  }
}

\score {
  \new StaffGroup <<
\new Staff = "staffone" <<
  \new Voice {
\voiceOne c''4
  }
  

Re: Cross-staff stem engraver (was: New frog in an empty pond?)

2012-02-28 Thread Pavel Roskin

Quoting Joe Neeman :


I'm getting a message "Weird stem", and I don't see how to avoid it.
Perhaps I should create a totally new grob with a unique name, such as
StemSpan.  Is that possible?  What would be needed?



It would be nice to do this eventually, because having a different grob
name would make it easier for the users to tweak it. I think it would
involve editing scm/define-grobs.scm, but there may be a way to do it from
an .ly file also


It turn out the message comes from ly:stem::offset-callback and can be  
suppressed by redefining X-offset.



Don't use ly:axis-group-interface::add-element, because stems don't
implement the axis-group-interface. (Removing this will also remove the
axes warning.) Instead, use ly:grob-set-parent!. You'll probably want to
set both the X parent and the Y parent. Then the X and Y offsets of
new-stem will be measured relative to stem (instead of relative to the
whole system, which is the default).


That was it!  I have a working solution now!  It will need to be  
improved to ignore rests and other invisible stems, check the  
cross-staff property, avoid connecting incompatible stems and so on.   
The old stems should be made transparent.  But all that should be  
simple.  Once I have something easy to use, I plan to submit it to the  
LSR.


Actually, it looks like System is a better Y-parent for the new stem.   
Perhaps I'll try to use the common reference of the stems to be  
connected.


Here's what I have now (attached).

Thank you for your help!

--
Regards,
Pavel Roskin

\version "2.14.2"

#(define (extent-combine extents)
   (if (pair? (cdr extents))
   (interval-union (car extents) (extent-combine (cdr extents)))
   (car extents)))

#(define (stemSpanExtent grob)
   (let* ((yref (ly:grob-parent grob Y))
  (stems (ly:grob-object grob 'spanned-stems))
  (extents (map (lambda (x) (ly:grob-extent x yref Y)) stems))
  (maxextent (extent-combine extents)))
 maxextent))

#(define (stemSpanStencil grob)
   (let* ((stem (car (ly:grob-object grob 'spanned-stems)))
  (xextent (ly:grob-extent stem stem X))
  (yextent (stemSpanExtent grob)))
 (make-filled-box-stencil xextent yextent)))

#(define (reparentStems ctx stems trans)
   (if (and (pair? stems)
(pair? (cdr stems)))
   (let* ((stem (car stems))
  (new-stem (ly:engraver-make-grob trans 'Stem '(
 (ly:grob-set-parent! new-stem X stem)
 (set! (ly:grob-object new-stem 'spanned-stems) stems)
 (set! (ly:grob-property new-stem 'X-offset) 0)
 (set! (ly:grob-property new-stem 'stencil) stemSpanStencil

#(define (Cross_staff_stem_engraver ctx)
  (let ((stems '()))

`((acknowledgers
   (stem-interface
. ,(lambda (trans grob source)
 (set! stems (cons grob stems)

  (process-acknowledged
   . ,(lambda (trans)
 (reparentStems ctx stems trans) (set! stems '()))

\layout {
  \context {
\PianoStaff
\consists #Cross_staff_stem_engraver
  }
}

\new PianoStaff <<
  \new Staff { \stemUp g'4 a'  \stemDown c' }
  \new Staff { \stemUp f'4 e'  \stemDown c''' }
>>
___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel


Re: Cross-staff stem engraver (was: New frog in an empty pond?)

2012-02-28 Thread Joe Neeman
On Tue, Feb 28, 2012 at 2:56 PM, Pavel Roskin  wrote:

> Hello, Joe!
>
> > In case it wasn't clear from what I said before, engravers in lilypond
> > don't do the actual layout. Instead, they build the grobs and set up
> > the connections between them. Most of the layout is done in callback
> > functions.
>
> Yes, I realize it now.  Your suggestion to create a new stem worked
> fine.  I can get the relative coordinates of themes on different staves.
>
> The attached file shows where I am now.  There are many minor issues,
> and I hope I can solve most of them, but I'll certainly appreciate help.
>
> I'm getting a message "Weird stem", and I don't see how to avoid it.
> Perhaps I should create a totally new grob with a unique name, such as
> StemSpan.  Is that possible?  What would be needed?
>

It would be nice to do this eventually, because having a different grob
name would make it easier for the users to tweak it. I think it would
involve editing scm/define-grobs.scm, but there may be a way to do it from
an .ly file also


> How do I make the new stem start at the same point as the original
> one.  I tried this:
>
> (set! (ly:grob-property stem 'axes) (list X))
>
> I don't understand how it works.  Not setting axes leads to:
>
> programming error: axes should be nonempty
>

Don't use ly:axis-group-interface::add-element, because stems don't
implement the axis-group-interface. (Removing this will also remove the
axes warning.) Instead, use ly:grob-set-parent!. You'll probably want to
set both the X parent and the Y parent. Then the X and Y offsets of
new-stem will be measured relative to stem (instead of relative to the
whole system, which is the default).

Cheers,
Joe
___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel


Re: Cross-staff stem engraver (was: New frog in an empty pond?)

2012-02-28 Thread Pavel Roskin
Hello, Joe!

> In case it wasn't clear from what I said before, engravers in lilypond
> don't do the actual layout. Instead, they build the grobs and set up
> the connections between them. Most of the layout is done in callback
> functions.

Yes, I realize it now.  Your suggestion to create a new stem worked
fine.  I can get the relative coordinates of themes on different staves.

The attached file shows where I am now.  There are many minor issues,
and I hope I can solve most of them, but I'll certainly appreciate help.

I'm getting a message "Weird stem", and I don't see how to avoid it.
Perhaps I should create a totally new grob with a unique name, such as
StemSpan.  Is that possible?  What would be needed?

How do I make the new stem start at the same point as the original
one.  I tried this:

(set! (ly:grob-property stem 'axes) (list X))

I don't understand how it works.  Not setting axes leads to:

programming error: axes should be nonempty

Maybe I should use some other parent for the new stem?

The new stems are offset horizontally on purpose to see where they
are.  But the vertical position is wrong and I don't see how to fix it.

I'll appreciate if you have a look at the code.

-- 
Regards,
Pavel Roskin
\version "2.14.2"

#(define (grobParentByInterface grob intf axis)
   (if (memq intf (ly:grob-interfaces grob))
   grob
   (grobParentByInterface (ly:grob-parent grob axis) intf axis)))

#(define (extent-combine extents)
   (if (pair? (cdr extents))
   (interval-union (car extents) (extent-combine (cdr extents)))
   (car extents)))

#(define (crossStaffLength grob)
   (let* ((papercolumn (grobParentByInterface grob 'paper-column-interface X))
  (elementarray (ly:grob-object papercolumn 'elements))
  (yref (ly:grob-common-refpoint-of-array grob elementarray Y))
  (elements (ly:grob-object grob 'spanned-stems))
  (extents (map (lambda (x) (ly:grob-extent x yref Y)) elements))
  (foo (ly:message "extents: ~a" extents))
  (maxextent (extent-combine extents))
  (foo (ly:message "maxextent: ~a" maxextent))
  (length (- (car maxextent) (cdr maxextent
 length))

#(define (stemSpanStencil grob)
   (let* ((length (crossStaffLength grob)))
 (make-filled-box-stencil '(0.2 . 0.4) (cons 0 length

#(define (reparentStems ctx stems trans)
   (if (and (pair? stems) (pair? (cdr stems)))
   (let* ((stem (car stems))
  (parent (ly:grob-parent stem Y))
  (new-stem (ly:engraver-make-grob trans 'Stem '(
 (ly:message "stems: ~a" stems)
 (ly:message "new-stem: ~a" new-stem)
 (set! (ly:grob-property stem 'axes) (list X))
 (ly:axis-group-interface::add-element stem new-stem)
 (set! (ly:grob-object new-stem 'spanned-stems) stems)
 (set! (ly:grob-object new-stem 'Y-offset) 5)
 (set! (ly:grob-property new-stem 'stencil) stemSpanStencil)
 (set! (ly:grob-property new-stem 'length) crossStaffLength

#(define (Cross_staff_stem_engraver ctx)
  (let ((stems '()))

`((acknowledgers
   (stem-interface
. ,(lambda (trans grob source)
 (set! stems (cons grob stems)

  (process-acknowledged
   . ,(lambda (trans)
 (reparentStems ctx stems trans) (set! stems '()))

\layout {
  \context {
\PianoStaff
\consists #Cross_staff_stem_engraver
  }
}

\new PianoStaff <<
  \new Staff { \stemUp g' a' b' c'' }
  \new Staff { \stemUp f' e'  r }
>>
___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel


Re: Cross-staff stem engraver (was: New frog in an empty pond?)

2012-02-26 Thread Joe Neeman
On Sat, Feb 25, 2012 at 9:14 PM, Pavel Roskin  wrote:
>
>
> Using an engraver to catch the stems sounds like a good approach.  I could
> even do some filtering in the engraver.  And it should be possible to
> replace stems with one rather than connect them together.  It would
> simplify SVG output, and I suspect the connect point could be seen in some
> renderings of the postscript output.
>
> Thank you for your help!  I'm getting really close!


Glad to hear it :)

In case it wasn't clear from what I said before, engravers in lilypond
don't do the actual layout. Instead, they build the grobs and set up the
connections between them. Most of the layout is done in callback functions.

Cheers,
Joe
___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel


Re: Cross-staff stem engraver (was: New frog in an empty pond?)

2012-02-25 Thread Pavel Roskin

Quoting Joe Neeman :


The problem is where you ask for the stem Y-extent relative to yref (the
VerticalAlignment): in order to calculate the vertical distance between the
various staves and the VerticalAlignment, line breaking needs to be done
first. (And line breaking doesn't happen until after all the engravers are
done.)


I see.  It means that using an engraver it not a solution per se.   
Good to know.



I guess I'll need to redefine the stencil for stems.  Or maybe you mean
some other callback?



You could redefine stencil, but I think redefining length would be easier.


Of course, that's why I tried it first :)


Can you be more specific about the Y-extent not being calculated yet? When
you ask for the Y-extent, the calculation should be triggered if it hasn't
already happened.


Now I understand what's going on!  Apparently this triggering is not  
transitive (which is reasonable).  I'm attaching the minimal example  
when I get


grob Y-extent: (+inf.0 . -inf.0)

I think it should be possible to work around.  I'll be perfectly fine  
if my code doesn't work with chords spanning three and more staves if  
that limitation needs to exist.



As a general approach, setting length sounds like a reasonable way forward.
In addition, I'd suggest creating a new stem in process-acknowledged, then
doing

(set! (ly:grob-object new-stem 'spanned-stems) old-stems)
(set! (ly:grob-property new-stem 'length) your-length-callback)

In your length callback, you read back the spanned-stems object and do your
calculations. Is this similar to what you tried?


I never used an engraver and the length override at the save time.   
When doing the length override, I tried this approach:


- find PaperColumn among the grob parents
- scan its elements for stems
- use stems extents to find stems connectable to the given stem
- find the closest stem
- use the length that would extend the given stem to the closest stem

It actually worked, except some corner cases.  Now I understand why.

Using an engraver to catch the stems sounds like a good approach.  I  
could even do some filtering in the engraver.  And it should be  
possible to replace stems with one rather than connect them together.   
It would simplify SVG output, and I suspect the connect point could be  
seen in some renderings of the postscript output.


Thank you for your help!  I'm getting really close!

--
Regards,
Pavel Roskin

\version "2.14.2"

#(define (grobParentByInterface grob intf axis)
   (if (memq intf (ly:grob-interfaces grob))
   grob
   (grobParentByInterface (ly:grob-parent grob axis) intf axis)))

#(define (crossStaffLength grob)
   (let* ((papercolumn (grobParentByInterface grob 'paper-column-interface X))
  (elementarray (ly:grob-object papercolumn 'elements))
  (elements (ly:grob-array->list elementarray)))
 (map (lambda (x)
(ly:grob-extent x x Y)) elements)
 (ly:message "grob Y-extent: ~a" (ly:grob-extent grob grob Y))
 3))

\score {
  \new StaffGroup <<
\new Staff = "staffone" <<
  \new Voice {
c'
  }
>>
\new Staff = "stafftwo" <<
  \new Voice {
\clef bass
\override Stem #'cross-staff = ##t
\override Stem #'length = #crossStaffLength
c
  }
>>
\new Staff = "staffthree" <<
  \new Voice {
\override Stem #'cross-staff = ##t
\override Stem #'length = #crossStaffLength
\clef bass
g,
  }
>>
  >>
  \layout { }
}
___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel


Re: Cross-staff stem engraver (was: New frog in an empty pond?)

2012-02-25 Thread Joe Neeman
On Sat, Feb 25, 2012 at 5:49 AM, Pavel Roskin  wrote:

> Quoting Joe Neeman :
>
>  On Fri, Feb 24, 2012 at 3:04 PM, Pavel Roskin  wrote:
>>
>>> I tried writing an engraver that could be added to the StaffGroup
>>> context.  Collecting stems is not a problem.  The problem is that even
>>> the finalize handler is called to early.  I'm getting a warning:
>>>
>>> programming error: vertical alignment called before line breaking
>>> continuing, cross fingers
>>>
>>>
>> It's a little hard to guess what's going wrong without knowing exactly
>> what
>> you've tried. Are you trying to do layout logic in the engraver (ie. by
>> collecting stems, reading their properties, doing calculations and then
>> setting more properties)?
>>
>
> Yes, except that I'm not setting anything yet.  The current file is
> attached.


The problem is where you ask for the stem Y-extent relative to yref (the
VerticalAlignment): in order to calculate the vertical distance between the
various staves and the VerticalAlignment, line breaking needs to be done
first. (And line breaking doesn't happen until after all the engravers are
done.)



>  If you are, the first step is to move the layout
>> logic into grob callbacks.
>>
>
> I guess I'll need to redefine the stencil for stems.  Or maybe you mean
> some other callback?
>

You could redefine stencil, but I think redefining length would be easier.

I did a similar thing before.  I put all the logic into a function that was
> used to redefine the length property of the stem.  It worked for a simple
> case of two stems, but failed when three stems needed to be connected.  The
> Y-extent for at least one of the stems wasn't calculated yet.
>

Can you be more specific about the Y-extent not being calculated yet? When
you ask for the Y-extent, the calculation should be triggered if it hasn't
already happened.

As a general approach, setting length sounds like a reasonable way forward.
In addition, I'd suggest creating a new stem in process-acknowledged, then
doing

(set! (ly:grob-object new-stem 'spanned-stems) old-stems)
(set! (ly:grob-property new-stem 'length) your-length-callback)

In your length callback, you read back the spanned-stems object and do your
calculations. Is this similar to what you tried?

Cheers,
Joe
___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel


Re: Cross-staff stem engraver (was: New frog in an empty pond?)

2012-02-25 Thread Pavel Roskin

Quoting Joe Neeman :


On Fri, Feb 24, 2012 at 3:04 PM, Pavel Roskin  wrote:

I tried writing an engraver that could be added to the StaffGroup
context.  Collecting stems is not a problem.  The problem is that even
the finalize handler is called to early.  I'm getting a warning:

programming error: vertical alignment called before line breaking
continuing, cross fingers



It's a little hard to guess what's going wrong without knowing exactly what
you've tried. Are you trying to do layout logic in the engraver (ie. by
collecting stems, reading their properties, doing calculations and then
setting more properties)?


Yes, except that I'm not setting anything yet.  The current file is attached.


If you are, the first step is to move the layout
logic into grob callbacks.


I guess I'll need to redefine the stencil for stems.  Or maybe you  
mean some other callback?


I did a similar thing before.  I put all the logic into a function  
that was used to redefine the length property of the stem.  It worked  
for a simple case of two stems, but failed when three stems needed to  
be connected.  The Y-extent for at least one of the stems wasn't  
calculated yet.


I also tried setting Y-extent, but it's read-only.

--
Regards,
Pavel Roskin

\version "2.14.0"

#(define ((connectableStem? xref yref stemone dir below?) stemtwo)
   (cond
((not (memq 'stem-interface (ly:grob-interfaces stemtwo))) #f)
((equal? stemone stemtwo) #f)
((inf? (car (ly:grob-extent stemtwo xref X))) #f)
((not (equal? (ly:grob-extent stemone xref X) (ly:grob-extent stemtwo xref X))) #f)
((not (equal? dir (ly:grob-property stemtwo 'direction))) #f)
((below? (car (ly:grob-extent stemtwo yref Y)) (car (ly:grob-extent stemone yref Y))) #f)
(else #t)))

#(define ((lowerStem? ref below?) lower upper)
   (below? (car (ly:grob-extent lower ref Y)) (car (ly:grob-extent upper ref Y

#(define (crossStaffLength grob ctx stems)
   (let* ((papercolumn (ly:context-property ctx 'currentMusicalColumn))
  (foo (ly:message "papercolumn: ~a" papercolumn))
  (xref (ly:grob-common-refpoint grob (car stems) X))
  (foo (ly:message "xref: ~a" xref))
  (yref (ly:grob-common-refpoint grob (car stems) Y))
  (foo (ly:message "yref: ~a" yref))
  (dir (ly:grob-property grob 'direction))
  (below? (if (= dir UP) < >))
  (foo (ly:message "stems: ~a" stems))
  (goodstems (filter (connectableStem? xref yref grob dir below?) stems))
  (foo (ly:message "stems1: ~a" stems))
  (beststems (sort goodstems (lowerStem? yref below?)))
  (foo (ly:message "stems2: ~a" stems))
  (peer (car (append beststems (list grob
  (foo (ly:message "peer: ~a" peer)))
 (ly:message "grob: ~a" (ly:grob-extent grob yref Y))
 (ly:message "peer: ~a" (ly:grob-extent peer yref Y))
 (if (equal? grob peer)
 (begin (ly:programming-error "No suitable stem to connect to") 4)
 (if (> dir 0)
 (* 2 (- (car (ly:grob-extent peer yref Y))
 (car (ly:grob-extent grob yref Y
 (* 2 (- (cdr (ly:grob-extent grob yref Y))
 (cdr (ly:grob-extent peer yref Y

#(define (connectStems ctx stems)
   (ly:message "stems: ~a" stems)
   (if (and (pair? stems) (pair? (cdr stems)))
   (let ((stem (car stems))
 (otherstems (cdr stems)))
 (ly:message "otherstems: ~a" otherstems)
 (ly:message "length: ~a"
   (crossStaffLength stem ctx otherstems)

#(define (Cross_staff_stem_engraver ctx)
  (let ((stems '()))

`((acknowledgers
   (stem-interface
. ,(lambda (trans grob source)
 (ly:message "acknowledger: ~a" grob)
 (set! stems (cons grob stems

   (note-column-interface
. ,(lambda (trans grob source)
 (ly:message "acknowledger: ~a" grob

  (process-music
   . ,(lambda (trans) (ly:message "process-music") (connectStems ctx stems)))

  (process-acknowledged
   . ,(lambda (trans) (ly:message "process-acknowledged")))

  (stop-translation-timestep
   . ,(lambda (trans) (ly:message "stop-translation-timestep") (connectStems ctx stems)))

  (finalize
   . ,(lambda (trans) (ly:message "finalize") (connectStems ctx stems))

\layout {
  \context {
\StaffGroup
\consists #Cross_staff_stem_engraver
  }
}

\new StaffGroup <<
  \new Staff { g' }
  \new Staff { c' }
>>
___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel


Re: Cross-staff stem engraver (was: New frog in an empty pond?)

2012-02-25 Thread Joe Neeman
On Fri, Feb 24, 2012 at 3:04 PM, Pavel Roskin  wrote:

> Hello!
>
> I'm moving the thread to lilypond-devel and changing the subject.  I
> hope it's OK.
>
> On Thu, 23 Feb 2012 15:37:02 +
> Neil Puttock  wrote:
>
> > On 23 February 2012 15:18, Pavel Roskin  wrote:
> >
> > > I actually wanted to make a stopgap solution in Scheme.  I wrote
> > > some code that looks for other stems and sets the stem length so it
> > > would touch the stem above (attached).  But the code is unreliable.
> > >  Some stems are not calculated yet.
> >
> > I'd love to be proven wrong, but I don't think you'll have much
> > success with this approach.  At the very least, you'll need a Scheme
> > engraver at the correct context level to collect the stems at the
> > right time.  If a simple length override were possible with the
> > current infrastructure, we wouldn't need a Span_arpeggio_engraver to
> > typeset cross-staff arpeggios.
>
> I tried writing an engraver that could be added to the StaffGroup
> context.  Collecting stems is not a problem.  The problem is that even
> the finalize handler is called to early.  I'm getting a warning:
>
> programming error: vertical alignment called before line breaking
> continuing, cross fingers
>

It's a little hard to guess what's going wrong without knowing exactly what
you've tried. Are you trying to do layout logic in the engraver (ie. by
collecting stems, reading their properties, doing calculations and then
setting more properties)? If you are, the first step is to move the layout
logic into grob callbacks.

Cheers,
Joe
___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel


Cross-staff stem engraver (was: New frog in an empty pond?)

2012-02-24 Thread Pavel Roskin
Hello!

I'm moving the thread to lilypond-devel and changing the subject.  I
hope it's OK.

On Thu, 23 Feb 2012 15:37:02 +
Neil Puttock  wrote:

> On 23 February 2012 15:18, Pavel Roskin  wrote:
> 
> > I actually wanted to make a stopgap solution in Scheme.  I wrote
> > some code that looks for other stems and sets the stem length so it
> > would touch the stem above (attached).  But the code is unreliable.
> >  Some stems are not calculated yet.
> 
> I'd love to be proven wrong, but I don't think you'll have much
> success with this approach.  At the very least, you'll need a Scheme
> engraver at the correct context level to collect the stems at the
> right time.  If a simple length override were possible with the
> current infrastructure, we wouldn't need a Span_arpeggio_engraver to
> typeset cross-staff arpeggios.

I tried writing an engraver that could be added to the StaffGroup
context.  Collecting stems is not a problem.  The problem is that even
the finalize handler is called to early.  I'm getting a warning:

programming error: vertical alignment called before line breaking
continuing, cross fingers

Even though the common reference for the Y axis for the stems is a
valid grob of type VerticalAlignment, the Y-extents don't reflect the
distance between staves.

The code for cross-staff arpeggios (span-arpeggio-engraver.cc) only
collects data about stems and lets the standard arpeggio code
(arpeggio.cc) draw the cross-staff arpeggio.

If I understand correctly, an equivalent of that for stems would
require modification to the stem engraver so that it would draw
cross-staff stems.

As for the grid lines, there are actually two engravers.  One makes the
points (GridPoint) and the other connects them (GridLine).  GridPoint
should be hopefully irrelevant, as we have stems for that.  Printing
grid lines is implemented in grid-line-interface.cc.  As I understand,
it's not an engraver (that would be grid-line-span-engraver.cc), it's
an interface.

I checked the Scheme implementation of ambitus engraver.  It relies on
existing implementations of AmbitusLine and other grobs.  The placement
is done in finalize, but ambitus is not cross-staff, so there is no
issue with undefined staff-staff spacing.

I guess I need to rely on an existing grob that supports cross-staff
placement to draw the stem if I want to keep my modification in Scheme.

Perhaps I'll try GridLine, as Arpeggio would need bogus stems and bogus
noteheads to appear where I want it to be.  BarLine also seems to be
too sophisticated for the job.  Maybe there is an example of grob
definition in Scheme?

I'll appreciate comments that would steer me away from dead ends.

-- 
Regards,
Pavel Roskin

___
lilypond-devel mailing list
lilypond-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-devel