Fixes Issue 1504, allowing feather beam line breaking.
[lilypond/patrick.git] / lily / beaming-pattern.cc
blobb823d2ecdaafb7e1c84d8a1c291601c993fb80cd
1 /*
2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1999--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include "context.hh"
21 #include "beaming-pattern.hh"
24 Represents a stem belonging to a beam. Sometimes (for example, if the stem
25 belongs to a rest and stemlets aren't used) the stem will be invisible.
27 The rhythmic_importance_ of an element tells us the significance of the
28 moment at which this element occurs. For example, an element that occurs at
29 a beat is more significant than one that doesn't. Smaller number are
30 more important. The rhythmic_importance_ is decided and filled in by
31 Beaming_pattern. A rhythmic_importance_ smaller than zero has extra
32 significance: it represents the start of a beat and therefore beams may
33 need to be subdivided.
35 Beam_rhythmic_element::Beam_rhythmic_element ()
37 start_moment_ = 0;
38 rhythmic_importance_ = 0;
39 beam_count_drul_[LEFT] = 0;
40 beam_count_drul_[RIGHT] = 0;
41 invisible_ = false;
45 Beam_rhythmic_element::Beam_rhythmic_element (Moment m, int i, bool inv)
47 start_moment_ = m;
48 rhythmic_importance_ = 0;
49 beam_count_drul_[LEFT] = i;
50 beam_count_drul_[RIGHT] = i;
51 invisible_ = inv;
54 void
55 Beam_rhythmic_element::de_grace ()
57 if (start_moment_.grace_part_)
59 start_moment_.main_part_ = start_moment_.grace_part_;
60 start_moment_.grace_part_ = 0;
64 int
65 Beam_rhythmic_element::count (Direction d) const
67 return beam_count_drul_[d];
71 Finds the appropriate direction for the flags at the given index that
72 hang below the neighbouring flags. If
73 the stem has no more flags than either of its neighbours, this returns
74 CENTER.
76 Direction
77 Beaming_pattern::flag_direction (Beaming_options const &options, vsize i) const
79 // The extremal stems shouldn't be messed with, so it's appropriate to
80 // return CENTER here also.
81 if (i == 0 || i == infos_.size () - 1)
82 return CENTER;
84 int count = infos_[i].count (LEFT); // Both directions should still be the same
85 int left_count = infos_[i-1].count (RIGHT);
86 int right_count = infos_[i+1].count (LEFT);
88 // If we are told to subdivide beams and we are next to a beat, point the
89 // beamlet away from the beat.
90 if (options.subdivide_beams_)
92 if (infos_[i].rhythmic_importance_ < 0)
93 return RIGHT;
94 else if (infos_[i+1].rhythmic_importance_ < 0)
95 return LEFT;
98 if (count <= left_count && count <= right_count)
99 return CENTER;
101 // Try to avoid sticking-out flags as much as possible by pointing my flags
102 // at the neighbour with the most flags.
103 else if (right_count > left_count)
104 return RIGHT;
105 else if (left_count > right_count)
106 return LEFT;
108 // If all else fails, point the beamlet away from the important moment.
109 return (infos_[i].rhythmic_importance_ <= infos_[i+1].rhythmic_importance_) ? RIGHT : LEFT;
112 void
113 Beaming_pattern::de_grace ()
115 for (vsize i = 0; i < infos_.size (); i ++)
117 infos_[i].de_grace ();
121 void
122 Beaming_pattern::beamify (Beaming_options const &options)
124 unbeam_invisible_stems ();
126 if (infos_.size () <= 1)
127 return;
129 if (infos_[0].start_moment_.grace_part_)
130 de_grace ();
132 if (infos_[0].start_moment_ < Moment (0))
133 for (vsize i = 0; i < infos_.size (); i++)
134 infos_[i].start_moment_ += options.measure_length_;
136 find_rhythmic_importance (options);
138 for (vsize i = 1; i < infos_.size () - 1; i++)
140 Direction non_flag_dir = other_dir (flag_direction (options, i));
141 if (non_flag_dir)
143 int importance = (non_flag_dir == LEFT)
144 ? infos_[i].rhythmic_importance_ : infos_[i+1].rhythmic_importance_;
145 int count = (importance < 0 && options.subdivide_beams_)
146 ? 1 : min (infos_[i].count (non_flag_dir),
147 infos_[i+non_flag_dir].count (-non_flag_dir));
149 infos_[i].beam_count_drul_[non_flag_dir] = count;
154 void
155 Beaming_pattern::find_rhythmic_importance (Beaming_options const &options)
157 Moment measure_pos (0);
158 SCM grouping = options.grouping_;
159 vsize i = 0;
161 // Mark the importance of stems that start at a beat or a beat group.
162 while (i < infos_.size ())
164 // If a beat grouping is not specified, default to 2 beats per group.
165 int count = 2;
166 if (scm_is_pair (grouping))
168 count = scm_to_int (scm_car (grouping));
169 grouping = scm_cdr (grouping);
172 // Mark the start of this beat group
173 if (infos_[i].start_moment_ == measure_pos)
174 infos_[i].rhythmic_importance_ = -2;
176 // Mark the start of each unit up to the end of this beat group.
177 for (int unit = 1; unit <= count; unit++)
179 Moment next_measure_pos = measure_pos + options.base_moment_;
181 while (i < infos_.size () && infos_[i].start_moment_ < next_measure_pos)
183 Moment dt = infos_[i].start_moment_ - measure_pos;
185 // The rhythmic importance of a stem between beats depends on its fraction
186 // of a beat: those stems with a lower denominator are deemed more
187 // important.
188 // FIXME: This is not the right way to do things for tuplets. For example,
189 // in an 8th-note triplet with a quarter-note beat, 1/3 of a beat should be
190 // more important than 1/2.
191 if (infos_[i].rhythmic_importance_ >= 0)
192 infos_[i].rhythmic_importance_ = (int) (dt / options.base_moment_).den ();
194 i++;
197 measure_pos = next_measure_pos;
198 if (i < infos_.size () && infos_[i].start_moment_ == measure_pos)
199 infos_[i].rhythmic_importance_ = -1;
206 Invisible stems should be treated as though they have the same number of
207 beams as their least-beamed neighbour. Here we go through the stems and
208 modify the invisible stems to satisfy this requirement.
210 void
211 Beaming_pattern::unbeam_invisible_stems ()
213 for (vsize i = 1; i < infos_.size (); i++)
214 if (infos_[i].invisible_)
216 int b = min (infos_[i].count (LEFT), infos_[i-1].count (LEFT));
217 infos_[i].beam_count_drul_[LEFT] = b;
218 infos_[i].beam_count_drul_[RIGHT] = b;
221 for (vsize i = infos_.size (); i--;)
222 if (infos_[i].invisible_)
224 int b = min (infos_[i].count (LEFT), infos_[i+1].count (LEFT));
225 infos_[i].beam_count_drul_[LEFT] = b;
226 infos_[i].beam_count_drul_[RIGHT] = b;
231 void
232 Beaming_pattern::add_stem (Moment m, int b, bool invisible)
234 infos_.push_back (Beam_rhythmic_element (m, b, invisible));
237 Beaming_pattern::Beaming_pattern ()
242 Beaming_pattern::beamlet_count (int i, Direction d) const
244 return infos_.at (i).beam_count_drul_[d];
247 Moment
248 Beaming_pattern::start_moment (int i) const
250 return infos_.at (i).start_moment_;
253 Moment
254 Beaming_pattern::end_moment (int i) const
256 Duration *dur = new Duration (2 + max (beamlet_count (i, LEFT),
257 beamlet_count (i, RIGHT)),
260 return infos_.at (i).start_moment_ + dur->get_length();
263 bool
264 Beaming_pattern::invisibility (int i) const
266 return infos_.at (i).invisible_;
270 Split a beamin pattern at index i and return a new
271 Beaming_pattern containing the removed elements
273 Beaming_pattern *
274 Beaming_pattern::split_pattern (int i)
276 Beaming_pattern* new_pattern=0;
277 int count;
279 new_pattern = new Beaming_pattern ();
280 for (vsize j=i+1; j<infos_.size (); j++)
282 count = max(beamlet_count (j, LEFT), beamlet_count(j, RIGHT));
283 new_pattern->add_stem (start_moment (j),
284 count,
285 invisibility (j));
287 for (vsize j=i+1; j<infos_.size (); )
288 infos_.pop_back ();
289 return (new_pattern);
292 void
293 Beaming_options::from_context (Context *context)
295 grouping_ = context->get_property ("beatStructure");
296 subdivide_beams_ = to_boolean (context->get_property ("subdivideBeams"));
297 base_moment_ = robust_scm2moment (context->get_property ("baseMoment"),
298 Moment (1, 4));
299 measure_length_ = robust_scm2moment (context->get_property ("measureLength"),
300 Moment (4, 4));
303 Beaming_options::Beaming_options ()
305 grouping_ = SCM_EOL;
306 subdivide_beams_ = false;