]> git.donarmstrong.com Git - lilypond.git/commitdiff
Merge branch 'master' into lilypond/translation
authorFrancisco Vila <francisco.vila@hispalinux.es>
Mon, 18 May 2009 13:12:53 +0000 (15:12 +0200)
committerFrancisco Vila <francisco.vila@hispalinux.es>
Mon, 18 May 2009 13:12:53 +0000 (15:12 +0200)
12 files changed:
Documentation/user/chords.itely
input/regression/chordnames-nochord.ly [new file with mode: 0644]
lily/align-interface.cc
lily/axis-group-interface.cc
lily/chord-name-engraver.cc
lily/include/axis-group-interface.hh
lily/page-spacing.cc
ly/engraver-init.ly
scm/define-context-properties.scm
scm/define-grob-properties.scm
scm/fret-diagrams.scm
scripts/musicxml2ly.py

index 5b5422b6f6f582ac236d1180100fa37ea1538879..9e548efc6283520e0b391cdb1a68875e46ddd4e3 100644 (file)
@@ -454,6 +454,30 @@ of the mode of entry, unless there are inversions or added bass notes:
 >>
 @end lilypond
 
+@cindex no chord symbol
+@cindex N.C. symbol
+@cindex indicating No Chord in ChordNames
+
+Rests passed to a @code{ChordNames} context will cause the
+@code{noChordSymbol} markup to be displayed.
+
+@lilypond[verbatim, quote, relative=1]
+<<
+  \new ChordNames \chordmode {
+    c1
+    r1
+    g1
+    c1
+  }
+  \new Score \chordmode {
+    c1
+    r1
+    g1
+    c1
+  }
+>>
+@end lilypond
+
 @funindex{\chords}
 
 @code{\chords @{ ... @}} is a shortcut notation for
diff --git a/input/regression/chordnames-nochord.ly b/input/regression/chordnames-nochord.ly
new file mode 100644 (file)
index 0000000..6512421
--- /dev/null
@@ -0,0 +1,30 @@
+\version "2.13.1"
+
+\header {
+  texidoc = "Rests in music passed to ChordNames context display noChordSymbol.
+noChordSymbol is treated like a ChordName with respect to chordChanges.
+"
+}
+
+myChords = \chordmode {
+  c1 r1 r1 \break
+  r1 g1 c1 \break
+}
+
+\score {
+  <<
+    \new ChordNames { 
+      \myChords 
+      \set chordChanges = ##t
+      \myChords
+    }
+    \new FretBoards { 
+      \myChords 
+      \myChords
+    }
+    \new Staff { 
+      \myChords 
+      \myChords
+    }
+  >>
+}
index 27839aca920d46ce08dcce76b34271d064ac1168..d69930c3aa5ec715ab7bf2a42020506c966fab4b 100644 (file)
@@ -84,6 +84,8 @@ Align_interface::stretch_after_break (SCM grob)
    an empty extent, delete it from the list instead. If the extent is
    non-empty but there is no skyline available (or pure is true), just
    create a flat skyline from the bounding box */
