]> git.donarmstrong.com Git - lilypond.git/blob - lily/beaming-pattern.cc
Fix compiler warnings.
[lilypond.git] / lily / beaming-pattern.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1999--2010 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 /*
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.
209 */
210 void
211 Beaming_pattern::unbeam_invisible_stems ()
212 {
213   for (vsize i = 1; i < infos_.size (); i++)
214     if (infos_[i].invisible_)
215       {
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;
219       }
220
221   for (vsize i = infos_.size (); 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
231 void
232 Beaming_pattern::add_stem (Moment m, int b, bool invisible)
233 {
234   infos_.push_back (Beam_rhythmic_element (m, b, invisible));
235 }
236
237 Beaming_pattern::Beaming_pattern ()
238 {
239 }
240
241 int
242 Beaming_pattern::beamlet_count (int i, Direction d) const
243 {
244   return infos_.at (i).beam_count_drul_[d];
245 }
246
247 Moment
248 Beaming_pattern::start_moment (int i) const
249 {
250   return infos_.at (i).start_moment_;
251 }
252
253 Moment
254 Beaming_pattern::end_moment (int i) const
255 {
256   Duration *dur = new Duration (2 + max (beamlet_count (i, LEFT),
257                                         beamlet_count (i, RIGHT)),
258                                0);
259
260   return infos_.at (i).start_moment_ + dur->get_length();
261 }
262
263 bool
264 Beaming_pattern::invisibility (int i) const
265 {
266   return infos_.at (i).invisible_;
267 }
268
269 /*
270     Split a beamin pattern at index i and return a new
271     Beaming_pattern containing the removed elements
272 */
273 Beaming_pattern *
274 Beaming_pattern::split_pattern (int i)
275 {
276   Beaming_pattern* new_pattern=0;
277   int count;
278
279   new_pattern = new Beaming_pattern ();
280   for (vsize j=i+1; j<infos_.size (); j++)
281     {
282       count = max(beamlet_count (j, LEFT), beamlet_count(j, RIGHT));
283       new_pattern->add_stem (start_moment (j),
284                              count,
285                              invisibility (j));
286     }
287   for (vsize j=i+1; j<infos_.size (); )
288     infos_.pop_back ();
289   return (new_pattern);
290 }
291
292 void
293 Beaming_options::from_context (Context *context)
294 {
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));
301 }
302
303 Beaming_options::Beaming_options ()
304 {
305   grouping_ = SCM_EOL;
306   subdivide_beams_ = false;
307 }