gnu-music-discuss
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Bars


From: Juergen Reuter
Subject: Re: Bars
Date: Mon, 30 Apr 2001 01:30:30 +0200

Han-Wen writes:
> address@hidden writes:
> > The idea is to put bar lines only between the staffs, regardless of
> > where lyrics or whatever additional context else appear.  Hence,
>
> To get this right, you would have to code some C++: you'd have to
> rewrite parts of lily/span-bar.cc. Specifically, you have to write a
> new brew_molecule function, one that draws lines between the contents
> of the "elements" grob property.
>
> Good luck.

Well, to be honest, I am not very lucky yet...

Following your suggestion, I tried to rewrite (or, actually, to add) a
Span_bar::brew_molecule method, as you suggested.  Basically, it works
(with limitations, see below), but it still does not help me at all
due to other problems.

Though I did not investigate it in that detail, it seems the main
problem is that the existing code in span_bar.cc depends on the
existence of a bar_engraver in the staff context.

More specific, as of 1.3.149,
Axis_group_interface::group_extent_callback calls
Axis_group_interface::relative_group_extent, which itself relies on
elts, which is me->get_grob_property ("elements"), where me is a
span_bar grob.  In other words,
Axis_group_interface::relative_group_extent evaluates the sum of the
bar sizes that have been collected in span_bar.

However, if there is no bar_engraver in the staff context,
Axis_group_interface::relative_group_extent returns 0, since the sizes
of bars fail to be evaluated (during compilation, lily emits many
"warning: Can't find property type-check for `bar-size-procedure'.
Perhaps you made a typing error?").

This affects Span_bar::get_spanned_interval which is used by
Span_bar::center_on_spanned_callback and Span_bar::get_bar_size, and
(just looking at the code) it may also affect
Span_bar::evaluate_glyph.

The result is that, if you remove bar_engraver from staff context,
span_bar does not work properly any more.  It would be nice if this
bug could be resolved.

Back to my implementation: it basically suffers from the same problems
as Span_bar::get_spanned_interval, since it also relies on the bars in
me->get_grob_property ("elements").  A solution might be to replace
property "elements" by a new property "staff_symbols" that contains
staff_symbols rather than bars, and then evaluate
"Staff_symbol::line_count (staff_symbol) * Staff_symbol::staff_space
(staff_symbol)".  I think that is what you are actually interested in
when creating a span_bar.  Another solution would be, as I already
proposed, to introduce a visibility property for the bar engraver.
Then, one would set the visibility rather than removing or adding a
bar_engraver to whatever context.

Below is my implementation of the Span_bar::brew_molecule method.
It's against 1.3.149 -- I hope that is not a problem.  It is limited
in the same sense as the current span_bar implementation: it only
works if bar_engraver is not removed from the staff context.  Hence,
it does not solve my original problem, but it is a step into the right
direction.  If you think, my patch is too obscure, you may still
include it, if you like, but leave grob-description.scm untouched, so
that, by default, my patch is not activated.

The statement

    interstaff_bar_molecule[staff_bar_count].//DEBUG
      translate_axis (-1.0 PT, X_AXIS);//DEBUG

is for debugging purposes only: it slightly shifts the span_bar lines
to the left, so that you really can see what results from
bar_engraver, and what from span_bar_engraver.  You probably want to
finally remove these two lines.

By the way, I would like to propose renaming bar* and span_bar* into
staff_bar* and interstaff_bar*.

At the bottom of this message, there is a small test ly file.  It
shows a span_bar for a score with four staves.  N.B., there seems to
be a very obscure bug in lily: if you remove the \translator block or
the whole \paper block, the first span_bar is aligned too high,
although I would expect the paper block of this test file not to have
any effect.  Interestingly, if you also remove one the of "{ foo bar
foo }" of the LD \lyrics block, it works again.  Very strange...
Since only the first span_bar is affected, I guess it may be an
initialization problem.

And, oops, when I tried to do some assertions, I detected that
"axis_group_extent - axis_group->extent (axis_group,
Y_AXIS).length()", which I would have expected to be roughly 0,
returns values of around 16 and more in typical examples ly files...

And, finally, one other thing: PLEASE, PLEASE fix ly2dvi so that it
aborts with an error message, if lilypond segfaults.  It cost me at
least one hour to track down a silly seg fault, because lily crashed,
but the output on the screen looked as if lily had exited normally,
followed by a successful LaTeX run on lily's (due to the crash)
incomplete output.