+// TODO(jneem): the pure and non-pure parts seem to share very little
+// code. Split them into 2 functions, perhaps?
 static void
 get_skylines (Grob *me,
              vector<Grob*> *const elements,
@@ -137,9 +139,32 @@ get_skylines (Grob *me,
            {
              Box b;
              b[a] = extent;
-             b[other_axis (a)] = Interval (-infinity_f, infinity_f);
+             b[other_axis (a)] = Interval (0, infinity_f);
              skylines.insert (b, 0, other_axis (a));
            }
+
+         // This is a hack to get better accuracy on the pure-height of VerticalAlignment.
+         // It's quite common for a treble clef to be the highest element of one system
+         // and for a low note (or lyrics) to be the lowest note on another. The two will
+         // never collide, but the pure-height stuff only works with bounding boxes, so it
+         // doesn't know that. The result is a significant over-estimation of the pure-height,
+         // especially on systems with many staves. To correct for this, we build a skyline
+         // in two parts: the part we did above contains most of the grobs (note-heads, etc.)
+         // while the bit we're about to do only contains the breakable grobs at the beginning
+         // of the system. This way, the tall treble clefs are only compared with the treble
+         // clefs of the other staff and they will be ignored if the staff above is, for example,
+         // lyrics.
+         if (Axis_group_interface::has_interface (g))
+           {
+             Interval begin_of_line_extent = Axis_group_interface::begin_of_line_pure_height (g, start);
+             if (!begin_of_line_extent.is_empty ())
+               {
+                 Box b;
+                 b[a] = begin_of_line_extent;
+                 b[other_axis (a)] = Interval (-infinity_f, -1);
+                 skylines.insert (b, 0, other_axis (a));
+               }
+           }
        }
 
       if (skylines.is_empty ())
index 639c8b6267a12a6450cfe7739009e7e6b311cdbb..d14a56c08440ebdfecfff635ba1c6469272b28fc 100644 (file)
@@ -74,26 +74,37 @@ Axis_group_interface::relative_group_extent (vector<Grob*> const &elts,
   return r;
 }
 
+Interval
+Axis_group_interface::cached_pure_height (Grob *me, int start, int end)
+{
+  SCM adjacent_pure_heights = me->get_property ("adjacent-pure-heights");
 
-/*
-  FIXME: pure extent handling has a lot of ad-hoc caching.
-  This should be done with grob property callbacks.
+  if (!scm_is_pair (adjacent_pure_heights)
+      || !scm_is_vector (scm_cdr (adjacent_pure_heights)))
+    return Interval (0, 0);
 
-  --hwn
-*/
+  return combine_pure_heights (me, scm_cdr (adjacent_pure_heights), start, end);
+}
 
 Interval
-Axis_group_interface::cached_pure_height (Grob *me, int start, int end)
+Axis_group_interface::begin_of_line_pure_height (Grob *me, int start)
+{
+  SCM adjacent_pure_heights = me->get_property ("adjacent-pure-heights");
+
+  if (!scm_is_pair (adjacent_pure_heights)
+      || !scm_is_vector (scm_car (adjacent_pure_heights)))
+    return Interval (0, 0);
+
+  return combine_pure_heights (me, scm_car (adjacent_pure_heights), start, start+1);
+}
+
+Interval
+Axis_group_interface::combine_pure_heights (Grob *me, SCM measure_extents, int start, int end)
 {
   Paper_score *ps = get_root_system (me)->paper_score ();
   vector<vsize> breaks = ps->get_break_indices ();
   vector<Grob*> cols = ps->get_columns ();
 
-  SCM extents = me->get_property ("adjacent-pure-heights");
-
-  if (!scm_is_vector (extents))
-    return Interval (0, 0);
-
   Interval ext;
   for (vsize i = 0; i + 1 < breaks.size (); i++)
     {
@@ -102,12 +113,19 @@ Axis_group_interface::cached_pure_height (Grob *me, int start, int end)
        break;
 
       if (r >= start)
-       ext.unite (ly_scm2interval (scm_c_vector_ref (extents, i)));
+       ext.unite (ly_scm2interval (scm_c_vector_ref (measure_extents, i)));
     }
 
   return ext;
 }
 
+// adjacent-pure-heights is a pair of vectors, each of which has one element
+// for every measure in the score. The first vector stores, for each measure,
+// the combined height of the elements that are present only when the bar
+// is at the beginning of a line. The second vector stores, for each measure,
+// the combined height of the elements that are present only when the bar
+// is not at the beginning of a line.
+
 MAKE_SCHEME_CALLBACK (Axis_group_interface, adjacent_pure_heights, 1)
 SCM
 Axis_group_interface::adjacent_pure_heights (SCM smob)
@@ -122,13 +140,16 @@ Axis_group_interface::adjacent_pure_heights (SCM smob)
   vector<vsize> breaks = ps->get_break_indices ();
   vector<Grob*> cols = ps->get_columns ();
 
-  SCM ret = scm_c_make_vector (breaks.size () - 1, SCM_EOL);
+  SCM begin_line_heights = scm_c_make_vector (breaks.size () - 1, SCM_EOL);
+  SCM mid_line_heights = scm_c_make_vector (breaks.size () - 1, SCM_EOL);
+
   vsize it_index = 0;
   for (vsize i = 0; i + 1 < breaks.size (); i++)
     {
       int start = Paper_column::get_rank (cols[breaks[i]]);
       int end = Paper_column::get_rank (cols[breaks[i+1]]);
-      Interval iv;
+      Interval begin_line_iv;
+      Interval mid_line_iv;
 
       for (vsize j = it_index; j < items.size (); j++)
        {
@@ -139,8 +160,10 @@ Axis_group_interface::adjacent_pure_heights (SCM smob)
              && !to_boolean (it->get_property ("cross-staff")))
            {
              Interval dims = items[j]->pure_height (common, start, end);
+             Interval &target_iv = it->pure_is_visible (start-1, end) ? mid_line_iv : begin_line_iv;
+
              if (!dims.is_empty ())
-               iv.unite (dims);
+               target_iv.unite (dims);
            }
 
          if (rank < end)
@@ -156,14 +179,16 @@ Axis_group_interface::adjacent_pure_heights (SCM smob)
              && !to_boolean (spanners[j]->get_property ("cross-staff")))
            {
              Interval dims = spanners[j]->pure_height (common, start, end);
+
              if (!dims.is_empty ())
-               iv.unite (dims);
+               mid_line_iv.unite (dims);
            }
        }
 
