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"
19 Beam_rhythmic_element::Beam_rhythmic_element ()
22 beam_count_drul_[LEFT] = 0;
23 beam_count_drul_[RIGHT] = 0;
28 Beam_rhythmic_element::Beam_rhythmic_element (Moment m, int i, bool inv)
31 beam_count_drul_[LEFT] = i;
32 beam_count_drul_[RIGHT] = i;
38 Beam_rhythmic_element::de_grace ()
40 if (start_moment_.grace_part_)
42 start_moment_.main_part_ = start_moment_.grace_part_;
43 start_moment_.grace_part_ = 0;
48 count_factor_twos (int x)
51 while (x && x % 2 == 0)
61 Beaming_pattern::is_next_to_invisible_stem (vsize i) const
63 return infos_[i].invisible_
64 || (i > 0 && infos_[i-1].invisible_);
68 Finds the best point at which to subdivide a beam. In order of priority
69 (highest to lowest) this is
70 - before or after an invisible beam
71 - at the start of a beat group
72 - at the start of a beat
73 - whose position in its beat has the smallest denominator (that is,
74 a stem that starts halfway through a beat will be preferred over stems
75 that start 1/3 or 2/3s of the way through the beat).
77 - at the start of a beat group
78 - at the start of a beat
79 - whose position in its beat has the smallest denominator
81 If the split point occurs at the start of a beat group or at the start of a
82 beat, at_boundary will be set to true. Otherwise, it will be set to false.
85 Beaming_pattern::best_splitpoint_index (bool *at_boundary) const
87 bool require_invisible = false;
88 for (vsize i = 0; i < infos_.size (); i++)
89 require_invisible |= infos_[i].invisible_;
92 for (vsize i = 1; i < infos_.size (); i++)
94 if (infos_[i].group_start_ == infos_[i].start_moment_
95 && (!require_invisible || is_next_to_invisible_stem (i)))
99 for (vsize i = 1; i < infos_.size (); i++)
101 if (infos_[i].beat_start_ == infos_[i].start_moment_
102 && (!require_invisible || is_next_to_invisible_stem (i)))
106 *at_boundary = false;
108 int min_den = INT_MAX;
111 for (vsize i = 1; i < infos_.size (); i++)
113 Moment dt = infos_[i].start_moment_ - infos_[i].beat_start_;
116 This is a kludge, for the most common case of 16th, 32nds
117 etc. What should really happen is that \times x/y should
118 locally introduce a voice-specific beat duration. (or
119 perhaps: a list of beat durations for nested tuplets.)
123 dt /= infos_[i].beat_length_;
125 if (dt.den () < min_den
126 && (!require_invisible || is_next_to_invisible_stem (i)))
137 Beaming_pattern::beam_extend_count (Direction d) const
139 if (infos_.size () == 1)
140 return infos_[0].beam_count_drul_[d];
142 Beam_rhythmic_element thisbeam = boundary (infos_, d, 0);
143 Beam_rhythmic_element next = boundary (infos_, d, 1);
145 return min (thisbeam.beam_count_drul_[-d], next.beam_count_drul_[d]);
149 Beaming_pattern::de_grace ()
151 for (vsize i = 0; i < infos_.size (); i ++)
153 infos_[i].de_grace ();
158 Beaming_pattern::beamify (Beaming_options const &options)
160 unbeam_invisible_stems ();
162 if (infos_.size () <= 1)
165 if (infos_[0].start_moment_.grace_part_)
168 if (infos_[0].start_moment_ < Moment (0))
169 for (vsize i = 0; i < infos_.size (); i++)
170 infos_[i].start_moment_ += options.measure_length_;
172 Moment measure_pos (0);
174 vector<Moment> group_starts;
175 vector<Moment> beat_starts;
177 // Find the starting moments of the beats and the groups.
178 SCM grouping = options.grouping_;
179 while (measure_pos <= infos_.back ().start_moment_)
182 if (scm_is_pair (grouping))
184 count = scm_to_int (scm_car (grouping));
185 grouping = scm_cdr (grouping);
188 group_starts.push_back (measure_pos);
189 for (int i = 0; i < count; i++)
191 beat_starts.push_back (measure_pos + options.beat_length_ * i);
193 measure_pos += options.beat_length_ * count;
196 // Set the group_start_ and beam_start_ properties of each stem.
199 for (vsize i = 0; i < infos_.size (); i++)
201 while (j + 1 < group_starts.size ()
202 && group_starts[j+1] <= infos_[i].start_moment_)
205 if (j < group_starts.size ())
206 infos_[i].group_start_ = group_starts[j];
208 infos_[i].beat_length_ = options.beat_length_;
209 while (k + 1 < beat_starts.size ()
210 && beat_starts[k+1] <= infos_[i].start_moment_)
213 if (k < beat_starts.size ())
214 infos_[i].beat_start_ = beat_starts[k];
217 beamify (options.subdivide_beams_);
222 Determines beaming patterns by splitting the list of stems recursively.
224 Given a list of stems, we split it at the most 'natural' place (eg. at
225 the beginning of a beat) as determined by best_splitpoint_index. We
226 then beamify both subsets of beams. Finally, we determine the number of
227 beams between the subsets.
229 Note: if one of the subsets has only one element, we will not modify its
230 beams. This ensure that, for every stem, we will modify its beam count on at
234 Beaming_pattern::beamify (bool subdivide_beams)
236 if (infos_.size () <= 1)
239 Drul_array<Beaming_pattern> splits;
241 bool at_boundary = false;
242 int m = best_splitpoint_index (&at_boundary);
244 splits[LEFT].infos_ = vector<Beam_rhythmic_element> (infos_.begin (),
245 infos_.begin () + m);
246 splits[RIGHT].infos_ = vector<Beam_rhythmic_element> (infos_.begin () + m,
253 splits[d].beamify (subdivide_beams);
255 while (flip (&d) != LEFT);
257 int middle_beams = (at_boundary && subdivide_beams)
259 : min (splits[RIGHT].beam_extend_count (LEFT),
260 splits[LEFT].beam_extend_count (RIGHT));
264 if (splits[d].infos_.size () != 1)
265 boundary (splits[d].infos_, -d, 0).beam_count_drul_[-d] = middle_beams;
267 while (flip (&d) != LEFT);
269 infos_ = splits[LEFT].infos_;
270 infos_.insert (infos_.end (),
271 splits[RIGHT].infos_.begin (),
272 splits[RIGHT].infos_.end ());
277 Invisible stems should be treated as though they have the same number of
278 beams as their least-beamed neighbour. Here we go through the stems and
279 modify the invisible stems to satisfy this requirement.
282 Beaming_pattern::unbeam_invisible_stems ()
284 for (vsize i = 1; i < infos_.size (); i++)
285 if (infos_[i].invisible_)
287 int b = infos_[i-1].beam_count_drul_[LEFT];
288 infos_[i].beam_count_drul_[LEFT] = b;
289 infos_[i].beam_count_drul_[RIGHT] = b;
292 for (vsize i = infos_.size (); i--;)
293 if (infos_[i].invisible_)
295 int b = min (infos_[i].beam_count_drul_[LEFT], infos_[i+1].beam_count_drul_[LEFT]);
296 infos_[i].beam_count_drul_[LEFT] = b;
297 infos_[i].beam_count_drul_[RIGHT] = b;
303 Beaming_pattern::add_stem (Moment m, int b, bool invisible)
305 infos_.push_back (Beam_rhythmic_element (m, b, invisible));
308 Beaming_pattern::Beaming_pattern ()
313 Beaming_pattern::beamlet_count (int i, Direction d) const
315 return infos_.at (i).beam_count_drul_[d];
319 Beaming_options::from_context (Context *context)
321 grouping_ = context->get_property ("beatGrouping");
322 subdivide_beams_ = to_boolean (context->get_property ("subdivideBeams"));
323 beat_length_ = robust_scm2moment (context->get_property ("beatLength"), Moment (1, 4));
324 measure_length_ = robust_scm2moment (context->get_property ("measureLength"), Moment (1, 4));
327 Beaming_options::Beaming_options ()
330 subdivide_beams_ = false;