]> git.donarmstrong.com Git - lilypond.git/blob - lily/beaming-pattern.cc
Merge branch 'master' into lilypond/translation
[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   unbeam_invisible_stems ();
125
126   if (infos_.size () <= 1)
127     return;
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   for (vsize i = infos_.size (); i--;)
221     if (infos_[i].invisible_)
222       {
223         int b = min (infos_[i].count (LEFT), infos_[i + 1].count (LEFT));
224         infos_[i].beam_count_drul_[LEFT] = b;
225         infos_[i].beam_count_drul_[RIGHT] = b;
226       }
227 }
228
229 void
230 Beaming_pattern::add_stem (Moment m, int b, bool invisible)
231 {
232   infos_.push_back (Beam_rhythmic_element (m, b, invisible));
233 }
234
235 Beaming_pattern::Beaming_pattern ()
236 {
237 }
238
239 int
240 Beaming_pattern::beamlet_count (int i, Direction d) const
241 {
242   return infos_.at (i).beam_count_drul_[d];
243 }
244
245 Moment
246 Beaming_pattern::start_moment (int i) const
247 {
248   return infos_.at (i).start_moment_;
249 }
250
251 Moment
252 Beaming_pattern::end_moment (int i) const
253 {
254   Duration *dur = new Duration (2 + max (beamlet_count (i, LEFT),
255                                          beamlet_count (i, RIGHT)),
256                                 0);
257
258   return infos_.at (i).start_moment_ + dur->get_length ();
259 }
260
261 bool
262 Beaming_pattern::invisibility (int i) const
263 {
264   return infos_.at (i).invisible_;
265 }
266
267 /*
268     Split a beamin pattern at index i and return a new
269     Beaming_pattern containing the removed elements
270 */
271 Beaming_pattern *
272 Beaming_pattern::split_pattern (int i)
273 {
274   Beaming_pattern *new_pattern = 0;
275   int count;
276
277   new_pattern = new Beaming_pattern ();
278   for (vsize j = i + 1; j < infos_.size (); j++)
279     {
280       count = max (beamlet_count (j, LEFT), beamlet_count (j, RIGHT));
281       new_pattern->add_stem (start_moment (j),
282                              count,
283                              invisibility (j));
284     }
285   for (vsize j = i + 1; j < infos_.size ();)
286     infos_.pop_back ();
287   return (new_pattern);
288 }
289
290 void
291 Beaming_options::from_context (Context *context)
292 {
293   grouping_ = context->get_property ("beatStructure");
294   subdivide_beams_ = to_boolean (context->get_property ("subdivideBeams"));
295   base_moment_ = robust_scm2moment (context->get_property ("baseMoment"),
296                                     Moment (1, 4));
297   measure_length_ = robust_scm2moment (context->get_property ("measureLength"),
298                                        Moment (4, 4));
299 }
300
301 Beaming_options::Beaming_options ()
302 {
303   grouping_ = SCM_EOL;
304   subdivide_beams_ = false;
305 }