]> git.donarmstrong.com Git - lilypond.git/blob - lily/beaming-pattern.cc
Repair dangerous loop from commit 7ee874c5
[lilypond.git] / lily / beaming-pattern.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1999--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
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.
10
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.
15
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/>.
18 */
19
20 #include "context.hh"
21 #include "beaming-pattern.hh"
22
23 /*
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.
26
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.
34 */
35 Beam_rhythmic_element::Beam_rhythmic_element ()
36 {
37   start_moment_ = 0;
38   rhythmic_importance_ = 0;
39   beam_count_drul_[LEFT] = 0;
40   beam_count_drul_[RIGHT] = 0;
41   invisible_ = false;
42
43 }
44
45 Beam_rhythmic_element::Beam_rhythmic_element (Moment m, int i, bool inv)
46 {
47   start_moment_ = m;
48   rhythmic_importance_ = 0;
49   beam_count_drul_[LEFT] = i;
50   beam_count_drul_[RIGHT] = i;
51   invisible_ = inv;
52 }
53
54 void
55 Beam_rhythmic_element::de_grace ()
56 {
57   if (start_moment_.grace_part_)
58     {
59       start_moment_.main_part_ = start_moment_.grace_part_;
60       start_moment_.grace_part_ = 0;
61     }
62 }
63
64 int
65 Beam_rhythmic_element::count (Direction d) const
66 {
67   return beam_count_drul_[d];
68 }
69
70 /*
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.
75 */
76 Direction
77 Beaming_pattern::flag_direction (Beaming_options const &options, vsize i) const
78 {
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;
83
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);
87
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_)
91     {
92       if (infos_[i].rhythmic_importance_ < 0)
93         return RIGHT;
94       else if (infos_[i + 1].rhythmic_importance_ < 0)
95         return LEFT;
96     }
97
98   if (count <= left_count && count <= right_count)
99     return CENTER;
100
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;
107
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;
110 }
111
112 void
113 Beaming_pattern::de_grace ()
114 {
115   for (vsize i = 0; i < infos_.size (); i++)
116     {
117       infos_[i].de_grace ();
118     }
119 }
120
121 void
122 Beaming_pattern::beamify (Beaming_options const &options)
123 {
124   if (infos_.size () <= 1)
125     return;
126
127   unbeam_invisible_stems ();
128
129   if (infos_[0].start_moment_.grace_part_)
130     de_grace ();
131
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_;
135
136   find_rhythmic_importance (options);
137
138   for (vsize i = 1; i < infos_.size () - 1; i++)
139     {
140       Direction non_flag_dir = other_dir (flag_direction (options, i));
141       if (non_flag_dir)
142         {
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));
148
149           infos_[i].beam_count_drul_[non_flag_dir] = count;
150         }
151     }
152 }
153
154 void
155 Beaming_pattern::find_rhythmic_importance (Beaming_options const &options)
156 {
157   Moment measure_pos (0);
158   SCM grouping = options.grouping_;
159   vsize i = 0;
160
161   // Mark the importance of stems that start at a beat or a beat group.
162   while (i < infos_.size ())
163     {
164       // If a beat grouping is not specified, default to 2 beats per group.
165       int count = 2;
166       if (scm_is_pair (grouping))
167         {
168           count = scm_to_int (scm_car (grouping));
169           grouping = scm_cdr (grouping);
170         }
171
172       // Mark the start of this beat group
173       if (infos_[i].start_moment_ == measure_pos)
174         infos_[i].rhythmic_importance_ = -2;
175
176       // Mark the start of each unit up to the end of this beat group.
177       for (int unit = 1; unit <= count; unit++)
178         {
179           Moment next_measure_pos = measure_pos + options.base_moment_;
180
181           while (i < infos_.size () && infos_[i].start_moment_ < next_measure_pos)
182             {
183               Moment dt = infos_[i].start_moment_ - measure_pos;
184
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 ();
193
194               i++;
195             }
196
197           measure_pos = next_measure_pos;
198           if (i < infos_.size () && infos_[i].start_moment_ == measure_pos)
199             infos_[i].rhythmic_importance_ = -1;
200         }
201     }
202 }
203
204 /*
205   Invisible stems should be treated as though they have the same number of
206   beams as their least-beamed neighbour. Here we go through the stems and
207   modify the invisible stems to satisfy this requirement.
208 */
209 void
210 Beaming_pattern::unbeam_invisible_stems ()
211 {
212   for (vsize i = 1; i < infos_.size (); i++)
213     if (infos_[i].invisible_)
214       {
215         int b = min (infos_[i].count (LEFT), infos_[i - 1].count (LEFT));
216         infos_[i].beam_count_drul_[LEFT] = b;
217         infos_[i].beam_count_drul_[RIGHT] = b;
218       }
219
220   if (infos_.size () > 1)
221     for (vsize i = infos_.size () - 1; i--;)
222       if (infos_[i].invisible_)
223         {
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;
227         }
228 }
229
230 void
231 Beaming_pattern::add_stem (Moment m, int b, bool invisible)
232 {
233   infos_.push_back (Beam_rhythmic_element (m, b, invisible));
234 }
235
236 Beaming_pattern::Beaming_pattern ()
237 {
238 }
239
240 int
241 Beaming_pattern::beamlet_count (int i, Direction d) const
242 {
243   return infos_.at (i).beam_count_drul_[d];
244 }
245
246 Moment
247 Beaming_pattern::start_moment (int i) const
248 {
249   return infos_.at (i).start_moment_;
250 }
251
252 Moment
253 Beaming_pattern::end_moment (int i) const
254 {
255   Duration *dur = new Duration (2 + max (beamlet_count (i, LEFT),
256                                          beamlet_count (i, RIGHT)),
257                                 0);
258
259   return infos_.at (i).start_moment_ + dur->get_length ();
260 }
261
262 bool
263 Beaming_pattern::invisibility (int i) const
264 {
265   return infos_.at (i).invisible_;
266 }
267
268 /*
269     Split a beamin pattern at index i and return a new
270     Beaming_pattern containing the removed elements
271 */
272 Beaming_pattern *
273 Beaming_pattern::split_pattern (int i)
274 {
275   Beaming_pattern *new_pattern = 0;
276   int count;
277
278   new_pattern = new Beaming_pattern ();
279   for (vsize j = i + 1; j < infos_.size (); j++)
280     {
281       count = max (beamlet_count (j, LEFT), beamlet_count (j, RIGHT));
282       new_pattern->add_stem (start_moment (j),
283                              count,
284                              invisibility (j));
285     }
286   for (vsize j = i + 1; j < infos_.size ();)
287     infos_.pop_back ();
288   return (new_pattern);
289 }
290
291 void
292 Beaming_options::from_context (Context *context)
293 {
294   grouping_ = context->get_property ("beatStructure");
295   subdivide_beams_ = to_boolean (context->get_property ("subdivideBeams"));
296   base_moment_ = robust_scm2moment (context->get_property ("baseMoment"),
297                                     Moment (1, 4));
298   measure_length_ = robust_scm2moment (context->get_property ("measureLength"),
299                                        Moment (4, 4));
300 }
301
302 Beaming_options::Beaming_options ()
303 {
304   grouping_ = SCM_EOL;
305   subdivide_beams_ = false;
306 }