c1
\key cis \major
\clef alto
- \override Score.RehearsalMark #'break-align-symbol = #'key-signature
+ \override Score.RehearsalMark #'break-align-symbols = #'(key-signature)
\mark "on key"
cis
\key ces \major
- \override Score.RehearsalMark #'break-align-symbol = #'clef
+ \override Score.RehearsalMark #'break-align-symbols = #'(clef)
\clef treble
\mark "on clef"
ces
- \override Score.RehearsalMark #'break-align-symbol = #'time-signature
+ \override Score.RehearsalMark #'break-align-symbols = #'(time-signature)
\key d \minor
\clef tenor
\time 3/4
}
@end lilypond
+The text marks will, by default, be aligned with the middle of the notation
+object, but this can be changed by overriding the
+@code{break-align-anchor-alignment} and
+@code{break-align-anchor} properties for the appropriate grob.
+
+@lilypond[fragment,quote,ragged-right,verbatim]
+{
+ \override Score.RehearsalMark #'break-align-symbols = #'(key-signature)
+ c1
+ \key cis \major
+
+ % the RehearsalMark will be aligned with the left edge of the KeySignature
+ \once \override Staff.KeySignature #'break-align-anchor-alignment = #LEFT
+ \mark \default
+ cis1
+ \key ces \major
+
+ % the RehearsalMark will be aligned with the right edge of the KeySignature
+ \once \override Staff.KeySignature #'break-align-anchor-alignment = #RIGHT
+ \mark \default
+ ces1
+
+ % the RehearsalMark will be aligned with the right edge of the KeySignature
+ % and then shifted right by an additional 2 units.
+ \once \override Staff.KeySignature #'break-align = #2
+ \mark \default
+ ces1
+}
+
Although text marks are normally only printed above the topmost
staff, you may alter this to print them on every staff,
\header {
texidoc = "Hairpins extend to the extremes of the bound if there
- is no adjacent hairpin of dynamic-text. If there is, the hairpin
+ is no adjacent hairpin or dynamic-text. If there is, the hairpin
extends to the center of the column or the bound of the text
respectively."
\header {
texidoc = "The fill-line markup command should align texts in
- columns. For examlpe, the characters in the center should form one
+ columns. For example, the characters in the center should form one
column."
}
\version "2.10.0"
\header {
- texidoc = "With the new chord syntax, it is possible to associate
+ texidoc = "It is possible to associate
fingerings uniquely with notes. This makes it possible to add
horizontal fingerings to notes.
\layout {
line-width = 18.\cm
}
-\relative c'' \context GrandStaff {
+\relative c'' {
#(set-accidental-style 'piano-cautionary)
\time 2/4
d16 d d d d d cis d dis dis dis dis
\override Score.NonMusicalPaperColumn #'layer = #1
s1
- <b' c'' c'>1\arpeggio
+ <b' c'' c'>2\arpeggio
}
\context Voice \relative c {
+ \override Score.PaperColumn #'layer = #1
+ \override Score.PaperColumn #'stencil = #ly:paper-column::print
+
%% make sure neutral is down.
\override Stem #'neutral-direction = #down
\time 16/4 c''4 c c, c' d, c' e, c' f, c' g c a c b c
\layout { ragged-right = ##t}
\relative c'' {
+ \override Score.PaperColumn #'layer = #1
+ \override Score.PaperColumn #'stencil = #ly:paper-column::print
+
\stemDown
\time 12/4
f8[
#include "pitch.hh"
#include "protected-scm.hh"
#include "rhythmic-head.hh"
+#include "separation-item.hh"
#include "side-position-interface.hh"
#include "stream-event.hh"
#include "tie.hh"
void acknowledge_arpeggio (Grob_info);
void acknowledge_rhythmic_head (Grob_info);
void acknowledge_finger (Grob_info);
+ void acknowledge_note_column (Grob_info);
void stop_translation_timestep ();
void process_acknowledged ();
vector<Accidental_entry> accidentals_;
vector<Spanner*> ties_;
+ vector<Grob*> note_columns_;
};
/*
}
}
+ if (accidental_placement_)
+ for (vsize i = 0; i < note_columns_.size (); i++)
+ Separation_item::add_conditional_item (note_columns_[i], accidental_placement_);
+
accidental_placement_ = 0;
accidentals_.clear ();
left_objects_.clear ();
ties_.push_back (dynamic_cast<Spanner *> (info.grob ()));
}
+void
+Accidental_engraver::acknowledge_note_column (Grob_info info)
+{
+ note_columns_.push_back (info.grob ());
+}
+
void
Accidental_engraver::acknowledge_arpeggio (Grob_info info)
{
ADD_ACKNOWLEDGER (Accidental_engraver, finger);
ADD_ACKNOWLEDGER (Accidental_engraver, rhythmic_head);
ADD_ACKNOWLEDGER (Accidental_engraver, tie);
+ADD_ACKNOWLEDGER (Accidental_engraver, note_column);
ADD_TRANSLATOR (Accidental_engraver,
}
vector<Grob*>
-Accidental_placement::get_break_reminder_accidentals (vector<Grob*> const &elts, Grob *left)
+Accidental_placement::get_relevant_accidentals (vector<Grob*> const &elts, Grob *left)
{
vector<Grob*> br;
vector<Grob*> ra;
vector<Grob*> ret;
-
- if (dynamic_cast<Item *> (left)->break_status_dir () != RIGHT)
- return vector<Grob*> ();
+ bool right = dynamic_cast<Item *> (left)->break_status_dir () == RIGHT;
for (vsize i = 0; i < elts.size (); i++)
{
split_accidentals (elts[i], &br, &ra);
- ret.insert (ret.end (), br.begin (), br.end ());
- }
- return ret;
-}
-
-/*
- Accidentals are special, because they appear and disappear after
- ties at will.
-*/
-Interval
-Accidental_placement::get_relevant_accidental_extent (Grob *me,
- Item *item_col,
- Grob *left_object)
-{
- vector<Grob*> br, ra;
- vector<Grob*> *which = 0;
-
- Accidental_placement::split_accidentals (me, &br, &ra);
- concat (br, ra);
-
- if (dynamic_cast<Item *> (left_object)->break_status_dir () == RIGHT)
- which = &br;
- else
- which = &ra;
-
- Interval extent;
- for (vsize i = 0; i < which->size (); i++)
- extent.unite (which->at (i)->extent (item_col, X_AXIS));
+
+ ret.insert (ret.end (), ra.begin (), ra.end ());
- if (!extent.is_empty ())
- {
- Real p = robust_scm2double (me->get_property ("left-padding"), 0.2);
- extent[LEFT] -= p;
+ if (right)
+ ret.insert (ret.end (), br.begin (), br.end ());
}
-
- return extent;
+ return ret;
}
struct Accidental_placement_entry
return Grob::stencil_height (smob);
}
+/* If this gets called before line breaking, we will return a non-trivial
+ width even if we belong to a tie and won't actually get printed. */
+MAKE_SCHEME_CALLBACK (Accidental_interface, width, 1);
+SCM
+Accidental_interface::width (SCM smob)
+{
+ Grob *me = unsmob_grob (smob);
+ Stencil *s = unsmob_stencil (get_stencil (me));
+
+ if (s)
+ return ly_interval2scm (s->extent (X_AXIS));
+ return ly_interval2scm (Interval ());
+}
+
MAKE_SCHEME_CALLBACK (Accidental_interface, pure_height, 3);
SCM
Accidental_interface::pure_height (SCM smob, SCM start_scm, SCM)
me->suicide ();
return SCM_EOL;
}
-
+
+ return get_stencil (me);
+}
+
+SCM
+Accidental_interface::get_stencil (Grob *me)
+{
Font_metric *fm = Font_interface::get_default_font (me);
SCM alist = me->get_property ("glyph-name-alist");
void acknowledge_stem (Grob_info);
void acknowledge_rhythmic_head (Grob_info);
- void acknowledge_note_column (Grob_info);
protected:
void process_music ();
void stop_translation_timestep ();
Side_position_interface::add_support (arpeggio_, info.grob ());
}
-void
-Arpeggio_engraver::acknowledge_note_column (Grob_info info)
-{
- if (arpeggio_)
- info.grob ()->set_object ("arpeggio", arpeggio_->self_scm ());
-}
-
void
Arpeggio_engraver::process_music ()
{
ADD_ACKNOWLEDGER (Arpeggio_engraver, stem);
ADD_ACKNOWLEDGER (Arpeggio_engraver, rhythmic_head);
-ADD_ACKNOWLEDGER (Arpeggio_engraver, note_column);
ADD_TRANSLATOR (Arpeggio_engraver,
/* doc */ "Generate an Arpeggio symbol",
positions, one for above the staff, one for below).
In each pass, we loop through the unplaced grobs from left to right.
- If the grob overlaps the right-most affected position, we place it
+ If the grob doesn't overlap the right-most affected position, we place it
(and then update the right-most affected position to point to the right
edge of the just-placed grob). Otherwise, we skip it until the next pass.
*/
"elements "
"keep-fixed-while-stretching "
"max-stretch "
+ "no-alignment "
"pure-Y-common "
"pure-relevant-items "
"pure-relevant-spanners "
#include "score-engraver.hh"
#include "warn.hh"
#include "item.hh"
+#include "spanner.hh"
#include "translator.icc"
void request_bar (string type_string);
protected:
- virtual void finalize ();
void stop_translation_timestep ();
void process_acknowledged ();
+ DECLARE_END_ACKNOWLEDGER (spanner);
+
private:
- void typeset_bar ();
void create_bar ();
Item *bar_;
+ vector<Spanner*> spanners_;
};
Bar_engraver::Bar_engraver ()
}
}
-void
-Bar_engraver::finalize ()
-{
- typeset_bar ();
-}
-
/*
Bar_engraver should come *after* any engravers that
modify whichBar
{
if (!bar_ && scm_is_string (get_property ("whichBar")))
create_bar ();
-}
-void
-Bar_engraver::typeset_bar ()
-{
- bar_ = 0;
+ if (bar_)
+ for (vsize i = 0; i < spanners_.size (); i++)
+ spanners_[i]->set_bound (RIGHT, bar_);
}
/*
{
if (!bar_)
context ()->get_score_context ()->set_property ("forbidBreak", SCM_BOOL_T);
- else
- typeset_bar ();
+
+ bar_ = 0;
+ spanners_.clear ();
+}
+
+void
+Bar_engraver::acknowledge_end_spanner (Grob_info gi)
+{
+ Grob *g = gi.grob ();
+
+ if (to_boolean (g->get_property ("to-barline")))
+ spanners_.push_back (dynamic_cast<Spanner*> (g));
}
+ADD_END_ACKNOWLEDGER (Bar_engraver, spanner);
+
ADD_TRANSLATOR (Bar_engraver,
/* doc */ "Create barlines. This engraver is controlled through the "
"@code{whichBar} property. If it has no bar line to create, it will forbid a linebreak at this point",
{
Grob *me = unsmob_grob (smob);
+ /*
+ Trigger note collision resolution first, since that may kill off
+ dots when merging.
+ */
+ if (Grob *collision = unsmob_grob (me->get_object ("note-collision")))
+ (void) collision->get_property ("positioning-done");
+
me->set_property ("positioning-done", SCM_BOOL_T);
vector<Grob*> dots
Real ss = 0;
Grob *commonx = me;
- { /*
- Trigger note collision resolution first, since that may kill off
- dots when merging.
- */
- for (vsize i = 0; i < dots.size (); i++)
- {
- Grob *n = dots[i]->get_parent (Y_AXIS);
- commonx = n->common_refpoint (commonx, X_AXIS);
-
- if (Grob *stem = unsmob_grob (n->get_object("stem")))
- {
- commonx = stem->common_refpoint (commonx, X_AXIS);
-
- if (Stem::first_head (stem) == n)
- main_heads.push_back (n);
- }
- }
- }
+ for (vsize i = 0; i < dots.size (); i++)
+ {
+ Grob *n = dots[i]->get_parent (Y_AXIS);
+ commonx = n->common_refpoint (commonx, X_AXIS);
+
+ if (Grob *stem = unsmob_grob (n->get_object("stem")))
+ {
+ commonx = stem->common_refpoint (commonx, X_AXIS);
+
+ if (Stem::first_head (stem) == n)
+ main_heads.push_back (n);
+ }
+ }
vector<Box> boxes;
set<Grob*> stems;
}
finished_cresc_ = cresc_;
+
+ /* backwards compatibility with hairpinToBarline */
+ bool use_bar = to_boolean (get_property ("hairpinToBarline"))
+ && scm_is_string (get_property ("whichBar"))
+ && !script_ev_;
+
+ finished_cresc_->set_property ("to-barline", scm_from_bool (use_bar));
+
+ announce_end_grob (finished_cresc_, SCM_EOL);
cresc_ = 0;
current_cresc_ev_ = 0;
}
{
if (finished_cresc_)
{
- bool use_bar = to_boolean (get_property ("hairpinToBarline"))
- && scm_is_string (get_property ("whichBar"))
- && !script_ev_;
-
-
- if (!finished_cresc_->get_bound (RIGHT)
- || use_bar)
+ if (!finished_cresc_->get_bound (RIGHT))
{
- Grob *column_bound = 0;
- if (use_bar)
- {
- column_bound = unsmob_grob (get_property ("breakableSeparationItem"));
- }
-
- if (!column_bound)
- column_bound = unsmob_grob (use_bar
- ? get_property ("currentCommandColumn")
- : get_property ("currentMusicalColumn"));
+ Grob *column_bound = unsmob_grob (get_property ("currentMusicalColumn"));
finished_cresc_->set_bound (RIGHT, script_
? script_
finished_line_spanner_->set_bound (RIGHT, ci);
finished_line_spanner_->set_bound (LEFT, ci);
}
-
finished_line_spanner_ = 0;
}
}
Real off = 0;
if (dim_cache_[Y_AXIS].offset_)
- off = *dim_cache_[Y_AXIS].offset_;
+ {
+ if (to_boolean (get_property ("pure-Y-offset-in-progress")))
+ programming_error ("cyclic chain in pure-Y-offset callbacks");
+
+ off = *dim_cache_[Y_AXIS].offset_;
+ }
else
{
SCM proc = get_property_data ("Y-offset");
dim_cache_[Y_AXIS].offset_ = new Real (0.0);
+ set_property ("pure-Y-offset-in-progress", SCM_BOOL_T);
off = robust_scm2double (call_pure_function (proc,
scm_list_1 (self_scm ()),
start, end),
0.0);
+ del_property ("pure-Y-offset-in-progress");
delete dim_cache_[Y_AXIS].offset_;
dim_cache_[Y_AXIS].offset_ = 0;
}
"outside-staff-horizontal-padding "
"outside-staff-padding "
"outside-staff-priority "
+ "pure-Y-offset-in-progress "
"rotation "
"springs-and-rods "
"staff-symbol "
{
public:
DECLARE_SCHEME_CALLBACK (print, (SCM));
- DECLARE_SCHEME_CALLBACK (calc_stencils, (SCM));
DECLARE_SCHEME_CALLBACK (height, (SCM));
+ DECLARE_SCHEME_CALLBACK (width, (SCM));
DECLARE_SCHEME_CALLBACK (pure_height, (SCM, SCM, SCM));
DECLARE_GROB_INTERFACE();
static string get_fontcharname (string style, int alteration);
- static vector<Box> accurate_boxes (Grob *me,
- Grob **common);
+ static vector<Box> accurate_boxes (Grob *me, Grob **common);
+ static SCM get_stencil (Grob *me);
};
#endif
DECLARE_SCHEME_CALLBACK (alignment_callback, (SCM element));
static void add_accidental (Grob *, Grob *);
- static vector<Grob*> get_break_reminder_accidentals (vector<Grob*> const &elts,
- Grob *left);
- static Interval get_relevant_accidental_extent (Grob *me,
- Item *item_col,
- Grob *acc);
+ static vector<Grob*> get_relevant_accidentals (vector<Grob*> const &elts, Grob *left);
static void split_accidentals (Grob *accs,
vector<Grob*> *break_reminder,
vector<Grob*> *real_acc);
static Grob *first_head (Grob *me);
static Grob *get_rest (Grob *me);
static void set_stem (Grob *me, Grob *);
- static void set_dotcol (Grob *me, Grob *);
static void add_head (Grob *me, Grob *);
static bool has_rests (Grob *me);
static Grob *dot_column (Grob *me);
#include "grob-interface.hh"
#include "lily-proto.hh"
+#include "spring.hh"
class Note_spacing
{
public:
DECLARE_GROB_INTERFACE();
- static void get_spacing (Grob *me, Item *, Real, Real, Real *, Real *);
+ static Spring get_spacing (Grob *me, Item *, Real, Real);
static void stem_dir_correction (Grob *me, Item *next_col, Real incr,
Real *, Real *);
- static Item *right_column (Grob *);
- static Item *left_column (Grob *);
};
#endif /* NOTE_SPACING_HH */
static Moment when_mom (Grob *);
static bool is_used (Grob *);
static bool is_breakable (Grob *);
+ static Real minimum_distance (Grob *l, Grob *r);
};
#endif // PAPER_COLUMN_HH
+++ /dev/null
-/*
- separating-group-spanner.hh -- declare Separating_group_spanner
-
- source file of the GNU LilyPond music typesetter
-
- (c) 1998--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
-*/
-
-#ifndef SEPARATING_GROUP_SPANNER_HH
-#define SEPARATING_GROUP_SPANNER_HH
-
-#include "grob-interface.hh"
-#include "lily-proto.hh"
-
-class Separating_group_spanner
-{
- static void find_rods (Item *,
- vector<Grob*> const &separators,
- vsize idx,
- Real);
-public:
- static void add_spacing_unit (Grob *me, Item *);
-
- DECLARE_GROB_INTERFACE();
- DECLARE_SCHEME_CALLBACK (set_spacing_rods, (SCM));
-};
-
-#endif /* SEPARATING_GROUP_SPANNER_HH */
-
static vector<Box> boxes (Grob *me, Grob *left);
static Skyline conditional_skyline (Grob *, Grob *);
- static Interval width (Grob *);
- static Interval relative_width (Grob *, Grob *);
static Grob *extremal_break_aligned_grob (Grob *, Direction, Interval *);
- static bool set_distance (Drul_array<Item *>, Real);
- static void set_skyline_distance (Drul_array<Item*>, Real);
+ static void set_distance (Drul_array<Item *>, Real);
+ static bool is_empty (Grob *me);
static void add_item (Grob *, Item *);
static void add_conditional_item (Grob *, Grob *);
};
#include "std-vector.hh"
#include "lily-proto.hh"
+#include "spring.hh"
#include "smobs.hh"
-struct Spring_description
-{
- Real ideal_;
- Real inverse_hooke_;
- Real block_force_;
-
- Real length (Real force) const;
- Spring_description ();
-
- bool is_sane () const;
-
- bool operator> (const Spring_description &s) const
- {
- return block_force_ > s.block_force_;
- }
-
- bool operator< (const Spring_description &s) const
- {
- return block_force_ < s.block_force_;
- }
-};
-
class Simple_spacer
{
public:
void solve (Real line_len, bool ragged);
void add_rod (int l, int r, Real dist);
- void add_spring (Real, Real);
+ void add_spring (Spring const&);
Real range_ideal_len (int l, int r) const;
- Real range_stiffness (int l, int r) const;
+ Real range_stiffness (int l, int r, bool stretch) const;
Real configuration_length (Real) const;
vector<Real> spring_positions () const;
Real compress_line ();
Real rod_force (int l, int r, Real dist);
- vector<Spring_description> springs_;
+ vector<Spring> springs_;
Real line_len_;
Real force_;
bool ragged_;
#include "lily-proto.hh"
#include "grob-interface.hh"
+#include "spring.hh"
struct Spaceable_grob
{
/// set a minimum distance
static void add_rod (Grob *me, Grob *to, Real distance);
- static void add_spring (Grob *me, Grob *to, Real dist, Real strength);
- static void get_spring (Grob *me, Grob *other, Real *dist, Real *inv_strength);
+ static void add_spring (Grob *me, Grob *to, Spring sp);
+ static Spring get_spring (Grob *me, Grob *other);
DECLARE_GROB_INTERFACE();
static SCM get_minimum_distances (Grob *);
#include "grob-interface.hh"
#include "lily-proto.hh"
+#ifndef SPACING_INTERFACE_HH
+#define SPACING_INTERFACE_HH
+
struct Spacing_interface
{
+ static Real minimum_distance (Grob *me, Grob *right_col);
+ static vector<Item*> right_note_columns (Grob *me);
+ static vector<Item*> left_note_columns (Grob *me);
+ static Item* right_column (Grob *me);
+ static Item* left_column (Grob *me);
+ static Drul_array<Skyline> skylines (Grob *me, Grob *right_col);
+ static Grob* extremal_break_aligned_grob (Grob *me, Direction, Direction, Interval*);
+
DECLARE_GROB_INTERFACE();
};
+#endif /* SPACING_INTERFACE_HH */
Spacing_options();
void init_from_grob (Grob *me);
- Real get_duration_space (Rational d, bool *) const;
+ Real get_duration_space (Rational d) const;
};
#endif /* SPACING_OPTIONS_HH */
#include "rational.hh"
#include "std-vector.hh"
#include "grob-interface.hh"
+#include "spring.hh"
class Spacing_spanner
{
Paper_column *nextr,
Spacing_options const *options);
static Real default_bar_spacing (Grob *, Grob *, Grob *, Moment);
- static Real get_duration_space (Moment dur, Spacing_options const *, bool *);
static Rational effective_shortest_duration (Grob *me, vector<Grob*> const &all);
static void breakable_column_spacing (Grob *, Item *l, Item *r, Spacing_options const *);
static void prune_loose_columns (Grob *, vector<Grob*> *cols, Spacing_options *);
static bool fills_measure (Grob *, Item *, Item *);
public:
static vector<Grob*> get_columns (Grob *me);
- static Real note_spacing (Grob *, Grob *, Grob *, Spacing_options const *, bool *);
- static void standard_breakable_column_spacing (Grob *me, Item *l, Item *r,
- Real *fixed, Real *space,
- Spacing_options const *);
+ static Real note_spacing (Grob *, Grob *, Grob *, Spacing_options const *);
+ static Spring standard_breakable_column_spacing (Grob *me, Item *l, Item *r, Spacing_options const *);
DECLARE_SCHEME_CALLBACK (set_springs, (SCM));
DECLARE_SCHEME_CALLBACK (calc_common_shortest_duration, (SCM));
/*
- spring.hh -- declare Spring, Column_spring
+ spring.hh -- declare Spring
source file of the GNU LilyPond music typesetter
#include "lily-proto.hh"
#include "smobs.hh"
-struct Spring_smob
+class Spring
{
- Grob *other_;
Real distance_;
- bool expand_only_b_;
- Real inverse_strength_;
+ Real min_distance_;
- DECLARE_SIMPLE_SMOBS (Spring_smob);
-public:
- Spring_smob ();
-};
-DECLARE_UNSMOB (Spring_smob, spring);
+ Real inverse_stretch_strength_;
+ Real inverse_compress_strength_;
-struct Spring
-{
- Drul_array<Item *> item_drul_;
- Real distance_;
- bool expand_only_b_;
-
- /*
- TODO: make 2 strengths: one for stretching, and one for shrinking.
- */
- Real inverse_strength_;
- void add_to_cols ();
- void set_to_cols ();
+ Real blocking_force_;
+
+ void update_blocking_force ();
+
+ DECLARE_SIMPLE_SMOBS (Spring);
+public:
Spring ();
+ Spring (Real distance, Real min_distance);
+
+ Real distance () const {return distance_;}
+ Real min_distance () const {return min_distance_;}
+ Real inverse_stretch_strength () const {return inverse_stretch_strength_;}
+ Real inverse_compress_strength () const {return inverse_compress_strength_;}
+ Real blocking_force () const {return blocking_force_;}
+
+ Real length (Real f) const;
+
+ void set_distance (Real);
+ void set_min_distance (Real);
+ void set_inverse_stretch_strength (Real);
+ void set_inverse_compress_strength (Real);
+ void set_blocking_force (Real);
+ void set_default_strength ();
+
+ void operator*= (Real);
+ bool operator> (Spring const&) const;
};
+DECLARE_UNSMOB (Spring, spring);
+
+Spring merge_springs (vector<Spring> const &springs);
#endif /* SPRING_HH */
#include "lily-proto.hh"
#include "grob-interface.hh"
+#include "spring.hh"
class Staff_spacing
{
+ static Real optical_correction (Grob *, Grob *, Interval);
+ static Real next_notes_correction (Grob *, Grob *);
+
public:
- static void next_notes_correction (Grob *, Grob *, Real, Real, Real *, Real *);
- static void next_note_correction (Grob *, Grob *, Interval, Real, Real, Real*, Real *, int *);
DECLARE_GROB_INTERFACE();
- static void get_spacing_params (Grob *, Real *, Real *);
-
+ static Spring get_spacing (Grob *, Grob *right_col);
static Interval bar_y_positions (Grob *);
};
Multi_measure_rest_engraver::stop_translation_timestep ()
{
/* We cannot do this earlier, as breakableSeparationItem is not yet
- there. */
+ there.
+
+ Actually, we no longer use breakableSeparationItem -- should this be moved?
+ -- jneem */
if (bar_seen_)
{
- Grob *cmc = unsmob_grob (get_property ("breakableSeparationItem"));
- if (!cmc)
- cmc = unsmob_grob (get_property ("currentCommandColumn"));
+ Grob *cmc = unsmob_grob (get_property ("currentCommandColumn"));
/* Ugh, this is a kludge - need this for multi-measure-rest-grace.ly */
last_command_item_ = dynamic_cast<Item *> (cmc);
{
Item *b = sp->get_bound (d);
- Interval coldim = (Separation_item::has_interface (b))
- ? Separation_item::relative_width (b, common)
- : b->extent (common, X_AXIS);
+ Interval coldim = b->extent (common, X_AXIS);
sp_iv[d] = coldim.is_empty () ? b->relative_coordinate (common, X_AXIS) : coldim[-d];
}
*/
SCM
Note_collision_interface::automatic_shift (Grob *me,
- Drul_array < vector<Grob*>
- > clash_groups)
+ Drul_array<vector<Grob*> > clash_groups)
{
Drul_array < vector<int> > shifts;
SCM tups = SCM_EOL;
}
}
-void
-Note_column::set_dotcol (Grob *me, Grob *d)
-{
- Axis_group_interface::add_element (me, d);
-}
-
Grob *
Note_column::first_head (Grob *me)
{
{
if (last_spacing_
&& last_spacing_parent_context_
- && last_spacing_parent_context_ == context ()->get_parent_context ())
+ && last_spacing_parent_context_ == context ()->get_parent_context ()
+ && to_boolean (get_property ("hasStaffSpacing")))
{
- Grob *sep = unsmob_grob (get_property ("breakableSeparationItem"));
- if (sep)
- Pointer_group_interface::add_grob (last_spacing_,
- ly_symbol2scm ("right-items"),
- sep);
+ Grob *col = unsmob_grob (get_property ("currentCommandColumn"));
+ Pointer_group_interface::add_grob (last_spacing_,
+ ly_symbol2scm ("right-items"),
+ col);
}
if (spacing_)
#include "warn.hh"
#include "stem.hh"
#include "separation-item.hh"
+#include "spacing-interface.hh"
#include "staff-spacing.hh"
#include "accidental-placement.hh"
#include "output-def.hh"
spacing?
*/
-void
+Spring
Note_spacing::get_spacing (Grob *me, Item *right_col,
- Real base_space, Real increment, Real *space, Real *fixed)
+ Real base_space, Real increment)
{
- Drul_array<SCM> props (me->get_object ("left-items"),
- me->get_object ("right-items"));
- Direction d = LEFT;
- Direction col_dir = right_col->break_status_dir ();
- Drul_array<Interval> extents;
+ vector<Item*> note_columns = Spacing_interface::left_note_columns (me);
+ Real left_head_end = 0;
- Interval left_head_wid;
- do
+ for (vsize i = 0; i < note_columns.size (); i++)
{
- vector<Grob*> const &items (ly_scm2link_array (props [d]));
- for (vsize i = items.size (); i--;)
- {
- Item *it = dynamic_cast<Item *> (items[i]);
-
- if (d == RIGHT && it->break_status_dir () != col_dir)
- it = it->find_prebroken_piece (col_dir);
-
- /*
- some kind of mismatch, eg. a note column, that is behind a
- linebreak.
- */
- if (!it)
- continue;
-
- Item *it_col = it->get_column ();
- if (d == RIGHT && right_col != it_col)
- continue;
-
- if (Separation_item::has_interface (it))
- {
- extents[d].unite (Separation_item::width (it));
- continue;
- }
-
- if (d == LEFT
- && Note_column::has_interface (it))
- {
- SCM r = it->get_object ("rest");
- Grob *g = unsmob_grob (r);
- if (!g)
- g = Note_column::first_head (it);
-
- /*
- Ugh. If Stem is switched off, we don't know what the
- first note head will be.
- */
- if (g)
- {
- if (g->common_refpoint (it_col, X_AXIS) != it_col)
- programming_error ("Note_spacing::get_spacing (): Common refpoint incorrect");
- else
- left_head_wid = g->extent (it_col, X_AXIS);
- }
- }
-
- extents[d].unite (it->extent (it_col, X_AXIS));
- if (d == RIGHT)
- {
- Grob *accs = Note_column::accidentals (it);
- if (!accs)
- accs = Note_column::accidentals (it->get_parent (X_AXIS));
-
- if (accs)
- {
- Interval v
- = Accidental_placement::get_relevant_accidental_extent (accs, it_col, me);
-
- extents[d].unite (v);
- }
-
- if (Grob *arpeggio = Note_column::arpeggio (it))
- extents[d].unite (arpeggio->extent (it_col, X_AXIS));
- }
- }
-
- if (extents[d].is_empty ())
- extents[d] = Interval (0, 0);
+ SCM r = note_columns[i]->get_object ("rest");
+ Grob *g = unsmob_grob (r);
+ Grob *col = note_columns[i]->get_column ();
+
+ if (!g)
+ g = Note_column::first_head (note_columns[i]);
+
+ /*
+ Ugh. If Stem is switched off, we don't know what the
+ first note head will be.
+ */
+ if (g)
+ {
+ if (g->common_refpoint (col, X_AXIS) != col)
+ programming_error ("Note_spacing::get_spacing (): Common refpoint incorrect");
+ else
+ left_head_end = g->extent (col, X_AXIS)[RIGHT];
+ }
}
- while (flip (&d) != LEFT);
/*
- We look at the width of the note head, since smaller heads get less space
+ The main factor that determines the amount of space is the width of the
+ note head (or the rest). For example, a quarter rest gets almost 0.5 ss
+ less horizontal space than a note.
- eg. a quarter rest gets almost 0.5 ss less horizontal space than a note.
+ The other parts of a note column (eg. flags, accidentals, etc.) don't get
+ the full amount of space. We give them half the amount of space, but then
+ adjust things so there are no collisions.
+ */
+ Drul_array<Skyline> skys = Spacing_interface::skylines (me, right_col);
+ Real min_dist = max (0.0, skys[LEFT].distance (skys[RIGHT]));
+ Real min_desired_space = left_head_end + (min_dist - left_head_end) / 2;
- What is sticking out of the note head (eg. a flag), doesn't get
- the full amount of space.
+ /* if the right object sticks out a lot, include a bit of extra space.
+ But only for non-musical-columns; this shouldn't apply to accidentals */
+ if (!Paper_column::is_musical (right_col))
+ min_desired_space = max (min_desired_space,
+ left_head_end + LEFT * skys[RIGHT].max_height ());
- FIXED also includes the left part of the right object.
- */
- *fixed
- = (left_head_wid.is_empty () ? increment
- : /*
- Size of the head:
- */
- (left_head_wid[RIGHT]+
-
- /*
- What's sticking out of the head, eg. a flag:
- */
- (extents[LEFT][RIGHT] - left_head_wid[RIGHT]) / 2))
-
- /*
- What is sticking out on the left side of the right note:
- */
- + (extents[RIGHT].is_empty ()
- ? 0.0
- : ((- extents[RIGHT][LEFT] / 2)
+ Real ideal = base_space - increment + min_desired_space;
- /*
- Add that which sticks out a lot.
- */
- + max (0.0, -extents[RIGHT][LEFT] - (base_space - 0.5 * increment))));
+ stem_dir_correction (me, right_col, increment, &ideal, &min_desired_space);
- /*
- We don't do complicated stuff: (base_space - increment) is the
- normal amount of white, which also determines the amount of
- stretch. Upon (extreme) stretching, notes with accidentals should
- stretch as much as notes without accidentals.
- */
- *space = (base_space - increment) + *fixed;
+ Spring ret (ideal, min_dist);
+ ret.set_inverse_compress_strength (max (0.0, ideal - max (min_dist, min_desired_space)));
+ ret.set_inverse_stretch_strength (max (0.1, base_space - increment));
+ return ret;
+}
-#if 0
- /*
- The below situation is now handled by the "sticks out a lot" case
- above. However we keep around the code for a few releases before
- we drop it.
- */
- if (!extents[RIGHT].is_empty ()
- && (Paper_column::is_breakable (right_col)))
- {
- /*
- This is for the situation
+static Real
+knee_correction (Grob *note_spacing, Grob *right_stem, Real increment)
+{
+ Real note_head_width = increment;
+ Grob *head = right_stem ? Stem::support_head (right_stem) : 0;
+ Grob *rcolumn = dynamic_cast<Item*> (head)->get_column ();
- rest | 3/4 (eol)
+ Interval head_extent;
+ if (head)
+ {
+ head_extent = head->extent (rcolumn, X_AXIS);
- Since we only take half of the right-object space above, the
- barline will bump into the notes preceding it, if the right
- thing is big. We add the rest of the extents here:
- */
+ if (!head_extent.is_empty ())
+ note_head_width = head_extent[RIGHT];
- *space += -extents[RIGHT][LEFT] / 2;
- *fixed += -extents[RIGHT][LEFT] / 2;
+ note_head_width -= Stem::thickness (right_stem);
}
-#endif
-
- stem_dir_correction (me, right_col, increment, space, fixed);
-}
-
-Item *
-Note_spacing::left_column (Grob *me)
-{
- if (!me->is_live ())
- return 0;
- return dynamic_cast<Item *> (me)->get_column ();
+ return -note_head_width * get_grob_direction (right_stem)
+ * robust_scm2double (note_spacing->get_property ("knee-spacing-correction"), 0);
}
-/*
- Compute the column of the right-items. This is a big function,
- since RIGHT-ITEMS may span more columns (eg. if a clef if inserted,
- this will add a new columns to RIGHT-ITEMS. Here we look at the
- columns, and return the left-most. If there are multiple columns, we
- prune RIGHT-ITEMS.
-*/
-Item *
-Note_spacing::right_column (Grob *me)
+static Real
+different_directions_correction (Grob *note_spacing,
+ Drul_array<Interval> stem_posns,
+ Direction left_stem_dir)
{
- if (!me->is_live ())
- return 0;
+ Real ret = 0.0;
+ Interval intersect = stem_posns[LEFT];
+ intersect.intersect (stem_posns[RIGHT]);
- Grob_array *a = unsmob_grob_array (me->get_object ("right-items"));
- Item *mincol = 0;
- int min_rank = INT_MAX;
- bool prune = false;
- for (vsize i = 0; a && i < a->size (); i++)
+ if (!intersect.is_empty ())
{
- Item *ri = a->item (i);
- Item *col = ri->get_column ();
+ ret = abs (intersect.length ());
- int rank = Paper_column::get_rank (col);
-
- if (rank < min_rank)
- {
- min_rank = rank;
- if (mincol)
- prune = true;
-
- mincol = col;
- }
+ /*
+ Ugh. 7 is hardcoded.
+ */
+ ret = min (ret / 7, 1.0)
+ * left_stem_dir
+ * robust_scm2double (note_spacing->get_property ("stem-spacing-correction"), 0);
}
+ return ret;
+}
- if (prune && a)
- {
- vector<Grob*> &right = a->array_reference ();
- for (vsize i = right.size (); i--;)
- {
- if (dynamic_cast<Item *> (right[i])->get_column () != mincol)
- right.erase (right.begin () + i);
- }
- }
+static Real
+same_direction_correction (Grob *note_spacing, Drul_array<Interval> head_posns)
+{
+ /*
+ Correct for the following situation:
+
+ X X
+ | |
+ | |
+ | X |
+ | | |
+ ========
+
+ ^ move the center one to the left.
+
+
+ this effect seems to be much more subtle than the
+ stem-direction stuff (why?), and also does not scale with the
+ difference in stem length.
+
+ */
- if (!mincol)
+ Interval hp = head_posns[LEFT];
+ hp.intersect (head_posns[RIGHT]);
+ if (!hp.is_empty ())
return 0;
-
- return mincol;
+
+ Direction lowest
+ = (head_posns[LEFT][DOWN] > head_posns[RIGHT][UP]) ? RIGHT : LEFT;
+
+ Real delta = head_posns[-lowest][DOWN] - head_posns[lowest][UP];
+ Real corr = robust_scm2double (note_spacing->get_property ("same-direction-correction"), 0);
+
+ return (delta > 1) ? -lowest * corr : 0;
}
+
/**
Correct for optical illusions. See [Wanske] p. 138. The combination
up-stem + down-stem should get extra space, the combination
down-stem + up-stem less.
- TODO: have to check wether the stems are in the same staff.
+ TODO: have to check whether the stems are in the same staff.
*/
void
Note_spacing::stem_dir_correction (Grob *me, Item *rcolumn,
Interval bar_xextent;
Interval bar_yextent;
- bool correct_stem_dirs = true;
Direction d = LEFT;
- bool acc_right = false;
+
+ Grob *bar = Spacing_interface::extremal_break_aligned_grob (me, RIGHT,
+ rcolumn->break_status_dir (),
+ &bar_xextent);
+ if (bar && dynamic_cast<Item*> (bar)->get_column () == rcolumn)
+ bar_yextent = Staff_spacing::bar_y_positions (bar);
do
{
{
Item *it = dynamic_cast<Item *> (items[i]);
- if (d == RIGHT)
- acc_right = acc_right || Note_column::accidentals (it);
+ /*
+ don't correct if accidentals are sticking out of the right side.
+ */
+ if (d == RIGHT && Note_column::accidentals (it))
+ return;
Grob *stem = Note_column::get_stem (it);
- if (!stem || !stem->is_live ())
- {
- if (d == RIGHT && Separation_item::has_interface (it))
- {
- if (it->get_column () != rcolumn)
- it = it->find_prebroken_piece (rcolumn->break_status_dir ());
-
- Grob *last = Separation_item::extremal_break_aligned_grob (it, LEFT, &bar_xextent);
-
- if (last)
- bar_yextent = Staff_spacing::bar_y_positions (last);
-
- break;
- }
-
- return;
- }
-
- if (Stem::is_invisible (stem))
- {
- correct_stem_dirs = false;
- continue;
- }
+ if (!stem || !stem->is_live () || Stem::is_invisible (stem))
+ return;
stems_drul[d] = stem;
beams_drul[d] = Stem::get_beam (stem);
Direction stem_dir = get_grob_direction (stem);
if (stem_dirs[d] && stem_dirs[d] != stem_dir)
- {
- correct_stem_dirs = false;
- continue;
- }
+ return;
+
stem_dirs[d] = stem_dir;
/*
*/
if (d == LEFT
&& Stem::duration_log (stem) > 2 && !Stem::get_beam (stem))
- correct_stem_dirs = false;
+ return;
Interval hp = Stem::head_positions (stem);
- if (correct_stem_dirs
- && !hp.is_empty ())
+ if (!hp.is_empty ())
{
Real chord_start = hp[stem_dir];
}
while (flip (&d) != LEFT);
- /*
- don't correct if accidentals are sticking out of the right side.
- */
- if (acc_right)
- return;
-
Real correction = 0.0;
if (!bar_yextent.is_empty ())
stem_posns[RIGHT] *= 2;
}
- if (correct_stem_dirs && stem_dirs[LEFT] * stem_dirs[RIGHT] == -1)
+ if (stem_dirs[LEFT] * stem_dirs[RIGHT] == -1)
{
if (beams_drul[LEFT] && beams_drul[LEFT] == beams_drul[RIGHT])
{
-
- /*
- this is a knee: maximal correction.
- */
- Real note_head_width = increment;
- Grob *st = stems_drul[RIGHT];
- Grob *head = st ? Stem::support_head (st) : 0;
-
- Interval head_extent;
- if (head)
- {
- head_extent = head->extent (rcolumn, X_AXIS);
-
- if (!head_extent.is_empty ())
- note_head_width = head_extent[RIGHT];
-
- if (st)
- {
- Real thick = Stem::thickness (st);
-
- note_head_width -= thick;
- }
- }
-
- correction = note_head_width * stem_dirs[LEFT];
- correction *= robust_scm2double (me->get_property ("knee-spacing-correction"), 0);
+ correction = knee_correction (me, stems_drul[RIGHT], increment);
*fixed += correction;
}
else
{
- intersect = stem_posns[LEFT];
- intersect.intersect (stem_posns[RIGHT]);
- correct_stem_dirs = correct_stem_dirs && !intersect.is_empty ();
-
- if (correct_stem_dirs)
- {
- correction = abs (intersect.length ());
-
- /*
- Ugh. 7 is hardcoded.
- */
- correction = min (correction / 7, 1.0);
- correction *= stem_dirs[LEFT];
- correction
- *= robust_scm2double (me->get_property ("stem-spacing-correction"), 0);
- }
+ correction = different_directions_correction (me, stem_posns, stem_dirs[LEFT]);
if (!bar_yextent.is_empty ())
correction *= 0.5;
}
}
- else if (correct_stem_dirs && stem_dirs[LEFT] * stem_dirs[RIGHT] == UP)
- {
- /*
- Correct for the following situation:
-
- X X
- | |
- | |
- | X |
- | | |
- ========
-
- ^ move the center one to the left.
-
-
- this effect seems to be much more subtle than the
- stem-direction stuff (why?), and also does not scale with the
- difference in stem length.
-
- */
-
- Interval hp = head_posns[LEFT];
- hp.intersect (head_posns[RIGHT]);
- if (!hp.is_empty ())
- return;
-
- Direction lowest
- = (head_posns[LEFT][DOWN] > head_posns[RIGHT][UP]) ? RIGHT : LEFT;
-
- Real delta = head_posns[-lowest][DOWN] - head_posns[lowest][UP];
- Real corr = robust_scm2double (me->get_property ("same-direction-correction"), 0);
-
- if (delta > 1)
- correction = -lowest * corr;
- }
+ else if (stem_dirs[LEFT] * stem_dirs[RIGHT] == 1)
+ correction = same_direction_correction (me, head_posns);
*space += correction;
#include "paper-column-engraver.hh"
#include "system.hh"
#include "international.hh"
+#include "accidental-placement.hh"
#include "axis-group-interface.hh"
#include "context.hh"
#include "note-spacing.hh"
#include "paper-column.hh"
#include "pointer-group-interface.hh"
+#include "separation-item.hh"
#include "staff-spacing.hh"
#include "system.hh"
#include "warn.hh"
for (vsize i = 0; i < items_.size (); i++)
{
Item *elem = items_[i];
+ Grob *col = Item::is_non_musical (elem) ? command_column_ : musical_column_;
+
if (!elem->get_parent (X_AXIS)
|| !unsmob_grob (elem->get_object ("axis-group-parent-X")))
{
- bool br = Item::is_non_musical (elem);
- Axis_group_interface::add_element (br ? command_column_ : musical_column_, elem);
+ Axis_group_interface::add_element (col, elem);
}
+ else if (Accidental_placement::has_interface (elem))
+ Separation_item::add_conditional_item (col, elem);
+ else
+ Separation_item::add_item (col, elem);
}
items_.clear ();
#include "system.hh"
#include "spring.hh"
#include "lookup.hh"
+#include "separation-item.hh"
#include "string-convert.hh"
Grob *
return scm_is_symbol (me->get_property ("line-break-permission"));
}
+Real
+Paper_column::minimum_distance (Grob *left, Grob *right)
+{
+ Drul_array<Grob*> cols (left, right);
+ Drul_array<Skyline> skys = Drul_array<Skyline> (Skyline (RIGHT), Skyline (LEFT));
+
+ Direction d = LEFT;
+ do
+ {
+ Skyline_pair *sp = Skyline_pair::unsmob (cols[d]->get_property ("horizontal-skylines"));
+ if (sp)
+ skys[d] = (*sp)[-d];
+ }
+ while (flip (&d) != LEFT);
+
+ return max (0.0, skys[LEFT].distance (skys[RIGHT]));
+}
+
/*
Print a vertical line and the rank number, to aid debugging.
*/
for (SCM s = me->get_object ("ideal-distances");
scm_is_pair (s); s = scm_cdr (s))
{
- Spring_smob *sp = unsmob_spring (scm_car (s));
- if (!sp->other_->get_system ())
+ Spring *sp = unsmob_spring (scm_caar (s));
+ if (!unsmob_grob (scm_cdar (s))
+ || !unsmob_grob (scm_cdar (s))->get_system ())
continue;
j++;
vector<Offset> pts;
pts.push_back (Offset (0, y));
- Offset p2 (sp->distance_, y);
+ Offset p2 (sp->distance (), y);
pts.push_back (p2);
Stencil id_stencil = Lookup::points_to_line_stencil (0.1, pts);
SCM distance_stc = Text_interface::interpret_markup (me->layout ()->self_scm (),
small_letters,
- ly_string2scm (String_convert::form_string ("%5.2lf", sp->distance_)));
+ ly_string2scm (String_convert::form_string ("%5.2lf", sp->distance ())));
- id_stencil.add_stencil (unsmob_stencil (distance_stc)->translated (Offset (sp->distance_/3, y+1)));
+ id_stencil.add_stencil (unsmob_stencil (distance_stc)->translated (Offset (sp->distance ()/3, y+1)));
id_stencil.add_stencil (head.translated (p2));
id_stencil = id_stencil.in_color (0,0,1);
l.add_stencil (id_stencil);
Grob *stem_;
Grob *note_column_;
Grob *dotcol_;
+ Grob *arpeggio_;
TRANSLATOR_DECLARATIONS (Rhythmic_column_engraver);
protected:
- DECLARE_ACKNOWLEDGER (dot_column);
DECLARE_ACKNOWLEDGER (stem);
DECLARE_ACKNOWLEDGER (rhythmic_head);
+ DECLARE_ACKNOWLEDGER (arpeggio);
void process_acknowledged ();
void stop_translation_timestep ();
};
stem_ = 0;
note_column_ = 0;
- dotcol_ = 0;
+ arpeggio_ = 0;
}
if (rheads_.size ())
{
if (!note_column_)
- {
- note_column_ = make_item ("NoteColumn", rheads_[0]->self_scm ());
- }
+ note_column_ = make_item ("NoteColumn", rheads_[0]->self_scm ());
for (vsize i = 0; i < rheads_.size (); i++)
- {
- if (!rheads_[i]->get_parent (X_AXIS))
- Note_column::add_head (note_column_, rheads_[i]);
- }
+ if (!rheads_[i]->get_parent (X_AXIS))
+ Note_column::add_head (note_column_, rheads_[i]);
+
rheads_.resize (0);
}
if (note_column_)
{
- if (dotcol_
- && !dotcol_->get_parent (X_AXIS))
- Note_column::set_dotcol (note_column_, dotcol_);
-
if (stem_
&& !stem_->get_parent (X_AXIS))
{
Note_column::set_stem (note_column_, stem_);
stem_ = 0;
}
+
+ if (arpeggio_)
+ {
+ Pointer_group_interface::add_grob (note_column_, ly_symbol2scm ("elements"), arpeggio_);
+ note_column_->set_object ("arpeggio", arpeggio_->self_scm ());
+ }
}
}
}
void
-Rhythmic_column_engraver::acknowledge_dot_column (Grob_info i)
+Rhythmic_column_engraver::acknowledge_arpeggio (Grob_info i)
{
- dotcol_ = i.grob ();
+ arpeggio_ = i.grob ();
}
void
Rhythmic_column_engraver::stop_translation_timestep ()
{
note_column_ = 0;
- dotcol_ = 0;
stem_ = 0;
+ arpeggio_ = 0;
}
-ADD_ACKNOWLEDGER (Rhythmic_column_engraver, dot_column);
ADD_ACKNOWLEDGER (Rhythmic_column_engraver, stem);
ADD_ACKNOWLEDGER (Rhythmic_column_engraver, rhythmic_head);
+ADD_ACKNOWLEDGER (Rhythmic_column_engraver, arpeggio);
ADD_TRANSLATOR (Rhythmic_column_engraver,
/* doc */ "Generates NoteColumn, an objects that groups stems, noteheads and rests.",
+++ /dev/null
-/*
- separating-group-spanner.cc -- implement Separating_group_spanner
-
- source file of the GNU LilyPond music typesetter
-
- (c) 1998--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
-*/
-
-#include "separating-group-spanner.hh"
-
-#include "separation-item.hh"
-#include "paper-column.hh"
-#include "output-def.hh"
-#include "dimensions.hh"
-#include "pointer-group-interface.hh"
-#include "moment.hh"
-
-void
-Separating_group_spanner::find_rods (Item *r,
- vector<Grob*> const &separators,
- vsize idx,
- Real padding)
-{
-
- /*
- This is an inner loop: look for the first normal (unbroken) Left
- grob. This looks like an inner loop (ie. quadratic total), but in
- most cases, the interesting L will just be the first entry of
- NEXT, making it linear in most of the cases.
- */
- for (; idx != VPOS; idx--)
- {
- Item *l = dynamic_cast<Item *> (separators[idx]);
- Item *lb = l->find_prebroken_piece (RIGHT);
-
- if (lb)
- {
- Separation_item::set_distance (Drul_array<Item*> (lb, r), padding);
- }
-
- if (Separation_item::set_distance (Drul_array<Item *> (l, r), padding)
- /*
- This check is because grace notes are set very tight, and
- the accidentals of main note may stick out so far to cover
- a barline preceding the grace note.
- */
- && spanned_time_interval (l, r).length ().main_part_ > Rational (0))
- break;
-
- /*
- this grob doesn't cause a constraint. We look further until we
- find one that does.
- */
- }
-}
-
-MAKE_SCHEME_CALLBACK (Separating_group_spanner, set_spacing_rods, 1);
-SCM
-Separating_group_spanner::set_spacing_rods (SCM smob)
-{
- Grob *me = unsmob_grob (smob);
-
- /*
- Ugh: padding is added doubly, also for SeparationItem
- */
- Real padding = robust_scm2double (me->get_property ("padding"), 0.1);
-
- extract_grob_set (me, "elements", elts);
- for (vsize i = elts.size (); i-- > 1;)
- {
- Item *r = dynamic_cast<Item *> (elts[i]);
- if (!r)
- continue;
-
- if (Separation_item::width (r).is_empty ())
- continue;
-
- Item *rb
- = dynamic_cast<Item *> (r->find_prebroken_piece (LEFT));
-
- find_rods (r, elts, i - 1, padding);
- if (rb)
- find_rods (rb, elts, i - 1, padding);
- }
-
- return SCM_UNSPECIFIED;
-}
-
-void
-Separating_group_spanner::add_spacing_unit (Grob *me, Item *i)
-{
- Pointer_group_interface::add_unordered_grob (me, ly_symbol2scm ("elements"), i);
-}
-
-ADD_INTERFACE (Separating_group_spanner,
- "A spanner that calculates spacing constraints (\"rods\") "
- "using the @code{separation-item-interface} grobs in @code{elements}.",
-
- /* properties */
- "elements "
- "padding ");
#include "engraver.hh"
-#include "separating-group-spanner.hh"
#include "separation-item.hh"
#include "paper-column.hh"
#include "output-def.hh"
class Separating_line_group_engraver : public Engraver
{
protected:
- Item *break_item_;
- Item *musical_item_;
- Item *last_musical_item_;
-
Spacings current_spacings_;
Spacings last_spacings_;
- Spanner *sep_span_;
-
DECLARE_ACKNOWLEDGER (item);
- void process_music ();
- virtual void finalize ();
+ DECLARE_ACKNOWLEDGER (break_aligned);
void stop_translation_timestep ();
void start_translation_timestep ();
+
+ vector<Grob*> break_aligned_;
public:
TRANSLATOR_DECLARATIONS (Separating_line_group_engraver);
};
Separating_line_group_engraver::Separating_line_group_engraver ()
{
- sep_span_ = 0;
- break_item_ = 0;
- musical_item_ = 0;
-}
-
-void
-Separating_line_group_engraver::process_music ()
-{
- if (!sep_span_)
- {
- sep_span_ = make_spanner ("SeparatingGroupSpanner", SCM_EOL);
-
- sep_span_->set_bound (LEFT, unsmob_grob (get_property ("currentCommandColumn")));
- }
-}
-void
-Separating_line_group_engraver::finalize ()
-{
- if (!sep_span_)
- return;
-
- SCM ccol = get_property ("currentCommandColumn");
- Grob *column = unsmob_grob (ccol);
-
- sep_span_->set_bound (RIGHT, unsmob_grob (ccol));
- sep_span_ = 0;
-
- if (last_spacings_.staff_spacing_
- && last_spacings_.staff_spacing_->get_column () == column)
- last_spacings_.staff_spacing_->suicide ();
}
void
Separating_line_group_engraver::acknowledge_item (Grob_info i)
{
Item *it = i.item ();
- if (it->get_parent (X_AXIS)
- && it->get_parent (X_AXIS) == it->get_parent (Y_AXIS)
- && Axis_group_interface::has_axis (it->get_parent (X_AXIS), X_AXIS)
- && Axis_group_interface::has_axis (it->get_parent (Y_AXIS), Y_AXIS))
- return;
-
- if (to_boolean (it->get_property ("no-spacing-rods")))
- return;
if (Note_spacing::has_interface (it))
{
return;
}
- bool ib = Item::is_non_musical (it);
- Item *&p_ref_ (ib ? break_item_
- : musical_item_);
-
- if (!p_ref_)
+ if (Item::is_non_musical (it)
+ && !current_spacings_.staff_spacing_
+ && to_boolean (get_property ("createSpacing")))
{
- p_ref_ = make_item ("SeparationItem", SCM_EOL);
+ Grob *col = unsmob_grob (get_property ("currentCommandColumn"));
- if (ib)
- {
- p_ref_->set_property ("non-musical", SCM_BOOL_T);
- context ()->set_property ("breakableSeparationItem", p_ref_->self_scm ());
- }
+ current_spacings_.staff_spacing_ = make_item ("StaffSpacing", SCM_EOL);
+ context ()->set_property ("hasStaffSpacing", SCM_BOOL_T);
- if (to_boolean (get_property ("createSpacing"))
- && p_ref_ == break_item_)
+ Pointer_group_interface::add_grob (current_spacings_.staff_spacing_,
+ ly_symbol2scm ("left-items"),
+ col);
+
+ if (!last_spacings_.note_spacings_.size ()
+ && last_spacings_.staff_spacing_)
{
- Item *it = make_item ("StaffSpacing", SCM_EOL);
- current_spacings_.staff_spacing_ = it;
- Pointer_group_interface::add_grob (it, ly_symbol2scm ("left-items"),
- break_item_);
-
- if (!last_spacings_.note_spacings_.size ()
- && last_spacings_.staff_spacing_)
+ SCM ri = last_spacings_.staff_spacing_->get_object ("right-items");
+ Grob_array *ga = unsmob_grob_array (ri);
+ if (!ga)
{
- SCM ri = last_spacings_.staff_spacing_->get_object ("right-items");
- Grob_array *ga = unsmob_grob_array (ri);
- if (!ga)
- {
- SCM ga_scm = Grob_array::make_array ();
- last_spacings_.staff_spacing_->set_object ("right-items", ga_scm);
- ga = unsmob_grob_array (ga_scm);
- }
-
- ga->clear ();
- ga->add (break_item_);
+ SCM ga_scm = Grob_array::make_array ();
+ last_spacings_.staff_spacing_->set_object ("right-items", ga_scm);
+ ga = unsmob_grob_array (ga_scm);
}
+
+ ga->clear ();
+ ga->add (col);
}
}
+}
- if (Accidental_placement::has_interface (it))
- Separation_item::add_conditional_item (p_ref_, it);
- else
- Separation_item::add_item (p_ref_, it);
+void
+Separating_line_group_engraver::acknowledge_break_aligned (Grob_info gi)
+{
+ break_aligned_.push_back (gi.grob ());
}
void
Separating_line_group_engraver::start_translation_timestep ()
{
- if (break_item_)
- {
- context ()->unset_property (ly_symbol2scm ("breakableSeparationItem"));
- break_item_ = 0;
- }
+ context ()->unset_property (ly_symbol2scm ("hasStaffSpacing"));
}
void
Separating_line_group_engraver::stop_translation_timestep ()
{
- if (break_item_)
- Separating_group_spanner::add_spacing_unit (sep_span_, break_item_);
-
- if (Item *sp = current_spacings_.staff_spacing_)
+ for (vsize i = 0; i < break_aligned_.size (); i++)
{
- /*
- TODO: should really look at the left-items of following
- note-spacing grobs.
- */
- if (musical_item_)
- Pointer_group_interface::add_grob (sp, ly_symbol2scm ("right-items"),
- musical_item_);
+ SCM smob = break_aligned_[i]->self_scm ();
+
+ if (Item *sp = current_spacings_.staff_spacing_)
+ Pointer_group_interface::add_grob (sp, ly_symbol2scm ("left-break-aligned"), smob);
+
+ for (vsize j = 0; j < last_spacings_.note_spacings_.size (); j++)
+ Pointer_group_interface::add_grob (last_spacings_.note_spacings_[j],
+ ly_symbol2scm ("right-break-aligned"), smob);
}
if (!current_spacings_.is_empty ())
last_spacings_ = current_spacings_;
- current_spacings_.clear ();
-
- if (musical_item_)
- Separating_group_spanner::add_spacing_unit (sep_span_, musical_item_);
+ if (Item *sp = current_spacings_.staff_spacing_)
+ if (Grob *col = unsmob_grob (get_property ("currentMusicalColumn")))
+ Pointer_group_interface::add_grob (sp, ly_symbol2scm ("right-items"), col);
- musical_item_ = 0;
+ current_spacings_.clear ();
+ break_aligned_.clear ();
}
ADD_ACKNOWLEDGER (Separating_line_group_engraver, item);
+ADD_ACKNOWLEDGER (Separating_line_group_engraver, break_aligned);
+
ADD_TRANSLATOR (Separating_line_group_engraver,
/* doc */ "Generates objects for computing spacing parameters.",
- /* create */
- "SeparationItem "
- "SeparatingGroupSpanner "
- "StaffSpacing",
+ /* create */ "StaffSpacing",
/* read */ "createSpacing",
- /* write */ "breakableSeparationItem");
+ /* write */ "hasStaffSpacing"
+ );
#include "separation-item.hh"
+#include "axis-group-interface.hh"
#include "lookup.hh"
#include "stencil.hh"
#include "skyline.hh"
}
void
-Separation_item::set_skyline_distance (Drul_array<Item *> items,
+Separation_item::set_distance (Drul_array<Item *> items,
Real padding)
{
Drul_array<Skyline_pair*> lines (Skyline_pair::unsmob (items[LEFT]->get_property ("horizontal-skylines")),
}
bool
-Separation_item::set_distance (Drul_array<Item *> items,
- Real padding)
+Separation_item::is_empty (Grob *me)
{
- set_skyline_distance (items, padding);
- return true;
+ Skyline_pair *sky = Skyline_pair::unsmob (me->get_property ("horizontal-skylines"));
+ return (!sky || sky->is_empty ());
}
/*
vector<Grob*> elts;
if (left)
- elts = Accidental_placement::get_break_reminder_accidentals (read_only_elts, left);
+ elts = Accidental_placement::get_relevant_accidentals (read_only_elts, left);
else
elts = read_only_elts;
{
Item *il = dynamic_cast<Item *> (elts[i]);
if (pc != il->get_column ())
- {
- continue;
- }
+ continue;
+ if (Axis_group_interface::has_interface (il))
+ continue;
Interval y (il->pure_height (ycommon, 0, very_large));
Interval x (il->extent (pc, X_AXIS));
Interval extra = robust_scm2interval (elts[i]->get_property ("extra-spacing-width"),
- Interval (0, 0));
+ Interval (-0.1, 0.1));
x[LEFT] += extra[LEFT];
x[RIGHT] += extra[RIGHT];
if (to_boolean (elts[i]->get_property ("infinite-spacing-height")))
y = Interval (-infinity_f, infinity_f);
+ if (!x.is_empty () && !y.is_empty ())
out.push_back (Box (x, y));
}
return out;
}
-Interval
-Separation_item::width (Grob *me)
-{
- SCM sw = me->get_property ("X-extent");
- return ly_scm2interval (sw);
-}
-
-Interval
-Separation_item::relative_width (Grob *me, Grob *common)
-{
- Interval iv = width (me);
-
- return dynamic_cast<Item *> (me)->get_column ()->relative_coordinate (common, X_AXIS) + iv;
-}
-
-/*
- Try to find the break-aligned symbol in SEPARATION_ITEM that is
- sticking out at direction D. The x size is put in LAST_EXT
-*/
-Grob *
-Separation_item::extremal_break_aligned_grob (Grob *me,
- Direction d,
- Interval *last_ext)
-{
- Grob *col = dynamic_cast<Item *> (me)->get_column ();
- last_ext->set_empty ();
- Grob *last_grob = 0;
-
- extract_grob_set (me, "elements", elts);
- for (vsize i = elts.size (); i--;)
- {
- Grob *break_item = elts[i];
- if (!scm_is_symbol (break_item->get_property ("break-align-symbol")))
- continue;
-
- if (!scm_is_pair (break_item->get_property ("space-alist")))
- continue;
-
- Interval ext = break_item->extent (col, X_AXIS);
-
- if (ext.is_empty ())
- continue;
-
- if (!last_grob
- || (last_grob && d * (ext[d]- (*last_ext)[d]) > 0))
- {
- *last_ext = ext;
- last_grob = break_item;
- }
- }
-
- return last_grob;
-}
-
extern bool debug_skylines;
MAKE_SCHEME_CALLBACK (Separation_item, print, 1)
SCM
ADD_INTERFACE (Separation_item,
"Item that computes widths to generate spacing rods. "
- "This is done in concert with @ref{separating-group-spanner-interface}.",
+ ,
"X-extent "
"conditional-elements "
Real ideal = scm_to_double (scm_caar (s));
Real inv_hooke = scm_to_double (scm_cadar (s));
- spacer.add_spring (ideal, inv_hooke);
+ Spring sp (ideal, 0.0);
+ sp.set_inverse_compress_strength (inv_hooke);
+ sp.set_inverse_stretch_strength (inv_hooke);
+
+ spacer.add_spring (sp);
}
for (SCM s = rods; scm_is_pair (s); s = scm_cdr (s))
Real
Simple_spacer::rod_force (int l, int r, Real dist)
{
- Real c = range_stiffness (l, r);
Real d = range_ideal_len (l, r);
+ Real c = range_stiffness (l, r, dist > d);
Real block_stretch = dist - d;
return c * block_stretch;
}
Real spring_dist = range_ideal_len (l, r);
if (spring_dist < dist)
for (int i = l; i < r; i++)
- springs_[i].ideal_ *= dist / spring_dist;
+ springs_[i].set_distance (springs_[i].distance () * dist / spring_dist);
return;
}
force_ = max (force_, block_force);
for (int i = l; i < r; i++)
- springs_[i].block_force_ = max (block_force, springs_[i].block_force_);
+ springs_[i].set_blocking_force (max (block_force, springs_[i].blocking_force ()));
}
Real
{
Real d = 0.;
for (int i = l; i < r; i++)
- d += springs_[i].ideal_;
+ d += springs_[i].distance ();
return d;
}
Real
-Simple_spacer::range_stiffness (int l, int r) const
+Simple_spacer::range_stiffness (int l, int r, bool stretch) const
{
Real den = 0.0;
for (int i = l; i < r; i++)
- den += springs_[i].inverse_hooke_;
+ den += stretch ? springs_[i].inverse_stretch_strength ()
+ : springs_[i].inverse_compress_strength ();
return 1 / den;
}
Simple_spacer::solve (Real line_len, bool ragged)
{
Real conf = configuration_length (force_);
- double inv_hooke = 0;
- for (vsize i=0; i < springs_.size (); i++)
- inv_hooke += springs_[i].inverse_hooke_;
ragged_ = ragged;
line_len_ = line_len;
- if ((inv_hooke > 0) && (conf < line_len_))
+ if (conf < line_len_)
force_ = expand_line ();
else if (conf > line_len_)
force_ = compress_line ();
fits_ = true;
for (vsize i=0; i < springs_.size (); i++)
- inv_hooke += springs_[i].inverse_hooke_;
+ inv_hooke += springs_[i].inverse_stretch_strength ();
assert (cur_len <= line_len_);
return (line_len_ - cur_len) / inv_hooke + force_;
double inv_hooke = 0;
double cur_len = configuration_length (force_);
double cur_force = force_;
+ bool compressed = false;
+
+ /* just because we are in compress_line () doesn't mean that the line
+ will actually be compressed (as in, a negative force) because
+ we start out with a stretched line. Here, we check whether we
+ will be compressed or stretched (so we know which spring constant to use) */
+ if (configuration_length (0.0) > line_len_)
+ {
+ cur_force = 0.0;
+ cur_len = configuration_length (0.0);
+ compressed = true;
+ }
fits_ = true;
for (vsize i=0; i < springs_.size (); i++)
- inv_hooke += springs_[i].inverse_hooke_;
+ inv_hooke += compressed
+ ? springs_[i].inverse_compress_strength ()
+ : springs_[i].inverse_stretch_strength ();
assert (line_len_ <= cur_len);
- vector<Spring_description> sorted_springs = springs_;
- sort (sorted_springs.begin (), sorted_springs.end (), greater<Spring_description> ());
+ vector<Spring> sorted_springs = springs_;
+ sort (sorted_springs.begin (), sorted_springs.end (), greater<Spring> ());
+
for (vsize i = 0; i < sorted_springs.size (); i++)
{
- Spring_description sp = sorted_springs[i];
+ Spring sp = sorted_springs[i];
- assert (sp.block_force_ <= cur_force);
- if (isinf (sp.block_force_))
+ assert (sp.blocking_force () <= cur_force);
+ if (isinf (sp.blocking_force ()))
break;
- double block_dist = (cur_force - sp.block_force_) * inv_hooke;
+ double block_dist = (cur_force - sp.blocking_force ()) * inv_hooke;
if (cur_len - block_dist < line_len_)
{
- cur_force += (line_len_ - cur_len) / inv_hooke;
- cur_len = line_len_;
+ cur_force += (line_len_ - cur_len) / inv_hooke;
+ cur_len = line_len_;
- /*
- Paranoia check.
+ /*
+ Paranoia check.
*/
- assert (fabs (configuration_length (cur_force) - cur_len) < 1e-6);
- return cur_force;
+ assert (fabs (configuration_length (cur_force) - cur_len) < 1e-6);
+ return cur_force;
}
cur_len -= block_dist;
- inv_hooke -= sp.inverse_hooke_;
- cur_force = sp.block_force_;
+ inv_hooke -= sp.inverse_compress_strength ();
+ cur_force = sp.blocking_force ();
}
fits_ = false;
}
void
-Simple_spacer::add_spring (Real ideal, Real inverse_hooke)
+Simple_spacer::add_spring (Spring const &sp)
{
- Spring_description description;
-
- description.ideal_ = ideal;
- description.inverse_hooke_ = inverse_hooke;
- if (!description.is_sane ())
- {
- programming_error ("insane spring found, setting to unit");
-
- description.inverse_hooke_ = 1.0;
- description.ideal_ = 1.0;
- }
-
- description.block_force_ = -description.ideal_ / description.inverse_hooke_;
- // block at distance 0
-
- springs_.push_back (description);
+ force_ = max (force_, sp.blocking_force ());
+ springs_.push_back (sp);
}
vector<Real>
/****************************************************************/
-Spring_description::Spring_description ()
-{
- ideal_ = 0.0;
- inverse_hooke_ = 0.0;
- block_force_ = 0.0;
-}
-
-bool
-Spring_description::is_sane () const
-{
- return (inverse_hooke_ >= 0)
- && ideal_ >= 0
- && !isinf (ideal_) && !isnan (ideal_)
- && (inverse_hooke_ == 0.0 || fabs (inverse_hooke_) > 1e-8)
- ;
-}
-
-Real
-Spring_description::length (Real f) const
-{
- return ideal_ + max (f, block_force_) * inverse_hooke_;
-}
-
-/****************************************************************/
-
-/*
- TODO: should a add penalty for widely varying spring forces (caused
- by constraints, eg.
-
-
- . =====
- . | |
- .o|o|x ##x
- .
-
- The ## forces the notes apart; we shouldn't allow the O's to touch
- this closely.
-*/
-
struct Rod_description
{
vsize r_;
{
vector<Rod_description> rods_;
vector<Rod_description> end_rods_; /* use these if they end at the last column of the line */
- Real ideal_;
- Real inverse_hooke_;
- Real end_ideal_;
- Real end_inverse_hooke_;
+ Spring spring_;
+ Spring end_spring_;
+
SCM break_permission_;
Interval keep_inside_line_;
Column_description ()
{
- ideal_ = 0;
- inverse_hooke_ = 0;
- end_ideal_ = 0;
- end_inverse_hooke_ = 0;
break_permission_ = SCM_EOL;
}
};
Column_description description;
Grob *next_col = next_spaceable_column (cols, col_index);
if (next_col)
- Spaceable_grob::get_spring (col, next_col, &description.ideal_, &description.inverse_hooke_);
+ description.spring_ = Spaceable_grob::get_spring (col, next_col);
+
Grob *end_col = dynamic_cast<Item*> (cols[col_index+1])->find_prebroken_piece (LEFT);
if (end_col)
- Spaceable_grob::get_spring (col, end_col, &description.end_ideal_, &description.end_inverse_hooke_);
+ description.end_spring_ = Spaceable_grob::get_spring (col, end_col);
for (SCM s = Spaceable_grob::get_minimum_distances (col);
scm_is_pair (s); s = scm_cdr (s))
Simple_spacer spacer;
for (vsize i = breaks[b]; i < end - 1; i++)
- spacer.add_spring (cols[i].ideal_, cols[i].inverse_hooke_);
- spacer.add_spring (cols[end-1].end_ideal_, cols[end-1].end_inverse_hooke_);
+ spacer.add_spring (cols[i].spring_);
+ spacer.add_spring (cols[end-1].end_spring_);
for (vsize i = breaks[b]; i < end; i++)
for (vsize i = 0; i + 1 < ret.cols_.size (); i++)
{
cols.push_back (get_column_description (ret.cols_, i, i == 0));
- spacer.add_spring (cols[i].ideal_, cols[i].inverse_hooke_);
+ spacer.add_spring (cols[i].spring_);
}
for (vsize i = 0; i < cols.size (); i++)
{
bool
Skyline::is_empty () const
{
- return buildings_.empty ();
+ Building b = buildings_.front ();
+ return b.end_ == infinity_f && b.y_intercept_ == -infinity_f;
}
Skyline_pair::Skyline_pair ()
void
Slur_engraver::stop_translation_timestep ()
{
- if (Grob *g = unsmob_grob (get_property ("breakableSeparationItem")))
+ if (Grob *g = unsmob_grob (get_property ("currentCommandColumn")))
{
for (vsize i = 0; i < end_slurs_.size (); i++)
Slur::add_extra_encompass (end_slurs_[i], g);
}
void
-Spaceable_grob::add_spring (Grob *me, Grob *other,
- Real distance, Real inverse_strength)
+Spaceable_grob::add_spring (Grob *me, Grob *other, Spring sp)
{
- if (distance < 0.0 || inverse_strength < 0.0)
- {
- programming_error ("adding reverse spring, setting to unit");
- distance = 1.0;
- inverse_strength = 1.0;
- }
-
- if (isinf (distance) || isnan (distance)
- || isnan (inverse_strength))
- {
- /* strength == INF is possible. It means fixed distance. */
- programming_error ("insane distance found");
- distance = 1.0;
- inverse_strength = 1.0;
- }
-
-#ifndef NDEBUG
- SCM mins = me->get_object ("ideal-distances");
- for (SCM s = mins; scm_is_pair (s); s = scm_cdr (s))
- {
- Spring_smob *sp = unsmob_spring (scm_car (s));
- if (sp->other_ == other)
- {
- programming_error ("already have that spring");
- return;
- }
- }
-#endif
-
- Spring_smob spring;
- spring.inverse_strength_ = inverse_strength;
- spring.distance_ = distance;
- spring.other_ = other;
-
SCM ideal = me->get_object ("ideal-distances");
- ideal = scm_cons (spring.smobbed_copy (), ideal);
+
+ ideal = scm_cons (scm_cons (sp.smobbed_copy (), other->self_scm ()), ideal);
me->set_object ("ideal-distances", ideal);
}
-void
-Spaceable_grob::get_spring (Grob *this_col, Grob *next_col, Real *dist, Real *inv_strength)
+Spring
+Spaceable_grob::get_spring (Grob *this_col, Grob *next_col)
{
- Spring_smob *spring = 0;
+ Spring *spring = 0;
for (SCM s = this_col->get_object ("ideal-distances");
!spring && scm_is_pair (s);
s = scm_cdr (s))
{
- Spring_smob *sp = unsmob_spring (scm_car (s));
-
- if (sp && sp->other_ == next_col)
- spring = sp;
+ if (scm_is_pair (scm_car (s))
+ && unsmob_grob (scm_cdar (s)) == next_col
+ && unsmob_spring (scm_caar (s)))
+ spring = unsmob_spring (scm_caar (s));
}
if (!spring)
programming_error (_f ("No spring between column %d and next one",
Paper_column::get_rank (this_col)));
- *dist = (spring) ? spring->distance_ : 5.0;
- *inv_strength = (spring) ? spring->inverse_strength_ : 1.0;
+ return spring ? *spring : Spring ();
}
#include "warn.hh"
#include "pointer-group-interface.hh"
#include "system.hh"
+#include "spacing-interface.hh"
+#include "spring.hh"
/*
LilyPond spaces by taking a simple-minded spacing algorithm, and
The one-size-fits all spacing. It doesn't take into account
different spacing wishes from one to the next column.
*/
-void
-Spacing_spanner::standard_breakable_column_spacing (Grob *me, Item *l, Item *r,
- Real *fixed, Real *space,
- Spacing_options const *options)
+Spring
+Spacing_spanner::standard_breakable_column_spacing (Grob *me, Item *l, Item *r, Spacing_options const *options)
{
- *fixed = 0.0;
- Direction d = LEFT;
- Drul_array<Item *> cols (l, r);
-
- do
- {
- /*
- TODO: this is fishy, the extent gets distorted due to wide
- \marks, so better not do this.
- */
- if (!Paper_column::is_musical (cols[d]))
- {
- /*
- Tied accidentals over barlines cause problems, so lets see
- what happens if we do this for non musical columns only.
- */
- Interval lext = cols[d]->extent (cols [d], X_AXIS);
- if (!lext.is_empty ())
- *fixed += -d * lext[-d];
- }
- }
- while (flip (&d) != LEFT);
+ Real min_dist = max (0.0, Paper_column::minimum_distance (l, r));
+ Real ideal;
if (Paper_column::is_breakable (l) && Paper_column::is_breakable (r))
{
Real incr = robust_scm2double (me->get_property ("spacing-increment"), 1);
- *space = *fixed + incr * double (mlen.main_part_ / options->global_shortest_) * 0.8;
+ ideal = min_dist + incr * double (mlen.main_part_ / options->global_shortest_) * 0.8;
}
else
{
In this case, Staff_spacing should handle the job,
using dt when it is 0 is silly.
*/
- *space = *fixed + 0.5;
+ ideal = min_dist + 0.5;
}
else
- {
- bool dummy;
- *space = *fixed + options->get_duration_space (dt.main_part_, &dummy);
- }
+ ideal = min_dist + options->get_duration_space (dt.main_part_);
}
+ return Spring (ideal, min_dist);
}
Moment *
Real
Spacing_spanner::note_spacing (Grob *me, Grob *lc, Grob *rc,
- Spacing_options const *options,
- bool *expand_only)
+ Spacing_options const *options)
{
(void) me;
Real dist = 0.0;
if (delta_t.main_part_ && !lwhen.grace_part_)
{
- dist = options->get_duration_space (shortest_playing_len.main_part_,
- expand_only);
+ dist = options->get_duration_space (shortest_playing_len.main_part_);
dist *= double (delta_t.main_part_ / shortest_playing_len.main_part_);
}
else if (delta_t.grace_part_)
available (namely the space for the global shortest note), and
multiply that by grace-space-factor
*/
- dist = options->get_duration_space (options->global_shortest_, expand_only) / 2.0;
+ dist = options->get_duration_space (options->global_shortest_) / 2.0;
Grob *grace_spacing = unsmob_grob (lc->get_object ("grace-spacing"));
if (grace_spacing)
{
Spacing_options grace_opts;
grace_opts.init_from_grob (grace_spacing);
- bool bla;
- dist = grace_opts.get_duration_space (delta_t.grace_part_, &bla);
+ dist = grace_opts.get_duration_space (delta_t.grace_part_);
}
}
#include "paper-column.hh"
#include "column-x-positions.hh"
#include "pointer-group-interface.hh"
+#include "spacing-interface.hh"
#include "spacing-spanner.hh"
#include "note-spacing.hh"
#include "moment.hh"
return false;
l_neighbor = l_neighbor->get_column ();
- r_neighbor = dynamic_cast<Item *> (Note_spacing::right_column (r_neighbor));
+ r_neighbor = dynamic_cast<Item *> (Spacing_interface::right_column (r_neighbor));
if (l == l_neighbor && r == r_neighbor)
return false;
for (vsize k = wishes.size (); k--;)
{
Grob *sp = wishes[k];
- if (Note_spacing::left_column (sp) != lc
- || Note_spacing::right_column (sp) != rc)
+ if (Spacing_interface::left_column (sp) != lc
+ || Spacing_interface::right_column (sp) != rc)
continue;
if (Note_spacing::has_interface (sp))
The note spacing should be taken from the musical
columns.
*/
- Real space = 0.0;
- Real fixed = 0.0;
- bool dummy = false;
-
- Real base = note_spacing (me, lc, rc, options, &dummy);
- Note_spacing::get_spacing (sp, rc, base, options->increment_,
- &space, &fixed);
+ Real base = note_spacing (me, lc, rc, options);
+ Spring spring = Note_spacing::get_spacing (sp, rc, base, options->increment_);
- space -= options->increment_;
-
- dists[d] = max (dists[d], space);
+ dists[d] = max (dists[d], spring.distance () - options->increment_);
}
else if (Staff_spacing::has_interface (sp))
{
- Real space = 0;
- Real fixed_space = 0;
- Staff_spacing::get_spacing_params (sp,
- &space, &fixed_space);
+ Spring spring = Staff_spacing::get_spacing (sp, rc);
- dists[d] = max (dists[d], fixed_space);
+ dists[d] = max (dists[d], spring.min_distance ());
}
else
programming_error ("Subversive spacing wish");
Item *wish = dynamic_cast<Item *> (wishes[k]);
Item *lc = wish->get_column ();
- Grob *right = Note_spacing::right_column (wish);
+ Grob *right = Spacing_interface::right_column (wish);
if (!right)
continue;
--- /dev/null
+/*
+ spacing-interface.cc -- functionality that is shared between Note_spacing
+ and Staff_spacing
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2007 Joe Neeman <joeneeman@gmail.com>
+*/
+
+#include "spacing-interface.hh"
+
+#include "grob.hh"
+#include "grob-array.hh"
+#include "item.hh"
+#include "note-column.hh"
+#include "pointer-group-interface.hh"
+#include "paper-column.hh"
+#include "separation-item.hh"
+#include "skyline.hh"
+
+/* return the right-pointing skyline of the left-items and the left-pointing
+ skyline of the right-items (with the skyline of the left-items in
+ ret[LEFT]) */
+Drul_array<Skyline>
+Spacing_interface::skylines (Grob *me, Grob *right_col)
+{
+ /* the logic here is a little convoluted.
+ A {Staff,Note}_spacing doesn't copy left-items when it clones,
+ so in order to find the separation items, we need to use the original
+ spacing grob. But once we find the separation items, we need to get back
+ the broken piece.
+ */
+
+ Grob *orig = me->original () ? me->original () : me;
+ Drul_array<Direction> break_dirs (dynamic_cast<Item*> (me)->break_status_dir (),
+ dynamic_cast<Item*> (right_col)->break_status_dir ());
+ Drul_array<Skyline> skylines = Drul_array<Skyline> (Skyline (RIGHT), Skyline (LEFT));
+ Drul_array<vector<Grob*> > items (ly_scm2link_array (orig->get_object ("left-items")),
+ ly_scm2link_array (orig->get_object ("right-items")));
+
+ Direction d = LEFT;
+ do
+ {
+ skylines[d].set_minimum_height (0.0);
+
+ for (vsize i = 0; i < items[d].size (); i++)
+ {
+ Grob *g = items[d][i];
+ if (Item *it = dynamic_cast<Item*> (g))
+ if (Grob *piece = it->find_prebroken_piece (break_dirs[d]))
+ g = piece;
+
+ if (Separation_item::has_interface (g))
+ {
+ SCM sky_scm = g->get_property ("horizontal-skylines");
+ Skyline_pair *sky = Skyline_pair::unsmob (sky_scm);
+ if (sky)
+ skylines[d].merge ((*sky)[-d]);
+ else
+ programming_error ("separation item has no skyline");
+
+ if (d == RIGHT && items[LEFT].size ())
+ skylines[d].merge (Separation_item::conditional_skyline (items[d][i], items[LEFT][0]));
+ }
+ }
+ }
+ while (flip (&d) != LEFT);
+
+ return skylines;
+}
+
+Real
+Spacing_interface::minimum_distance (Grob *me, Grob *right)
+{
+ Drul_array<Skyline> skylines = Spacing_interface::skylines (me, right);
+
+ return max (0.0, skylines[LEFT].distance (skylines[RIGHT]));
+}
+
+/*
+ Compute the column of the right-items. This is a big function,
+ since RIGHT-ITEMS may span more columns (eg. if a clef is inserted,
+ this will add a new column to RIGHT-ITEMS. Here we look at the
+ columns, and return the left-most. If there are multiple columns, we
+ prune RIGHT-ITEMS.
+*/
+Item *
+Spacing_interface::right_column (Grob *me)
+{
+ if (!me->is_live ())
+ return 0;
+
+ Grob_array *a = unsmob_grob_array (me->get_object ("right-items"));
+ Item *mincol = 0;
+ int min_rank = INT_MAX;
+ bool prune = false;
+ for (vsize i = 0; a && i < a->size (); i++)
+ {
+ Item *ri = a->item (i);
+ Item *col = ri->get_column ();
+
+ int rank = Paper_column::get_rank (col);
+
+ if (rank < min_rank)
+ {
+ min_rank = rank;
+ if (mincol)
+ prune = true;
+
+ mincol = col;
+ }
+ }
+
+ if (prune && a)
+ {
+ vector<Grob*> &right = a->array_reference ();
+ for (vsize i = right.size (); i--;)
+ {
+ if (dynamic_cast<Item *> (right[i])->get_column () != mincol)
+ right.erase (right.begin () + i);
+ }
+ }
+
+ return mincol;
+}
+
+Item *
+Spacing_interface::left_column (Grob *me)
+{
+ if (!me->is_live ())
+ return 0;
+
+ return dynamic_cast<Item *> (me)->get_column ();
+}
+
+static vector<Item*>
+get_note_columns (vector<Grob*> const &elts)
+{
+ vector<Item*> ret;
+
+ for (vsize i = 0; i < elts.size (); i++)
+ {
+ if (Note_column::has_interface (elts[i]))
+ ret.push_back (dynamic_cast<Item*> (elts[i]));
+ else if (Separation_item::has_interface (elts[i]))
+ {
+ extract_grob_set (elts[i], "elements", more_elts);
+ vector<Item*> ncs = get_note_columns (more_elts);
+
+ ret.insert (ret.end (), ncs.begin (), ncs.end ());
+ }
+ }
+
+ return ret;
+}
+
+vector<Item*>
+Spacing_interface::right_note_columns (Grob *me)
+{
+ extract_grob_set (me, "right-items", elts);
+ return get_note_columns (elts);
+}
+
+vector<Item*>
+Spacing_interface::left_note_columns (Grob *me)
+{
+ extract_grob_set (me, "left-items", elts);
+ return get_note_columns (elts);
+}
+
+/*
+ Try to find the break-aligned symbol that belongs on the D-side
+ of ME, sticking out in direction -D. The x size is put in LAST_EXT
+*/
+Grob *
+Spacing_interface::extremal_break_aligned_grob (Grob *me,
+ Direction d,
+ Direction break_dir,
+ Interval *last_ext)
+{
+ Grob *col = 0;
+ last_ext->set_empty ();
+ Grob *last_grob = 0;
+
+ extract_grob_set (me, d == LEFT ? "left-break-aligned" : "right-break-aligned", elts);
+
+ for (vsize i = elts.size (); i--;)
+ {
+ Item *break_item = dynamic_cast<Item*> (elts[i]);
+
+ if (break_item->break_status_dir () != break_dir)
+ break_item = break_item->find_prebroken_piece (break_dir);
+
+ if (!break_item || !scm_is_pair (break_item->get_property ("space-alist")))
+ continue;
+
+ if (!col)
+ col = dynamic_cast<Item*> (elts[0])->get_column ()->find_prebroken_piece (break_dir);
+
+ Interval ext = break_item->extent (col, X_AXIS);
+
+ if (ext.is_empty ())
+ continue;
+
+ if (!last_grob
+ || (last_grob && d * (ext[-d]- (*last_ext)[-d]) < 0))
+ {
+ *last_ext = ext;
+ last_grob = break_item;
+ }
+ }
+
+ return last_grob;
+}
+
+
+ADD_INTERFACE (Spacing_interface,
+ "This object calculates the desired and minimum distances between two columns.",
+
+ "left-items "
+ "right-items "
+ );
else
programming_error ("Column without spacing object");
- bool expand_only = false;
Real base_note_space = 0.0;
if (Paper_column::is_musical (next_col)
&& Paper_column::is_musical (loose_col))
- base_note_space = Spacing_spanner::note_spacing (spacing, loose_col, next_col,
- &options, &expand_only);
+ base_note_space = Spacing_spanner::note_spacing (spacing, loose_col, next_col,
+ &options);
else
{
- Real fixed, space;
-
- Spacing_spanner::standard_breakable_column_spacing (spacing,
- loose_col, next_col,
- &fixed, &space,
- &options);
-
- base_note_space = space;
+ Spring spring = Spacing_spanner::standard_breakable_column_spacing (spacing,
+ loose_col, next_col,
+ &options);
+
+ base_note_space = spring.distance ();
}
base_note_space = max (base_note_space,
Get the measure wide ant for arithmetic spacing.
*/
Real
-Spacing_options::get_duration_space (Rational d,
- bool *expand_only) const
+Spacing_options::get_duration_space (Rational d) const
{
Real k = shortest_duration_space_;
*/
Real log = log_2 (global_shortest_);
k -= log;
- *expand_only = false;
return (log_2 (d) + k) * increment_;
}
#include <math.h>
#include <cstdio>
-using namespace std;
-
#include "spacing-options.hh"
#include "international.hh"
#include "main.hh"
#include "paper-column.hh"
#include "paper-score.hh"
#include "pointer-group-interface.hh"
+#include "separation-item.hh"
#include "spaceable-grob.hh"
#include "spacing-interface.hh"
#include "staff-spacing.hh"
{
if (Paper_column::is_musical (left_col))
{
- bool skip_unbroken_right = false;
-
if (!Paper_column::is_musical (right_col)
&& options->float_nonmusical_columns_
&& after_right_col
&& Paper_column::is_musical (after_right_col))
- skip_unbroken_right = true;
-
- if (skip_unbroken_right)
{
/*
TODO: should generate rods to prevent collisions.
}
}
+static void
+set_column_rods (vector<Grob*> const &cols, vsize idx, Real padding)
+{
+
+ /*
+ This is an inner loop: look for the first normal (unbroken) Left
+ grob. This looks like an inner loop (ie. quadratic total), but in
+ most cases, the interesting L will just be the first entry of
+ NEXT, making it linear in most of the cases.
+ */
+ Item *r = dynamic_cast<Item*> (cols[idx]);
+
+ if (Separation_item::is_empty (r))
+ return;
+
+ while (idx--)
+ {
+ Item *l = dynamic_cast<Item*> (cols[idx]);
+ Item *lb = l->find_prebroken_piece (RIGHT);
+
+ if (Separation_item::is_empty (l) && (!lb || Separation_item::is_empty (lb)))
+ continue;
+
+ Separation_item::set_distance (Drul_array<Item *> (l, r), padding);
+ if (lb)
+ Separation_item::set_distance (Drul_array<Item*> (lb, r), padding);
+
+
+ /*
+ This check is because grace notes are set very tight, and
+ the accidentals of main note may stick out so far to cover
+ a barline preceding the grace note.
+ */
+ if (spanned_time_interval (l, r).length ().main_part_ > Rational (0))
+ break;
+
+ /*
+ this grob doesn't cause a constraint. We look further until we
+ find one that does.
+ */
+ }
+}
+
void
Spacing_spanner::generate_springs (Grob *me,
vector<Grob*> const &cols,
Paper_column *next = (i + 1 < cols.size ()) ? dynamic_cast<Paper_column *> (cols[i+1]) : 0;
if (i > 0)
- generate_pair_spacing (me, prev, col, next, options);
+ {
+ generate_pair_spacing (me, prev, col, next, options);
+ set_column_rods (cols, i, 0.1); // FIXME
+ }
prev = col;
}
}
/*
- Generate the space between two musical columns LEFT_COL and RIGHT_COL, given
- spacing parameters INCR and SHORTEST.
+ Generate the space between two musical columns LEFT_COL and RIGHT_COL.
*/
void
Spacing_spanner::musical_column_spacing (Grob *me,
Item *right_col,
Spacing_options const *options)
{
- bool expand_only = false;
- Real base_note_space = note_spacing (me, left_col, right_col, options, &expand_only);
-
- Real max_fixed = 0;
- Real max_space = 0;
- Real compound_note_space = 0.0;
- Real compound_fixed_note_space = 0.0;
+ Real base_note_space = note_spacing (me, left_col, right_col, options);
+ Spring spring;
if (options->stretch_uniformly_)
- {
- compound_note_space = base_note_space;
-
- if (!Paper_column::is_musical (right_col))
- {
- /*
- Crude fix for notes that lead up to barlines and time sigs.
- */
- Interval lext = right_col->extent (right_col, X_AXIS);
- if (!lext.is_empty ())
- compound_note_space += -lext[LEFT];
- }
- }
+ spring = Spring (base_note_space, 0.0);
else
{
- int wish_count = 0;
-
+ vector<Spring> springs;
extract_grob_set (left_col, "right-neighbors", neighbors);
- /*
- We adjust the space following a note only if the next note
- happens after the current note (this is set in the grob
- property SPACING-SEQUENCE.
- */
for (vsize i = 0; i < neighbors.size (); i++)
{
Grob *wish = neighbors[i];
- Item *wish_rcol = Note_spacing::right_column (wish);
- if (Note_spacing::left_column (wish) != left_col
+ Item *wish_rcol = Spacing_interface::right_column (wish);
+ if (Spacing_interface::left_column (wish) != left_col
|| (wish_rcol != right_col && wish_rcol != right_col->original ()))
continue;
This is probably a waste of time in the case of polyphonic
music. */
if (Note_spacing::has_interface (wish))
- {
- Real space = 0.0;
- Real fixed = 0.0;
-
- Note_spacing::get_spacing (wish, right_col, base_note_space, options->increment_, &space, &fixed);
-
-
- max_space = max (max_space, space);
- max_fixed = max (max_fixed, fixed);
-
- compound_note_space += space;
- compound_fixed_note_space += fixed;
- wish_count++;
- }
+ springs.push_back (Note_spacing::get_spacing (wish, right_col, base_note_space, options->increment_));
}
- if (Paper_column::when_mom (right_col).grace_part_
- && !Paper_column::when_mom (left_col).grace_part_)
- {
- /*
- Ugh. 0.8 is arbitrary.
- */
- compound_note_space *= 0.8;
- }
-
- if (compound_note_space < 0 || wish_count == 0)
+ if (springs.empty ())
{
if (!Paper_column::is_musical (right_col))
spacing, because the width of s^"text" output is also
taken into account here.
*/
- compound_fixed_note_space = options->increment_;
- compound_note_space = max (base_note_space,
- options->increment_);
+ spring = Spring (max (base_note_space, options->increment_),
+ options->increment_);
}
else
{
Fixed should be 0.0. If there are no spacing wishes, we're
likely dealing with polyphonic spacing of hemiolas.
- We used to have compound_fixed_note_space = options->increment_
+ We used to have min_distance_ = options->increment_
but this can lead to numeric instability problems when we
do
- inverse_strength = (compound_note_space - compound_fixed_note_space)
+ inverse_strength = (distance_ - min_distance_)
*/
-
- compound_note_space = base_note_space;
- compound_fixed_note_space = 0.0;
+ spring = Spring (base_note_space, 0.0);
}
}
- else if (to_boolean (me->get_property ("average-spacing-wishes")))
- {
- compound_note_space /= wish_count;
- compound_fixed_note_space /= wish_count;
- }
else
- {
- compound_fixed_note_space = max_fixed;
- compound_note_space = max_space;
- }
+ spring = merge_springs (springs);
+ }
+ if (Paper_column::when_mom (right_col).grace_part_
+ && !Paper_column::when_mom (left_col).grace_part_)
+ {
/*
- Whatever we do, the fixed space is smaller than the real
- space.
-
- TODO: this criterion is discontinuous in the derivative.
- Maybe it should be continuous?
+ Ugh. 0.8 is arbitrary.
*/
- compound_fixed_note_space = min (compound_fixed_note_space,
- compound_note_space);
+ spring *= 0.8;
}
- Real inverse_strength = 1.0;
- Real distance = 1.0;
-
/*
TODO: make sure that the space doesn't exceed the right margin.
*/
pack as much bars of music as possible into a line, but the
line will then be stretched to fill the whole linewidth.
*/
- inverse_strength = 1.0;
- distance = compound_fixed_note_space;
- }
- else
- {
- inverse_strength = (compound_note_space - compound_fixed_note_space);
- distance = compound_note_space;
+ spring.set_distance (spring.min_distance ());
+ spring.set_inverse_stretch_strength (1.0);
}
- Spaceable_grob::add_spring (left_col, right_col, distance, inverse_strength);
+ Spaceable_grob::add_spring (left_col, right_col, spring);
}
/*
Spacing_spanner::breakable_column_spacing (Grob *me, Item *l, Item *r,
Spacing_options const *options)
{
- Real compound_fixed = 0.0;
- Real compound_space = 0.0;
- Real max_fixed = 0.0;
- Real max_space = 0.0;
-
- int wish_count = 0;
+ vector<Spring> springs;
+ Spring spring;
Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
if (!spacing_grob || !Staff_spacing::has_interface (spacing_grob))
continue;
- Real space = 0.;
- Real fixed_space = 0.;
-
/*
column for the left one settings should be ok due automatic
pointer munging.
*/
assert (spacing_grob->get_column () == l);
- Staff_spacing::get_spacing_params (spacing_grob,
- &space, &fixed_space);
-
- if (Paper_column::when_mom (r).grace_part_)
- {
- /*
- Correct for grace notes.
-
- Ugh. The 0.8 is arbitrary.
- */
- space *= 0.8;
- }
-
- max_space = max (max_space, space);
- max_fixed = max (max_fixed, fixed_space);
-
- compound_space += space;
- compound_fixed += fixed_space;
- wish_count++;
+ springs.push_back (Staff_spacing::get_spacing (spacing_grob, r));
}
}
- if (compound_space <= 0.0 || !wish_count)
- {
- standard_breakable_column_spacing (me, l, r, &compound_fixed, &compound_space,
- options);
- wish_count = 1;
- }
+ if (springs.empty ())
+ spring = standard_breakable_column_spacing (me, l, r, options);
else
+ spring = merge_springs (springs);
+
+ if (Paper_column::when_mom (r).grace_part_)
{
- if (to_boolean (me->get_property ("average-spacing-wishes")))
- {
- compound_space /= wish_count;
- compound_fixed /= wish_count;
- }
- else
- {
- compound_fixed = max_fixed;
- compound_space = max_space;
- }
-
+ /*
+ Correct for grace notes.
+
+ Ugh. The 0.8 is arbitrary.
+ */
+ spring *= 0.8;
}
if (Paper_column::is_musical (r)
&& l->break_status_dir () == CENTER
&& fills_measure (me, l, r))
{
- compound_space += 1.0;
+ spring.set_distance (spring.distance () + 1.0);
+ spring.set_default_strength ();
}
if (options->stretch_uniformly_ && l->break_status_dir () != RIGHT)
- compound_fixed = 0.0;
-
- assert (!isinf (compound_space));
- compound_space = max (compound_space, compound_fixed);
+ {
+ spring.set_min_distance (0.0);
+ spring.set_default_strength ();
+ }
- Real inverse_strength = (compound_space - compound_fixed);
- Real distance = compound_space;
- Spaceable_grob::add_spring (l, r, distance, inverse_strength);
+ Spaceable_grob::add_spring (l, r, spring);
}
ADD_INTERFACE (Spacing_spanner,
"also the X-reference point of the spanner.\n",
"minimum-length "
+ "to-barline "
);
#include "warn.hh"
#include "ly-smobs.icc"
-Spring_smob::Spring_smob ()
-{
- distance_ = 0.;
- inverse_strength_ = 1.0;
- expand_only_b_ = false;
- other_ = 0;
-}
-
-IMPLEMENT_SIMPLE_SMOBS (Spring_smob);
+IMPLEMENT_SIMPLE_SMOBS (Spring);
SCM
-Spring_smob::mark_smob (SCM x)
+Spring::mark_smob (SCM x)
{
(void)x;
}
int
-Spring_smob::print_smob (SCM, SCM p, scm_print_state *)
+Spring::print_smob (SCM, SCM p, scm_print_state *)
{
scm_puts ("#<Spring smob>", p);
return 1;
}
SCM
-Spring_smob::equal_p (SCM a, SCM b)
+Spring::equal_p (SCM a, SCM b)
{
return a == b? SCM_BOOL_T : SCM_BOOL_F;
}
--- /dev/null
+/*
+ spring.cc -- declare Spring
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 2007 Joe Neeman <joeneeman@gmail.com>
+*/
+
+#include "spring.hh"
+
+Spring::Spring ()
+{
+ distance_ = 1.0;
+ min_distance_ = 1.0;
+ inverse_stretch_strength_ = 1.0;
+ inverse_compress_strength_ = 1.0;
+
+ update_blocking_force ();
+}
+
+Spring::Spring (Real dist, Real min_dist)
+{
+ distance_ = 1.0;
+ min_distance_ = 1.0;
+
+ set_distance (dist);
+ set_min_distance (min_dist);
+ set_default_strength ();
+ update_blocking_force ();
+}
+
+void
+Spring::update_blocking_force ()
+{
+ if (distance_ == min_distance_)
+ blocking_force_ = 0.0;
+ else
+ blocking_force_ = (min_distance_ - distance_) / inverse_compress_strength_;
+}
+
+/* scale a spring, but in a way that doesn't violate min_distance */
+void
+Spring::operator*= (Real r)
+{
+ distance_ = max (min_distance_, distance_ * r);
+ inverse_compress_strength_ = distance_ - min_distance_;
+ inverse_stretch_strength_ *= 0.8;
+}
+
+bool
+Spring::operator> (Spring const &other) const
+{
+ return blocking_force_ > other.blocking_force_;
+}
+
+/* merge springs, basically by averaging them, but leave a little headroom
+ above the largest minimum distance so that things don't get too cramped */
+Spring
+merge_springs (vector<Spring> const &springs)
+{
+ Real avg_distance = 0;
+ Real min_distance = 0;
+ Real avg_stretch = 0;
+
+ for (vsize i = 0; i < springs.size (); i++)
+ {
+ avg_distance += springs[i].distance ();
+ avg_stretch += springs[i].inverse_stretch_strength ();
+ min_distance = max (springs[i].min_distance (), min_distance);
+ }
+
+ avg_stretch /= springs.size ();
+ avg_distance /= springs.size ();
+ avg_distance = max (min_distance + 0.3, avg_distance);
+
+ Spring ret = Spring (avg_distance, min_distance);
+ ret.set_inverse_stretch_strength (avg_stretch);
+
+ return ret;
+}
+
+void
+Spring::set_distance (Real d)
+{
+ if (d < 0 || isinf (d) || isnan (d))
+ programming_error ("insane spring distance requested, ignoring it");
+ else
+ {
+ min_distance_ = min (min_distance_, d);
+ distance_ = d;
+ update_blocking_force ();
+ }
+}
+
+void
+Spring::set_min_distance (Real d)
+{
+ if (d < 0 || isinf (d) || isnan (d))
+ programming_error ("insane spring min_distance requested, ignoring it");
+ else
+ {
+ min_distance_ = d;
+ distance_ = max (distance_, min_distance_);
+ update_blocking_force ();
+ }
+}
+
+void
+Spring::set_inverse_stretch_strength (Real f)
+{
+ if (isinf (f) || isnan (f) || f < 0)
+ programming_error ("insane spring constant");
+ else
+ inverse_stretch_strength_ = f;
+}
+
+void
+Spring::set_inverse_compress_strength (Real f)
+{
+ if (isinf (f) || isnan (f) || f < 0)
+ programming_error ("insane spring constant");
+ else
+ inverse_compress_strength_ = f;
+
+ update_blocking_force ();
+}
+
+void
+Spring::set_blocking_force (Real f)
+{
+ if (isinf (f) || isnan (f))
+ {
+ programming_error ("insane blocking force");
+ return;
+ }
+
+ blocking_force_ = -infinity_f;
+ min_distance_ = length (f);
+ distance_ = max (distance_, min_distance_);
+ update_blocking_force ();
+}
+
+void
+Spring::set_default_strength ()
+{
+ inverse_compress_strength_ = distance_ - min_distance_;
+ inverse_stretch_strength_ = distance_ - min_distance_;
+}
+
+Real
+Spring::length (Real f) const
+{
+ Real force = max (f, blocking_force_);
+ Real inv_k = force < 0.0 ? inverse_compress_strength_ : inverse_stretch_strength_;
+ return distance_ + force * inv_k;
+}
#include <cstdio>
using namespace std;
+#include "international.hh"
#include "paper-column.hh"
#include "separation-item.hh"
#include "warn.hh"
#include "staff-symbol-referencer.hh"
#include "note-column.hh"
#include "stem.hh"
+#include "spacing-interface.hh"
#include "accidental-placement.hh"
#include "pointer-group-interface.hh"
#include "directional-element-interface.hh"
-/*
- Insert some more space for the next note, in case it has a stem in
- the wrong direction
+/* A stem following a bar-line creates an optical illusion similar to the
+ one mentioned in note-spacing.cc. We correct for it here.
+
+ TODO: should we still correct if there are accidentals/arpeggios before
+ the stem?
*/
-void
-Staff_spacing::next_note_correction (Grob *me,
- Grob *g,
- Interval bar_size,
- Real current_space, Real current_fixed,
- Real *space,
- Real *fix,
- int *wish_count)
+
+Real
+Staff_spacing::optical_correction (Grob *me, Grob *g, Interval bar_height)
{
- (void) current_fixed;
if (!g || !Note_column::has_interface (g))
- return ;
+ return 0;
- Item *col = dynamic_cast<Item *> (g)->get_column ();
- Real left_stickout_correction = max (0., (- g->extent (col, X_AXIS)[LEFT]));
-
- /* staff space -> positions */
- bar_size *= 2;
-
- /*
- Duh. If this gets out of hand, we should invent something more generic.
- */
- Grob *accs = Note_column::accidentals (g);
- if (accs)
- {
- Interval v;
- if (Accidental_placement::has_interface (accs))
- v = Accidental_placement::get_relevant_accidental_extent (accs, col, me);
- else
- v = accs->extent (col, X_AXIS);
-
- left_stickout_correction = max (left_stickout_correction, (- v[LEFT]));
- }
- Grob *arpeggio = unsmob_grob (g->get_object ("arpeggio"));
- if (arpeggio)
- left_stickout_correction = max (left_stickout_correction, - arpeggio->extent (col, X_AXIS)[LEFT]);
-
-
- /*
- Let's decrease the space a little if the problem is not located
- after a barline.
- */
- if (bar_size.is_empty ())
- left_stickout_correction *= 0.75;
-
- /*
- We want 0.3 ss before the sticking-out object.
-
- current_fixed/2 is our guess at (right side of left object + 0.3)
- */
- left_stickout_correction += current_fixed/2 - current_space;
- left_stickout_correction = max (left_stickout_correction, 0.0);
-
-
- Real optical_corr = 0.0;
Grob *stem = Note_column::get_stem (g);
- if (!bar_size.is_empty ()
- && !arpeggio
- && !accs
- && stem)
+ Real ret = 0.0;
+
+ if (!bar_height.is_empty () && stem)
{
Direction d = get_grob_direction (stem);
if (Stem::is_normal_stem (stem) && d == DOWN)
Interval stem_posns (min (stem_start, stem_end),
max (stem_end, stem_start));
- stem_posns.intersect (bar_size);
+ stem_posns.intersect (bar_height);
- optical_corr = min (abs (stem_posns.length () / 7.0), 1.0);
- optical_corr *= robust_scm2double (me->get_property ("stem-spacing-correction"), 1);
+ ret = min (abs (stem_posns.length () / 7.0), 1.0);
+ ret *= robust_scm2double (me->get_property ("stem-spacing-correction"), 1);
}
}
-
-
- Real correction = optical_corr + left_stickout_correction;
- if (correction)
- {
- (*wish_count) ++;
-
- /*
- This minute adjustments don't make sense for widely spaced scores.
- Hence, we need to keep the stretchable (that is, space - fix)
- distance equal.
- */
- *space += correction;
- *fix += correction;
- }
+ return ret;
}
+
/*
Y-positions that are covered by BAR_GROB, in the case that it is a
barline. */
return bar_size;
}
-/*
- Do corrections for the following notes.
-
- This is slightly convoluted, since the staffspacing grob gets
- pointers to the separation-items, not the note-columns or
- note-spacings.
-*/
-
-void
-Staff_spacing::next_notes_correction (Grob *me, Grob *last_grob,
- Real current_space, Real current_fixed,
- Real *compound_space, Real *compound_fixed
- )
+Real
+Staff_spacing::next_notes_correction (Grob *me,
+ Grob *last_grob)
{
Interval bar_size = bar_y_positions (last_grob);
+ Grob *orig = me->original () ? me->original () : me;
+ vector<Item*> note_columns = Spacing_interface::right_note_columns (orig);
- extract_grob_set (me, "right-items", right_items);
+ Real max_optical = 0.0;
- *compound_fixed = 0.0;
- *compound_space = 0.0;
- int wish_count = 0;
+ for (vsize i = 0; i < note_columns.size (); i++)
+ max_optical = max (max_optical, optical_correction (me, note_columns[i], bar_size));
- for (vsize i = right_items.size (); i--;)
- {
- Grob *g = right_items[i];
- if (Note_column::has_interface (right_items[i]))
- {
- Grob *g = right_items[i];
-
- Real space = 0.0;
- Real fixed = 0.0;
-
- next_note_correction (me, g, bar_size,
- current_space, current_fixed,
- &space, &fixed, &wish_count);
-
- *compound_space += space;
- *compound_fixed += fixed;
- }
- else
- {
- extract_grob_set (g, "elements", elts);
- for (vsize j = elts.size (); j--;)
- {
- Real space = 0.0;
- Real fixed = 0.0;
- next_note_correction (me, elts[j], bar_size,
- current_space, current_fixed,
- &space, &fixed,
- &wish_count);
- *compound_fixed += fixed;
- *compound_space += space;
- }
- }
- }
-
- if (wish_count > 1)
- {
- *compound_space /= wish_count;
- *compound_fixed /= wish_count;
- }
+ return max_optical;
}
-void
-Staff_spacing::get_spacing_params (Grob *me, Real *space, Real *fixed)
+/* We calculate three things here: the ideal distance, the minimum distance
+ (which is the distance at which collisions will occure) and the "fixed"
+ distance, which is the distance at which things start to look really bad.
+ We arrange things so that the fixed distance will be attained when the
+ line is compressed with a force of 1.0 */
+Spring
+Staff_spacing::get_spacing (Grob *me, Grob *right_col)
{
- *space = 1.0;
- *fixed = 1.0;
-
- Grob *separation_item = 0;
Item *me_item = dynamic_cast<Item *> (me);
-
- extract_grob_set (me, "left-items", items);
- for (vsize i = items.size (); i--;)
- {
- Grob *cand = items[i];
- if (cand && Separation_item::has_interface (cand))
- separation_item = cand;
- }
-
- // printf ("doing col %d\n" , Paper_column::get_rank (left_col));
- if (!separation_item)
- {
- programming_error ("no sep item");
- return;
- }
+ Grob *left_col = me_item->get_column ();
Interval last_ext;
- Grob *last_grob = Separation_item::extremal_break_aligned_grob (separation_item, RIGHT,
- &last_ext);
+ Direction break_dir = me_item->break_status_dir ();
+ Grob *last_grob = Spacing_interface::extremal_break_aligned_grob (me, LEFT,
+ break_dir,
+ &last_ext);
if (!last_grob)
{
/*
we used to have a warning here, but it generates a lot of
spurious error messages.
*/
- return;
+ return Spring ();
}
- *fixed = last_ext[RIGHT];
- *space = *fixed + 1.0;
-
SCM alist = last_grob->get_property ("space-alist");
if (!scm_list_p (alist))
- return;
+ return Spring ();
SCM space_def = scm_sloppy_assq (ly_symbol2scm ("first-note"), alist);
if (me_item->break_status_dir () == CENTER)
if (!scm_is_pair (space_def))
{
programming_error ("unknown prefatory spacing");
- return;
+ return Spring ();
}
space_def = scm_cdr (space_def);
Real distance = scm_to_double (scm_cdr (space_def));
SCM type = scm_car (space_def);
- *fixed = last_ext[RIGHT];
+ Real fixed = last_ext[RIGHT];
+ Real ideal = fixed + 1.0;
+
if (type == ly_symbol2scm ("fixed-space"))
{
- *fixed += distance;
- *space = *fixed;
+ fixed += distance;
+ ideal = fixed;
}
else if (type == ly_symbol2scm ("extra-space"))
- *space = *fixed + distance;
+ ideal = fixed + distance;
else if (type == ly_symbol2scm ("semi-fixed-space"))
{
- *fixed += distance / 2;
- *space = *fixed + distance / 2;
+ fixed += distance / 2;
+ ideal = fixed + distance / 2;
}
else if (type == ly_symbol2scm ("minimum-space"))
- *space = last_ext[LEFT] + max (last_ext.length (), distance);
+ ideal = last_ext[LEFT] + max (last_ext.length (), distance);
else if (type == ly_symbol2scm ("minimum-fixed-space"))
{
- *space = last_ext[LEFT] + max (last_ext.length (), distance);
- *fixed = *space;
+ fixed = last_ext[LEFT] + max (last_ext.length (), distance);
+ ideal = fixed;
}
- Real correction_fixed = 0.0;
- Real correction_space = 0.0;
- next_notes_correction (me, last_grob,
- *space, *fixed,
- &correction_space, &correction_fixed );
- *space += correction_space;
- *fixed += correction_fixed;
+
+ Real optical_correction = next_notes_correction (me, last_grob);
+ Real min_dist = Paper_column::minimum_distance (left_col, right_col);
+
+ /* ensure that the "fixed" distance will leave a gap of at least 0.3 ss. */
+ Real min_dist_correction = max (0.0, 0.3 + min_dist - fixed);
+ Real correction = max (optical_correction, min_dist_correction);
+
+ fixed += correction;
+ ideal += correction;
+
+ Spring ret (ideal, min_dist);
+ ret.set_inverse_stretch_strength (ideal - fixed);
+ return ret;
}
ADD_INTERFACE (Staff_spacing,
/* properties */
"stem-spacing-correction "
- "left-items "
- "right-items "
);
#include "paper-score.hh"
#include "paper-system.hh"
#include "pointer-group-interface.hh"
-#include "spacing-interface.hh"
#include "staff-symbol-referencer.hh"
#include "warn.hh"
#include "lookup.hh"
if (!wait)
heads_to_tie_.clear ();
- Grob *sep = unsmob_grob (get_property ("breakableSeparationItem"));
for (vsize i = 0; i < ties_.size (); i++)
- {
- if (sep)
- ties_[i]->set_object ("separation-item", sep->self_scm ());
-
typeset_tie (ties_[i]);
- }
+
ties_.clear ();
tie_column_ = 0;
}
{
Item *it = dynamic_cast<Spanner*> (ties[i])->get_bound (d);
if (it->break_status_dir ())
- {
- Item *sep
- = dynamic_cast<Item*> (unsmob_grob (ties[i]->get_object ("separation-item")));
- if (sep && sep->get_column () == it->get_column ())
- it = sep;
+ it = it->get_column ();
- bounds.push_back (it);
- }
- else
- {
- bounds.push_back (it);
- }
+ bounds.push_back (it);
}
set_chord_outline (bounds, d);
return sz > 0 && Axis_group_interface::has_interface (i.grob ())
&& !i.grob ()->get_parent (Y_AXIS)
+ && !to_boolean (i.grob ()->get_property ("no-alignment"))
&& Axis_group_interface::has_axis (i.grob (), Y_AXIS);
}
Volta_bracket_interface::add_bar (Grob *me, Item *b)
{
Pointer_group_interface::add_grob (me, ly_symbol2scm ("bars"), b);
- Side_position_interface::add_support (me, b);
add_bound_item (dynamic_cast<Spanner *> (me), b);
}
#include "engraver.hh"
+#include "axis-group-interface.hh"
#include "bar-line.hh"
#include "context.hh"
+#include "grob-array.hh"
#include "international.hh"
#include "note-column.hh"
#include "item.hh"
TRANSLATOR_DECLARATIONS (Volta_engraver);
protected:
- DECLARE_END_ACKNOWLEDGER (staff_symbol);
- DECLARE_ACKNOWLEDGER (staff_symbol);
DECLARE_ACKNOWLEDGER (bar_line);
- virtual void finalize ();
virtual void derived_mark () const;
void stop_translation_timestep ();
void process_music ();
Moment started_mom_;
- Spanner *volta_span_;
- Spanner *end_volta_span_;
- SCM staff_;
+ Spanner *volta_bracket_;
+ Spanner *end_volta_bracket_;
+ Spanner *volta_spanner_;
SCM start_string_;
-
- bool staff_eligible ();
};
void
Volta_engraver::derived_mark () const
{
- scm_gc_mark (staff_);
scm_gc_mark (start_string_);
}
Volta_engraver::Volta_engraver ()
{
- staff_ = SCM_EOL;
start_string_ = SCM_EOL;
- volta_span_ = 0;
- end_volta_span_ = 0;
-}
-
-/*
- TODO: this logic should be rewritten, it is buggy.
-
- One of the problems is that we can't determine wether or not to
- print the volta bracket during the first step, since that requires
- acknowledging the staff.
-*/
-bool
-Volta_engraver::staff_eligible ()
-{
- SCM doit = get_property ("voltaOnThisStaff");
- if (scm_is_bool (doit))
- return to_boolean (doit);
-
- if (!unsmob_grob (staff_))
- return false;
-
- /*
- TODO: this does weird things when you open a piece with a
- volta spanner.
- */
- SCM staffs = get_property ("stavesFound");
-
- /* Only put a volta on the top staff.
- Maybe this is a bit convoluted, and we should have a single
- volta engraver in score context or somesuch. */
- if (!scm_is_pair (staffs))
- {
- programming_error ("volta engraver can't find staves");
- return false;
- }
- else if (scm_car (scm_last_pair (staffs)) != staff_)
- return false;
- return true;
+ volta_bracket_ = 0;
+ end_volta_bracket_ = 0;
+ volta_spanner_ = 0;
}
void
{
SCM cs = get_property ("repeatCommands");
- if (!staff_eligible ())
- return;
-
bool end = false;
start_string_ = SCM_EOL;
while (scm_is_pair (cs))
cs = scm_cdr (cs);
}
- if (volta_span_)
+ if (volta_bracket_)
{
SCM l (get_property ("voltaSpannerDuration"));
Moment now = now_mom ();
end = end || early_stop;
}
- if (end && !volta_span_)
+ if (end && !volta_bracket_)
/* fixme: be more verbose. */
warning (_ ("cannot end volta spanner"));
else if (end)
{
- end_volta_span_ = volta_span_;
- volta_span_ = 0;
+ end_volta_bracket_ = volta_bracket_;
+ volta_bracket_ = 0;
}
- if (volta_span_
+ if (volta_bracket_
&& (scm_is_string (start_string_) || scm_is_pair (start_string_)))
{
warning (_ ("already have a volta spanner, ending that one prematurely"));
- if (end_volta_span_)
+ if (end_volta_bracket_)
{
warning (_ ("also already have an ended spanner"));
warning (_ ("giving up"));
return;
}
- end_volta_span_ = volta_span_;
- volta_span_ = 0;
+ end_volta_bracket_ = volta_bracket_;
+ volta_bracket_ = 0;
}
- if (!volta_span_
+ if (!volta_bracket_
&& Text_interface::is_markup (start_string_))
{
started_mom_ = now_mom ();
- volta_span_ = make_spanner ("VoltaBracket", SCM_EOL);
+ volta_bracket_ = make_spanner ("VoltaBracket", SCM_EOL);
- volta_span_->set_property ("text", start_string_);
- }
-}
+ volta_bracket_->set_property ("text", start_string_);
-void
-Volta_engraver::acknowledge_bar_line (Grob_info i)
-{
- if (volta_span_)
- Volta_bracket_interface::add_bar (volta_span_, i.item ());
- if (end_volta_span_)
- Volta_bracket_interface::add_bar (end_volta_span_, i.item ());
-}
+ if (!volta_spanner_)
+ volta_spanner_ = make_spanner ("VoltaBracketSpanner", SCM_EOL);
-void
-Volta_engraver::acknowledge_end_staff_symbol (Grob_info i)
-{
- if (i.grob ()->self_scm () == staff_)
- staff_ = SCM_EOL;
+ Axis_group_interface::add_element (volta_spanner_, volta_bracket_);
+ }
}
void
-Volta_engraver::acknowledge_staff_symbol (Grob_info i)
+Volta_engraver::acknowledge_bar_line (Grob_info i)
{
- /*
- We only want to know about a single staff: then we add to the
- support. */
- if (staff_ != SCM_EOL)
- staff_ = SCM_UNDEFINED;
-
- if (staff_ != SCM_UNDEFINED)
- staff_ = i.grob ()->self_scm ();
-}
-
+ if (volta_bracket_)
+ Volta_bracket_interface::add_bar (volta_bracket_, i.item ());
+ if (end_volta_bracket_)
+ Volta_bracket_interface::add_bar (end_volta_bracket_, i.item ());
-void
-Volta_engraver::finalize ()
-{
+ if (volta_spanner_)
+ Side_position_interface::add_support (volta_spanner_, i.grob ());
}
void
Volta_engraver::stop_translation_timestep ()
{
- if (volta_span_ && !staff_eligible ())
- {
- /*
- THIS IS A KLUDGE.
+ Grob *cc = unsmob_grob (get_property ("currentCommandColumn"));
+ Item *ci = dynamic_cast<Item *> (cc);
- we need to do this here, because STAFF_ is not initialized yet
- in the 1st call of process_music ()
- */
+ if (end_volta_bracket_ && !end_volta_bracket_->get_bound (RIGHT))
+ end_volta_bracket_->set_bound (RIGHT, ci);
- volta_span_->suicide ();
- volta_span_ = 0;
- }
+ if (volta_spanner_ && end_volta_bracket_)
+ volta_spanner_->set_bound (RIGHT, end_volta_bracket_->get_bound (RIGHT));
- if (end_volta_span_ && !end_volta_span_->get_bound (RIGHT))
+ if (end_volta_bracket_ && !volta_bracket_)
{
- Grob *cc = unsmob_grob (get_property ("currentCommandColumn"));
- Item *ci = dynamic_cast<Item *> (cc);
- end_volta_span_->set_bound (RIGHT, ci);
+ for (SCM s = get_property ("stavesFound"); scm_is_pair (s); s = scm_cdr (s))
+ Side_position_interface::add_support (volta_spanner_, unsmob_grob (scm_car (s)));
+ volta_spanner_ = 0;
}
- end_volta_span_ = 0;
+ end_volta_bracket_ = 0;
- if (volta_span_ && !volta_span_->get_bound (LEFT))
- {
- Grob *cc = unsmob_grob (get_property ("currentCommandColumn"));
- Item *ci = dynamic_cast<Item *> (cc);
- volta_span_->set_bound (LEFT, ci);
- }
+ if (volta_bracket_ && !volta_bracket_->get_bound (LEFT))
+ volta_bracket_->set_bound (LEFT, ci);
+
+ if (volta_spanner_ && volta_bracket_ && !volta_spanner_->get_bound (LEFT))
+ volta_spanner_->set_bound (LEFT, volta_bracket_->get_bound (LEFT));
}
/*
TODO: should attach volta to paper-column if no bar is found.
*/
-ADD_ACKNOWLEDGER (Volta_engraver, staff_symbol);
-ADD_END_ACKNOWLEDGER (Volta_engraver, staff_symbol);
ADD_ACKNOWLEDGER (Volta_engraver, bar_line);
ADD_TRANSLATOR (Volta_engraver,
/* doc */ "Make volta brackets.",
- /* create */ "VoltaBracket",
+ /* create */ "VoltaBracket VoltaBracketSpanner",
/* read */ "repeatCommands voltaSpannerDuration stavesFound",
/* write */ "");
%% with empty ones.
\consists "Font_size_engraver"
- \consists "Volta_engraver"
\consists "Separating_line_group_engraver"
\consists "Dot_column_engraver"
\consists "Staff_collecting_engraver"
\consists "Output_property_engraver"
\consists "Font_size_engraver"
- \consists "Volta_engraver"
\consists "Separating_line_group_engraver"
\consists "Dot_column_engraver"
\consists "Bar_engraver"
\type "Engraver_group"
\name ChordNames
\description "Typesets chord names."
-
- \consists "Volta_engraver"
\consists "Rest_swallow_translator"
\consists "Output_property_engraver"
\consists "Skip_event_swallow_translator"
\consists "Hara_kiri_engraver"
% \consists "Note_spacing_engraver"
- voltaOnThisStaff = ##f
\override VerticalAxisGroup #'minimum-Y-extent = #'(0 . 2)
- \override SeparatingGroupSpanner #'padding = #0.8
\override VerticalAxisGroup #'remove-first = ##t
\override VerticalAxisGroup #'remove-empty = ##t
}
\consists "Default_bar_line_engraver"
\consists "Output_property_engraver"
\consists "System_start_delimiter_engraver"
- \consists "Mark_engraver"
+ \consists "Mark_engraver"
+ \consists "Volta_engraver"
\consists "Metronome_mark_engraver"
\consists "Break_align_engraver"
\consists "Spacing_engraver"
(instrumentSupport ,grob-list? "list of grobs to attach instrument name
to.")
(tieMelismaBusy ,boolean? "Signal whether a tie is present.")
+ (hasStaffSpacing ,boolean? "True if the currentCommandColumn contains items that will
+affect spacing")
)))
(define-public all-translation-properties
to flip the direction of custos stem.")
(next ,ly:grob? "Object that is next relation (e.g., the lyric
syllable following an extender.")
+ (no-alignment ,boolean? "If set, don't place this grob in a
+VerticalAlignment; rather, place it using its own Y-offset callback")
(no-ledgers ,boolean? "If set, don't draw ledger lines on this
object.")
(no-stem-extend ,boolean? "If set, notes with ledger lines do not
(thin-kern ,number? "The space after a hair-line in a bar line.")
(threshold ,number-pair? "@code{(@var{min} . @var{max})}, where
@var{min} and @var{max} are dimensions in staff space.")
+ (to-barline ,boolean? "If true, the spanner will stop at that barline
+just before it would otherwise stop.")
(tie-configuration ,list? "List of @code{(@var{position} .
@var{dir})} pairs, indicating the desired tie configuration, where
@var{position} is the offset from the center of the staff in staff
(normal-stems ,ly:grob-array? "Array of visible stems.")
(note-heads ,ly:grob-array? "List of note head grobs")
(note-head ,ly:grob? "A single note head")
+ (pure-Y-offset-in-progress ,boolean? "A debugging aid for catching cyclic dependencies.")
(right-items ,ly:grob-array? "")
(right-neighbors ,ly:grob-array? "see left-neighbors")
(separation-item ,ly:grob? "A separation item.")
(alteration . ,accidental-interface::calc-alteration)
(stencil . ,ly:accidental-interface::print)
(Y-extent . ,ly:accidental-interface::height)
+ (X-extent . ,ly:accidental-interface::width)
(meta . ((class . Item)
(interfaces . (accidental-interface
font-interface))))))
(font-size . -2)
(Y-offset . ,ly:side-position-interface::y-aligned-side)
(side-axis . ,Y)
+ (outside-staff-priority . 100)
(X-offset . ,(ly:make-simple-closure
`(,+
,(ly:make-simple-closure
(direction . ,UP)
(self-alignment-X . ,CENTER)
(meta . ((class . Item)
- (interfaces . (system-start-text-interface
- side-position-interface
+ (interfaces . (side-position-interface
font-interface))))))
(KeyCancellation
(axes . (0))
(before-line-breaking . ,ly:paper-column::before-line-breaking)
(X-extent . ,ly:axis-group-interface::width)
+ (horizontal-skylines . ,ly:separation-item::calc-skylines)
;; (stencil . ,ly:paper-column::print)
(non-musical . #t)
(meta . ((class . Paper_column)
(interfaces . (paper-column-interface
axis-group-interface
+ separation-item-interface
spaceable-grob-interface))))))
(NoteCollision
(axes . (0 1))
(X-extent . ,ly:axis-group-interface::width)
(Y-extent . ,ly:axis-group-interface::height)
+ (horizontal-skylines . ,ly:separation-item::calc-skylines)
(meta . ((class . Item)
(interfaces . (axis-group-interface
+ separation-item-interface
note-column-interface))))))
(NoteHead
;; If you ever change this back, please document! --hwn
(knee-spacing-correction . 1.0)
(meta . ((class . Item)
- (interfaces . (
+ (interfaces . (spacing-interface
note-spacing-interface))))))
(NoteName
(axes . (0))
(allow-loose-spacing . #t)
(before-line-breaking . ,ly:paper-column::before-line-breaking)
+ (horizontal-skylines . ,ly:separation-item::calc-skylines)
;; (stencil . ,ly:paper-column::print)
(X-extent . ,ly:axis-group-interface::width)
;; (font-size . -6) (font-name . "sans") (Y-extent . #f)
(meta . ((class . Paper_column)
(interfaces . (paper-column-interface
+ separation-item-interface
axis-group-interface
spaceable-grob-interface))))))
(list ly:self-alignment-interface::x-aligned-on-self)))))
(Y-offset . ,ly:side-position-interface::y-aligned-side)
+ (extra-spacing-width . (+inf.0 . -inf.0))
(self-alignment-X . 0)
(direction . ,UP)
(non-musical . #t)
(interfaces . (
separation-item-interface))))))
- (SeparatingGroupSpanner
- . (
- (springs-and-rods . ,ly:separating-group-spanner::set-spacing-rods)
- (meta . ((class . Spanner)
- (interfaces . (only-prebreak-interface
-
- separating-group-spanner-interface))))))
-
(Slur
. ((details . ,default-slur-details)
(control-points . ,ly:slur::calc-control-points)
(non-musical . #t)
(stem-spacing-correction . 0.4)
(meta . ((class . Item)
- (interfaces . (staff-spacing-interface))))))
+ (interfaces . (spacing-interface
+ staff-spacing-interface))))))
(StaffSymbol
(VoltaBracket
. (
(stencil . ,ly:volta-bracket-interface::print)
- (direction . ,UP)
- (padding . 1)
(font-encoding . fetaNumber)
- (minimum-Y-extent . (0 . 2))
- (Y-offset . ,ly:side-position-interface::y-aligned-side)
- (side-axis . ,Y)
(thickness . 1.6) ;; line-thickness
(edge-height . (2.0 . 2.0)) ;; staff-space;
- (minimum-space . 5)
(font-size . -4)
- (outside-staff-priority . 100)
+ (direction . ,UP)
(meta . ((class . Spanner)
(interfaces . (volta-bracket-interface
horizontal-bracket-interface
font-interface)))
)))
+ (VoltaBracketSpanner
+ . (
+ (axes . (1))
+ (side-axis . ,Y)
+ (direction . ,UP)
+ (padding . 1)
+ (Y-offset . ,ly:side-position-interface::y-aligned-side)
+ (outside-staff-priority . 100)
+ (Y-extent . ,ly:axis-group-interface::height)
+ (X-extent . ,ly:axis-group-interface::width)
+ (no-alignment . ,#t)
+ (meta . ((class . Spanner)
+ (interfaces . (side-position-interface
+ axis-group-interface)))
+ )))
(VoiceFollower
. (
ly:piano-pedal-bracket::print
ly:rest::print
ly:script-interface::print
- ly:separating-group-spanner::set-spacing-rods
ly:slur::height
ly:slur::print
ly:spacing-spanner::set-springs