Greetings,
           Juergen

###############################################################################

--- scm/grob-description.scm.orig       Mon Apr  9 00:26:49 2001
+++ scm/grob-description.scm    Wed Apr 25 01:56:59 2001
@@ -511,7 +511,7 @@
        (SpanBar . (
                (break-align-symbol . Staff_bar)
                (barsize-procedure . ,Span_bar::get_bar_size) 
-               (molecule-callback . ,Bar::brew_molecule)
+               (molecule-callback . ,Span_bar::brew_molecule)
                (visibility-lambda . ,begin-of-line-invisible)
                (X-extent-callback . ,Span_bar::width_callback)
                (Y-offset-callbacks . (,Span_bar::center_on_spanned_callback))

###############################################################################

--- lily/include/span-bar.hh.orig       Sun Mar 11 19:10:33 2001
+++ lily/include/span-bar.hh    Tue Apr 24 23:49:58 2001
@@ -29,6 +29,7 @@
   static void evaluate_empty (Grob*);
   DECLARE_SCHEME_CALLBACK (width_callback, (SCM smob, SCM axis));
   DECLARE_SCHEME_CALLBACK (get_bar_size, (SCM ));
+  DECLARE_SCHEME_CALLBACK (brew_molecule, (SCM ));
   DECLARE_SCHEME_CALLBACK (before_line_breaking, (SCM ));
   DECLARE_SCHEME_CALLBACK (center_on_spanned_callback, (SCM element, SCM 
axis));
 };

###############################################################################

--- lily/span-bar.cc.orig       Sun Mar 11 19:10:34 2001
+++ lily/span-bar.cc    Sat Apr 28 23:20:15 2001
@@ -25,6 +25,131 @@
   me->add_dependency (b);
 }
 