-      scm_vector_set_x (ret, scm_from_int (i), ly_interval2scm (iv));
+      scm_vector_set_x (begin_line_heights, scm_from_int (i), ly_interval2scm (begin_line_iv));
+      scm_vector_set_x (mid_line_heights, scm_from_int (i), ly_interval2scm (mid_line_iv));
     }
-  return ret;
+  return scm_cons (begin_line_heights, mid_line_heights);
 }
 
 Interval
index f8858998a1d963669bc18d37f1ccc3d0aa8b6d43..288e29348076fea42f9f7a6526c274f903c168f5 100644 (file)
@@ -16,6 +16,7 @@
 #include "pitch.hh"
 #include "protected-scm.hh"
 #include "stream-event.hh"
+#include "text-interface.hh"
 #include "warn.hh"
 
 #include "translator.icc"
@@ -29,11 +30,13 @@ protected:
   virtual void finalize ();
   virtual void derived_mark () const;
   DECLARE_TRANSLATOR_LISTENER (note);
+  DECLARE_TRANSLATOR_LISTENER (rest);
 private:
   Item *chord_name_;
   vector<Stream_event*> notes_;
-
   SCM last_chord_;
+  Stream_event *rest_event_;
 };
 
 void
@@ -51,68 +54,80 @@ Chord_name_engraver::Chord_name_engraver ()
 {
   chord_name_ = 0;
   last_chord_ = SCM_EOL;
+  rest_event_ = 0;
 }
 
 void
 Chord_name_engraver::process_music ()
