Correct left text alignment of DynamicTextSpanner.
[lilypond.git] / lily / beaming-pattern.cc
blob290620355bbdcfe7b2f037c9635dff65d826f0e8
1 /*
2 beaming-info.cc -- implement Beam_rhythmic_element, Beaming_pattern
4 A Beaming_pattern object takes a set of stems at given moments and calculates
5 the pattern of their beam. That is, it works out, for each stem, how many
6 beams should be connected to the right and left sides of that stem. In
7 calculating this, Beaming_pattern takes into account
8 - the rhythmic position of the stems
9 - the options that are defined in Beaming_options
11 source file of the GNU LilyPond music typesetter
13 (c) 1999--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
16 #include "beaming-pattern.hh"
17 #include "context.hh"
20 Represents a stem belonging to a beam. Sometimes (for example, if the stem
21 belongs to a rest and stemlets aren't used) the stem will be invisible.
23 The rhythmic_importance_ of an element tells us the significance of the
24 moment at which this element occurs. For example, an element that occurs at
25 a beat is more significant than one that doesn't. Smaller number are
26 more important. The rhythmic_importance_ is decided and filled in by
27 Beaming_pattern. A rhythmic_importance_ smaller than zero has extra
28 significance: it represents the start of a beat and therefore beams may
29 need to be subdivided.
31 Beam_rhythmic_element::Beam_rhythmic_element ()
33 start_moment_ = 0;
34 rhythmic_importance_ = 0;
35 beam_count_drul_[LEFT] = 0;
36 beam_count_drul_[RIGHT] = 0;
37 invisible_ = false;
41 Beam_rhythmic_element::Beam_rhythmic_element (Moment m, int i, bool inv)
43 start_moment_ = m;
44 rhythmic_importance_ = 0;
45 beam_count_drul_[LEFT] = i;
46 beam_count_drul_[RIGHT] = i;
47 invisible_ = inv;
50 void
51 Beam_rhythmic_element::de_grace ()
53 if (start_moment_.grace_part_)
55 start_moment_.main_part_ = start_moment_.grace_part_;
56 start_moment_.grace_part_ = 0;
60 int
61 Beam_rhythmic_element::count (Direction d) const
63 return beam_count_drul_[d];
67 Finds the appropriate direction for the flags at the given index that
68 hang below the neighbouring flags. If
69 the stem has no more flags than either of its neighbours, this returns
70 CENTER.
72 Direction
73 Beaming_pattern::flag_direction (Beaming_options const &options, vsize i) const
75 // The extremal stems shouldn't be messed with, so it's appropriate to
76 // return CENTER here also.
77 if (i == 0 || i == infos_.size () - 1)
78 return CENTER;
80 int count = infos_[i].count (LEFT); // Both directions should still be the same
81 int left_count = infos_[i-1].count (RIGHT);
82 int right_count = infos_[i+1].count (LEFT);
84 // If we are told to subdivide beams and we are next to a beat, point the
85 // beamlet away from the beat.
86 if (options.subdivide_beams_)
88 if (infos_[i].rhythmic_importance_ < 0)
89 return RIGHT;
90 else if (infos_[i+1].rhythmic_importance_ < 0)
91 return LEFT;
94 if (count <= left_count && count <= right_count)
95 return CENTER;
97 // Try to avoid sticking-out flags as much as possible by pointing my flags
98 // at the neighbour with the most flags.
99 else if (right_count > left_count)
100 return RIGHT;
101 else if (left_count > right_count)
102 return LEFT;
104 // If all else fails, point the beamlet away from the important moment.
105 return (infos_[i].rhythmic_importance_ <= infos_[i+1].rhythmic_importance_) ? RIGHT : LEFT;
108 void
109 Beaming_pattern::de_grace ()
111 for (vsize i = 0; i < infos_.size (); i ++)
113 infos_[i].de_grace ();
117 void
118 Beaming_pattern::beamify (Beaming_options const &options)
120 unbeam_invisible_stems ();
122 if (infos_.size () <= 1)
123 return;
125 if (infos_[0].start_moment_.grace_part_)
126 de_grace ();
128 if (infos_[0].start_moment_ < Moment (0))
129 for (vsize i = 0; i < infos_.size (); i++)
130 infos_[i].start_moment_ += options.measure_length_;
132 find_rhythmic_importance (options);
134 for (vsize i = 1; i < infos_.size () - 1; i++)
136 Direction non_flag_dir = other_dir (flag_direction (options, i));
137 if (non_flag_dir)
139 int importance = (non_flag_dir == LEFT)
140 ? infos_[i].rhythmic_importance_ : infos_[i+1].rhythmic_importance_;
141 int count = (importance < 0 && options.subdivide_beams_)
142 ? 1 : min (infos_[i].count (non_flag_dir),
143 infos_[i+non_flag_dir].count (-non_flag_dir));
145 infos_[i].beam_count_drul_[non_flag_dir] = count;
150 void
151 Beaming_pattern::find_rhythmic_importance (Beaming_options const &options)
153 Moment measure_pos (0);
154 SCM grouping = options.grouping_;
155 vsize i = 0;
157 // Mark the importance of stems that start at a beat or a beat group.
158 while (i < infos_.size ())
160 // If a beat grouping is not specified, default to 2 beats per group.
161 int count = 2;
162 if (scm_is_pair (grouping))
164 count = scm_to_int (scm_car (grouping));
165 grouping = scm_cdr (grouping);
168 // Mark the start of this beat group
169 if (infos_[i].start_moment_ == measure_pos)
170 infos_[i].rhythmic_importance_ = -2;
172 // Mark the start of each beat up to the end of this beat group.
173 for (int beat = 1; beat <= count; beat++)
175 Moment next_measure_pos = measure_pos + options.beat_length_;
177 while (i < infos_.size () && infos_[i].start_moment_ < next_measure_pos)
179 Moment dt = infos_[i].start_moment_ - measure_pos;
181 // The rhythmic importance of a stem between beats depends on its fraction
182 // of a beat: those stems with a lower denominator are deemed more
183 // important.
184 // FIXME: This is not the right way to do things for tuplets. For example,
185 // in an 8th-note triplet with a quarter-note beat, 1/3 of a beat should be
186 // more important than 1/2.
187 if (infos_[i].rhythmic_importance_ >= 0)
188 infos_[i].rhythmic_importance_ = (dt / options.beat_length_).den ();
190 i++;
193 measure_pos = next_measure_pos;
194 if (i < infos_.size () && infos_[i].start_moment_ == measure_pos)
195 infos_[i].rhythmic_importance_ = -1;
202 Invisible stems should be treated as though they have the same number of
203 beams as their least-beamed neighbour. Here we go through the stems and
204 modify the invisible stems to satisfy this requirement.
206 void
207 Beaming_pattern::unbeam_invisible_stems ()
209 for (vsize i = 1; i < infos_.size (); i++)
210 if (infos_[i].invisible_)
212 int b = min (infos_[i].count (LEFT), infos_[i-1].count (LEFT));
213 infos_[i].beam_count_drul_[LEFT] = b;
214 infos_[i].beam_count_drul_[RIGHT] = b;
217 for (vsize i = infos_.size (); i--;)
218 if (infos_[i].invisible_)
220 int b = min (infos_[i].count (LEFT), infos_[i+1].count (LEFT));
221 infos_[i].beam_count_drul_[LEFT] = b;
222 infos_[i].beam_count_drul_[RIGHT] = b;
227 void
228 Beaming_pattern::add_stem (Moment m, int b, bool invisible)
230 infos_.push_back (Beam_rhythmic_element (m, b, invisible));
233 Beaming_pattern::Beaming_pattern ()
238 Beaming_pattern::beamlet_count (int i, Direction d) const
240 return infos_.at (i).beam_count_drul_[d];
243 void
244 Beaming_options::from_context (Context *context)
246 grouping_ = context->get_property ("beatGrouping");
247 subdivide_beams_ = to_boolean (context->get_property ("subdivideBeams"));
248 beat_length_ = robust_scm2moment (context->get_property ("beatLength"), Moment (1, 4));
249 measure_length_ = robust_scm2moment (context->get_property ("measureLength"), Moment (1, 4));
252 Beaming_options::Beaming_options ()
254 grouping_ = SCM_EOL;
255 subdivide_beams_ = false;