+MAKE_SCHEME_CALLBACK (Span_bar,brew_molecule,1);
+
+/**
+ * Limitations/Bugs:
+ *
+ * (1) Elements from 'me->get_grob_property ("elements")' must be
+ * ordered according to their y coordinates relative to their common
+ * axis group parent.  Otherwise, the computation goes mad.  (TODO:
+ * apply a sort algorithm that ensures this precondition.)  However,
+ * until now, I have seen no case where lily has not fulfilled this
+ * precondition.
+ *
+ * (2) This method depends on bar_engraver not being removed from
+ * staff context.  If bar_engraver is removed, the size of the staff
+ * lines is evaluated as 0, which results in a solid span bar line
+ * with faulty y coordinate.
+ *
+ */
+SCM
+Span_bar::brew_molecule (SCM smobbed_me) 
+{
+  Grob *me = unsmob_grob (smobbed_me);
+  Span_bar::evaluate_glyph(me);
+  SCM glyph = me->get_grob_property (ly_symbol2scm ("glyph"));
+  String glyph_str = ly_scm2string (glyph);
+  SCM first_elt = me->get_grob_property ("elements");
+
+  // first walk: compute axis_group parent via common_refpoint () on all bars
+  Grob *refpoint = 0;
+  int staff_bar_count = 0;
+  for (SCM elts = first_elt;
+       elts != SCM_EOL;
+       elts = gh_cdr (elts))
+  {
+    SCM smobbed_staff_bar = gh_car (elts);
+    Grob *staff_bar = unsmob_grob (smobbed_staff_bar);
+    refpoint = (staff_bar_count > 0) ?
+      staff_bar->common_refpoint (refpoint, Y_AXIS) :
+      staff_bar;
+    staff_bar_count++;
+  }
+  /* assert: refpoint is an axis-group object */
+  Grob *axis_group = refpoint;
+
+  // second walk: collect span bar components;
+  // compute extent of axis_group
+  Real last_staff_bar_length;
+  Real *interstaff_bar_length = new Real[staff_bar_count];
+  Real *interstaff_bar_yoffs = new Real[staff_bar_count];
+  Molecule *interstaff_bar_molecule = new Molecule[staff_bar_count];
+  Real axis_group_extent = 0.0;
+  staff_bar_count = 0;
+  for (SCM elts = first_elt;
+       elts != SCM_EOL;
+       elts = gh_cdr (elts))
+  {
+    SCM smobbed_staff_bar = gh_car (elts);
+    SCM smobbed_staff_bar_molecule =
+      Bar::brew_molecule (smobbed_staff_bar);
+    Grob *staff_bar = unsmob_grob (smobbed_staff_bar);
+    interstaff_bar_yoffs[staff_bar_count] =
+      staff_bar->relative_coordinate (axis_group, (Axis)Y_AXIS);
+    if (smobbed_staff_bar_molecule != SCM_EOL)
+    {
+      Real staff_bar_length =
+       unsmob_molecule (smobbed_staff_bar_molecule)->
+       extent (Y_AXIS).length ();
+      if (staff_bar_count > 0)
+      {
+       // clone bar_molecule and fix y extent
+       interstaff_bar_length[staff_bar_count] =
+         interstaff_bar_yoffs[staff_bar_count] -
+         interstaff_bar_yoffs[staff_bar_count - 1] -
+         last_staff_bar_length;
+       SCM smobbed_interstaff_bar_molecule = 
+         Bar::compound_barline (staff_bar, glyph_str,
+                                interstaff_bar_length[staff_bar_count]).
+         smobbed_copy ();
+       interstaff_bar_molecule[staff_bar_count] =
+         *unsmob_molecule (smobbed_interstaff_bar_molecule);
+      }
+      else
+      {
+       interstaff_bar_molecule[staff_bar_count] = Molecule::Molecule ();
+      }
+      last_staff_bar_length = staff_bar_length;
+    }
+    else
+    {
+      last_staff_bar_length = 0;
+      interstaff_bar_length[staff_bar_count] = 0;
+      interstaff_bar_molecule[staff_bar_count] = Molecule::Molecule ();
+    }
+    axis_group_extent += last_staff_bar_length;
+    axis_group_extent += interstaff_bar_length[staff_bar_count];
+    staff_bar_count++;
+  }
+  // assert(abs(axis_group_extent -
+  //           axis_group->extent (axis_group, Y_AXIS).length ()) < EPSILON);
+
+  // third walk: correct y axis on all span bar components;
+  // put all components into a single span bar molecule
+  Molecule span_bar_molecule = Molecule::Molecule ();
+  staff_bar_count = 0;
+  for (SCM elts = first_elt;
+       elts != SCM_EOL;
+       elts = gh_cdr (elts))
+  {
+    interstaff_bar_yoffs[staff_bar_count] +=
+      (axis_group_extent - interstaff_bar_length[staff_bar_count]) / 2;
+    interstaff_bar_molecule[staff_bar_count].//DEBUG
+      translate_axis (-1.0 PT, X_AXIS);//DEBUG
+    interstaff_bar_molecule[staff_bar_count].
+      translate_axis (interstaff_bar_yoffs[staff_bar_count], Y_AXIS);
+    span_bar_molecule.add_molecule (interstaff_bar_molecule[staff_bar_count]);
+    staff_bar_count++;
+  }
+
+  // clean-up & exit
+  delete interstaff_bar_length;
+  delete interstaff_bar_yoffs;
+  delete interstaff_bar_molecule;
+  return span_bar_molecule.smobbed_copy ();
+}
+
 MAKE_SCHEME_CALLBACK (Span_bar,width_callback,2);
 SCM
 Span_bar::width_callback (SCM element_smob, SCM scm_axis)

###############################################################################

span-bar-test.ly:
\score {
 \notes \relative c' \context StaffGroup = groupie <
  \context Staff = SA { c1 c1 c1}
  \context Lyrics = LA \lyrics <
   { bla1 die bla }
  >
  \context Staff = SB { a1 a1 a1}
  \context Lyrics = LB \lyrics <
   { bla1 die bla }
   { foo bar foo }
  >
  \context Staff = SC { f1 f1 f1}
  \context Lyrics = LC \lyrics <
   { bla1 die bla }
   { foo bar foo }
   { foo bar foo }
  >
  \context Staff = SD { d1 d1 d1}
  \context Lyrics = LD \lyrics <
   { bla1 die bla }
   { foo bar foo }
   { foo bar foo }
   { foo bar foo }
  >
 >
 \paper {
  \translator {
   \StaffContext
  }
 }
}



reply via email to

[Prev in Thread] Current Thread [Next in Thread]