-{
-  if (!notes_.size ())
-    return;
-
+{ 
+  SCM markup;
   SCM bass = SCM_EOL;
   SCM inversion = SCM_EOL;
   SCM pitches = SCM_EOL;
 
-  Stream_event *inversion_event = 0;
-  for (vsize i = 0; i < notes_.size (); i++)
+  if (rest_event_)
     {
-      Stream_event *n = notes_[i];
-      SCM p = n->get_property ("pitch");
-      if (!unsmob_pitch (p))
-       continue;
-
-      if (n->get_property ("inversion") == SCM_BOOL_T)
-       {
-         inversion_event = n;
-         inversion = p;
-       }
-      else if (n->get_property ("bass") == SCM_BOOL_T)
-       bass = p;
-      else
-       pitches = scm_cons (p, pitches);
+      SCM no_chord_markup = get_property ("noChordSymbol");
+      if (!Text_interface::is_markup (no_chord_markup))
+        return;
+      markup = no_chord_markup;
     }
-
-  if (inversion_event)
-    {
-      SCM oct = inversion_event->get_property ("octavation");
-      if (scm_is_number (oct))
-       {
-         Pitch *p = unsmob_pitch (inversion_event->get_property ("pitch"));
-         int octavation = scm_to_int (oct);
-         Pitch orig = p->transposed (Pitch (-octavation, 0, 0));
-
-         pitches = scm_cons (orig.smobbed_copy (), pitches);
-       }
-      else
-       programming_error ("inversion does not have original pitch");
+  else
+    {  
+      if (!notes_.size ())
+        return;
+
+      Stream_event *inversion_event = 0;
+      for (vsize i = 0; i < notes_.size (); i++)
+      {
+        Stream_event *n = notes_[i];
+        SCM p = n->get_property ("pitch");
+        if (!unsmob_pitch (p))
+          continue;
+
+        if (n->get_property ("inversion") == SCM_BOOL_T)
+        {
+          inversion_event = n;
+          inversion = p;
+        }
+        else if (n->get_property ("bass") == SCM_BOOL_T)
+          bass = p;
+        else
+          pitches = scm_cons (p, pitches);
+      }
+
+      if (inversion_event)
+      {
+        SCM oct = inversion_event->get_property ("octavation");
+        if (scm_is_number (oct))
+        {
+          Pitch *p = unsmob_pitch (inversion_event->get_property ("pitch"));
+          int octavation = scm_to_int (oct);
+          Pitch orig = p->transposed (Pitch (-octavation, 0, 0));
+
+          pitches = scm_cons (orig.smobbed_copy (), pitches);
+        }
+        else
+          programming_error ("inversion does not have original pitch");
+      }
+
+      pitches = scm_sort_list (pitches, Pitch::less_p_proc);
+
+      SCM name_proc = get_property ("chordNameFunction");
+      markup = scm_call_4 (name_proc, pitches, bass, inversion,
+          context ()->self_scm ());
     }
-
-  pitches = scm_sort_list (pitches, Pitch::less_p_proc);
-
-  SCM name_proc = get_property ("chordNameFunction");
-  SCM markup = scm_call_4 (name_proc, pitches, bass, inversion,
-                          context ()->self_scm ());
-
   /*
     Ugh.
   */
   SCM chord_as_scm = scm_cons (pitches, scm_cons (bass, inversion));
 
-  chord_name_ = make_item ("ChordName", notes_[0]->self_scm ());
+  chord_name_ = make_item ("ChordName", 
+      rest_event_ ? rest_event_->self_scm () : notes_[0]->self_scm ());
   chord_name_->set_property ("text", markup);
 
-  SCM s = get_property ("chordChanges");
-  if (to_boolean (s) && scm_is_pair (last_chord_)
+  SCM chord_changes = get_property("chordChanges");
+  if (to_boolean (chord_changes) && scm_is_pair (last_chord_)
       && ly_is_equal (chord_as_scm, last_chord_))
     chord_name_->set_property ("begin-of-line-visible", SCM_BOOL_T);
 
@@ -126,11 +141,19 @@ Chord_name_engraver::listen_note (Stream_event *ev)
   notes_.push_back (ev);
 }
 
+IMPLEMENT_TRANSLATOR_LISTENER (Chord_name_engraver, rest);
+void
+Chord_name_engraver::listen_rest (Stream_event *ev)
+{
+  ASSIGN_EVENT_ONCE(rest_event_, ev);
+}
+  
 void
 Chord_name_engraver::stop_translation_timestep ()
 {
   chord_name_ = 0;
   notes_.clear ();
+  rest_event_ = 0;
 }
 
 /*
@@ -139,7 +162,7 @@ Chord_name_engraver::stop_translation_timestep ()
 */
 ADD_TRANSLATOR (Chord_name_engraver,
                /* doc */
-               "Catch note events and generate the appropriate chordname.",
+               "Catch note and rest events and generate the appropriate chordname.",
 
                /* create */
                "ChordName ",
@@ -151,7 +174,8 @@ ADD_TRANSLATOR (Chord_name_engraver,
                "chordNoteNamer "
                "chordRootNamer "
                "chordNameExceptions "
-               "majorSevenSymbol ",
+               "majorSevenSymbol "
+                "noChordSymbol ",
 
                /* write */
                ""
index 6dd2e7b95c27ae404303030e9ff2e67b4b667ee1..f852c92a34165e98bc2b59a8ad0d22b01d2f86db 100644 (file)
@@ -31,7 +31,9 @@ struct Axis_group_interface
   static Interval relative_group_extent (vector<Grob*> const &list,
                                         Grob *common, Axis);
   static Interval relative_pure_height (Grob *me, int start, int end);
+  static Interval combine_pure_heights (Grob *me, SCM, int, int);
   static Interval cached_pure_height (Grob *me, int, int);
+  static Interval begin_of_line_pure_height (Grob *me, int);
 
   static Grob *calc_pure_elts_and_common (Grob*);
   static Skyline_pair skyline_spacing (Grob *me, vector<Grob*> elements);
index 3eb7c8f4a067345e836ba562bea90d2486b8bf87..c236c94e88936193defac0c3f5ffa6631901503f 100644 (file)
@@ -16,8 +16,9 @@
 void
 Page_spacing::calc_force ()
 {
-  /* If the first system is a title, we add back in the page-top-space. */
-  Real height = first_line_.title_ ? page_height_ + page_top_space_ : page_height_;
+  /* If the first system contains a title, we add back in the page-top-space. */
+  bool starts_with_title = first_line_.compressed_nontitle_lines_count_ < first_line_.compressed_lines_count_;
+  Real height = starts_with_title ? page_height_ + page_top_space_ : page_height_;
 
   if (rod_height_ + last_line_.bottom_padding_ >= height)
     force_ = infinity_f;
index 9aae417aa8bf04819ea86c02a72990bd4d3977ee..ba7b18b218946e30284c14a30b8b91dd55f72ce7 100644 (file)
@@ -561,7 +561,7 @@ automatically when an output definition (a @code{\score} or
   chordPrefixSpacer = #0
   chordNameExceptionsFull = #fullJazzExceptions
   chordNameExceptionsPartial = #partialJazzExceptions
-  
+  noChordSymbol = #(make-simple-markup "N.C.")
 
   bassStaffProperties = #'((assign clefGlyph "clefs.F")
   (assign clefPosition 2)
index 1012c8685568a32a833db3fb6f713f11c216c501..3b18e94df45aabcd5fdb6907e479287cd63fa9d8 100644 (file)
@@ -332,6 +332,8 @@ page turn to be allowed.")
 repeated section for a page turn to be allowed within that section.")
 
 
+     (noChordSymbol ,markup? "Markup to be displayed for rests in a
+ChordNames context.")
      (noteToFretFunction ,procedure? "How to produce a fret diagram.
 Parameters: A list of note events and a list of tabstring events.")
 
index 8d166a4d235e399c9c4efc6cbd4aff1c292645c8..af9aa948d0652fec53b2d0f3a59f82f68a6de476 100644 (file)
@@ -841,7 +841,7 @@ constructed from a whole number of squiggles.")
      (accidental-grob ,ly:grob? "The accidental for this note.")
      (accidental-grobs ,list? "An alist with @code{(@var{notename} .
 @var{groblist})} entries.")
-     (adjacent-pure-heights ,vector? "Used by a @code{VerticalAxisGroup} to
+     (adjacent-pure-heights ,pair? "A pair of vectors. Used by a @code{VerticalAxisGroup} to
 cache the @code{Y-extent}s of different column ranges.")
      (adjacent-hairpins ,ly:grob-array? "A list of directly neighboring
 hairpins.")
index a37c490aa9880facbe4b49ac787a4bd0a2a296b1..992c94941aa1ddd8e29c39e89ed516a768e05849 100644 (file)
@@ -293,6 +293,19 @@ with magnification @var{mag} of the string @var{text}."
         (else
           (cons string-coordinate (- fret-coordinate)))))
 
+    (define (stencil-coordinate-offset fret-offset string-offset)
+      "Return a pair @code{(x-offset . y-offstet)}
+      for translation in stencil coordinate system."
+      (cond
+        ((eq? orientation 'landscape)
+         (cons fret-offset (- string-offset)))
+        ((eq? orientation 'opposing-landscape)
+         (cons (- fret-offset) string-offset))
+        (else
+          (cons string-offset (- fret-offset)))))
+
+
+
     (define (make-bezier-sandwich-list start stop base height
                                        half-thickness)
       "Make the argument list for a bezier sandwich from
@@ -642,6 +655,7 @@ fret-diagram overall parameters."
          (if (null? restlist)
            positioned-glyph
            (ly:stencil-add
+             positioned-glyph
              (draw-xo restlist)))))
 
        (define (draw-capo fret)
@@ -734,18 +748,19 @@ at @var{fret}."
              (xo-stencil (draw-xo xo-list))
              (xo-fret-offset
                (stencil-fretboard-offset
-                 xo-stencil 'fret orientation)))
+                 xo-stencil 'fret orientation))
+             (xo-stencil-offset
+              (stencil-coordinate-offset
+               (- diagram-fret-top 
+                  xo-fret-offset
+                  (* size xo-padding))
+               0)))
         (set! fret-diagram-stencil
           (ly:stencil-add
             fret-diagram-stencil
             (ly:stencil-translate
               xo-stencil
-              (stencil-coordinates
-                (- diagram-fret-top
-                   xo-fret-offset
-                   (* size xo-padding))
-                0)))))) ; no string offset
-
+              xo-stencil-offset)))))
     (if (> capo-fret 0)
       (set! fret-diagram-stencil
         (ly:stencil-add
index d9dfaf3be64171ae4de27938ac1f56be4b22434c..b45cf41508089599bf9ec00ff4aec34538d4ba47 100644 (file)
@@ -945,11 +945,11 @@ def musicxml_print_to_lily (el):
     #      page-number CDATA #IMPLIED 
     #  >
     elts = []
-    if (hasattr (el, "new-system")):
+    if (hasattr (el, "new-system") and conversion_settings.convert_page_layout):
         val = getattr (el, "new-system")
         if (val == "yes"):
             elts.append (musicexp.Break ("break"))
-    if (hasattr (el, "new-page")):
+    if (hasattr (el, "new-page") and conversion_settings.convert_page_layout):
         val = getattr (el, "new-page")
         if (val == "yes"):
             elts.append (musicexp.Break ("pageBreak"))
@@ -2665,6 +2665,12 @@ information.""") % 'lilypond')
                   dest = "convert_rest_positions",
                   help = _ ("do not convert exact vertical positions of rests"))
 
+    p.add_option ('--npl', '--no-page-layout', 
+                  action = "store_false",
+                  default = True,
+                  dest = "convert_page_layout",
+                  help = _ ("do not convert the exact page layout and breaks"))
+
     p.add_option ('--no-beaming', 
                   action = "store_false",
                   default = True,
@@ -2901,7 +2907,7 @@ def convert (filename, options):
     print_ly_additional_definitions (printer, filename)
     if score_information:
         score_information.print_ly (printer)
-    if paper_information:
+    if paper_information and conversion_settings.convert_page_layout:
         paper_information.print_ly (printer)
     if layout_information:
         layout_information.print_ly (printer)
@@ -2940,6 +2946,7 @@ def main ():
         needed_additional_definitions.append (options.language)
         additional_definitions[options.language] = "\\include \"%s.ly\"\n" % options.language
     conversion_settings.ignore_beaming = not options.convert_beaming
+    conversion_settings.convert_page_layout = options.convert_page_layout
 
     # Allow the user to leave out the .xml or xml on the filename
     basefilename = args[0].decode('utf-8')