]> git.donarmstrong.com Git - lilypond.git/blob - lily/beaming-pattern.cc
Take invisible beams into account when beaming.
[lilypond.git] / lily / beaming-pattern.cc
1 /*
2   beaming-info.cc -- implement Beam_rhythmic_element, Beaming_pattern
3
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
10
11   source file of the GNU LilyPond music typesetter
12
13   (c) 1999--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
14 */
15
16 #include "beaming-pattern.hh"
17 #include "context.hh"
18
19 Beam_rhythmic_element::Beam_rhythmic_element ()
20 {
21   start_moment_ = 0;
22   beam_count_drul_[LEFT] = 0;
23   beam_count_drul_[RIGHT] = 0;
24   invisible_ = false;
25
26 }
27
28 Beam_rhythmic_element::Beam_rhythmic_element (Moment m, int i, bool inv)
29 {
30   start_moment_ = m;
31   beam_count_drul_[LEFT] = i;
32   beam_count_drul_[RIGHT] = i;
33   invisible_ = inv;
34 }
35
36
37 void
38 Beam_rhythmic_element::de_grace ()
39 {
40   if (start_moment_.grace_part_)
41     {
42       start_moment_.main_part_ = start_moment_.grace_part_; 
43       start_moment_.grace_part_ = 0;
44     }
45 }
46
47 int
48 count_factor_twos (int x)
49 {
50   int c = 0;
51   while (x && x % 2 == 0)
52     {
53       x /= 2;
54       c ++;
55     }
56          
57   return c;
58 }
59
60 bool
61 Beaming_pattern::is_next_to_invisible_stem (vsize i) const
62 {
63   return infos_[i].invisible_
64     || (i > 0 && infos_[i-1].invisible_);
65 }
66
67 /*
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).
76    - any other beam
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
80
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.
83 */
84 int
85 Beaming_pattern::best_splitpoint_index (bool *at_boundary) const
86 {
87   bool require_invisible = false;
88   for (vsize i = 0; i < infos_.size (); i++)
89     require_invisible |= infos_[i].invisible_;
90
91   *at_boundary = true;
92   for (vsize i = 1; i < infos_.size (); i++)  
93     {
94       if (infos_[i].group_start_ == infos_[i].start_moment_
95           && (!require_invisible || is_next_to_invisible_stem (i)))
96         return i;
97     }
98
99   for (vsize i = 1; i < infos_.size (); i++)  
100     {
101       if (infos_[i].beat_start_ == infos_[i].start_moment_
102           && (!require_invisible || is_next_to_invisible_stem (i)))
103         return i;
104     }
105
106   *at_boundary = false;
107   
108   int min_den = INT_MAX;
109   int min_index = -1;
110   
111   for (vsize i = 1; i < infos_.size (); i++)  
112     {
113       Moment dt = infos_[i].start_moment_ - infos_[i].beat_start_;
114
115       /*
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.)
120         
121        */
122       
123       dt /= infos_[i].beat_length_;
124       
125       if (dt.den () < min_den
126           && (!require_invisible || is_next_to_invisible_stem (i)))
127         {
128           min_den = dt.den ();
129           min_index = i;
130         }
131     }
132
133   return min_index;
134 }
135
136 int
137 Beaming_pattern::beam_extend_count (Direction d) const
138 {
139   if (infos_.size () == 1)
140     return infos_[0].beam_count_drul_[d];
141
142   Beam_rhythmic_element thisbeam = boundary (infos_, d, 0);
143   Beam_rhythmic_element next = boundary (infos_, d, 1);
144
145   return min (thisbeam.beam_count_drul_[-d], next.beam_count_drul_[d]);
146 }
147
148 void
149 Beaming_pattern::de_grace ()
150 {
151   for (vsize i = 0; i < infos_.size (); i ++)
152     {
153       infos_[i].de_grace ();
154     }
155 }
156
157 void
158 Beaming_pattern::beamify (Beaming_options const &options)
159 {
160   unbeam_invisible_stems ();
161
162   if (infos_.size () <= 1)
163     return;
164
165   if (infos_[0].start_moment_.grace_part_)
166     de_grace ();
167
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_;
171   
172   Moment measure_pos (0);
173   
174   vector<Moment> group_starts;
175   vector<Moment> beat_starts;
176
177   // Find the starting moments of the beats and the groups.
178   SCM grouping = options.grouping_;
179   while (measure_pos <= infos_.back ().start_moment_)
180     {
181       int count = 2;
182       if (scm_is_pair (grouping))
183         {
184           count = scm_to_int (scm_car (grouping));
185           grouping = scm_cdr (grouping);
186         }
187
188       group_starts.push_back (measure_pos);
189       for (int i = 0; i < count; i++)
190         {
191           beat_starts.push_back (measure_pos + options.beat_length_ * i);
192         }
193       measure_pos += options.beat_length_ * count;
194     }
195
196   // Set the group_start_ and beam_start_ properties of each stem.
197   vsize j = 0;
198   vsize k = 0;
199   for (vsize i = 0; i  < infos_.size (); i++)
200     {
201       while (j + 1 < group_starts.size ()
202              && group_starts[j+1] <= infos_[i].start_moment_)
203         j++;
204
205       if (j < group_starts.size ())
206         infos_[i].group_start_ = group_starts[j];
207       
208       infos_[i].beat_length_ = options.beat_length_;  
209       while (k + 1 < beat_starts.size () 
210              && beat_starts[k+1] <= infos_[i].start_moment_)
211         k++;
212
213       if (k < beat_starts.size ())
214         infos_[i].beat_start_ = beat_starts[k];
215     }
216   
217   beamify (options.subdivide_beams_);
218 }
219
220
221 /*
222   Determines beaming patterns by splitting the list of stems recursively.
223
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.
228
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
231   most one side.
232 */
233 void
234 Beaming_pattern::beamify (bool subdivide_beams)
235 {
236   if (infos_.size () <= 1)
237     return;
238   
239   Drul_array<Beaming_pattern> splits;
240
241   bool at_boundary = false;
242   int m = best_splitpoint_index (&at_boundary);
243
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,
247                                                         infos_.end ());
248
249   Direction d = LEFT;
250
251   do
252     {
253       splits[d].beamify (subdivide_beams);
254     }
255   while (flip (&d) != LEFT);
256
257   int middle_beams = (at_boundary && subdivide_beams)
258                       ? 1       
259                       : min (splits[RIGHT].beam_extend_count (LEFT),
260                              splits[LEFT].beam_extend_count (RIGHT));
261
262   do
263     {
264       if (splits[d].infos_.size () != 1)
265         boundary (splits[d].infos_, -d, 0).beam_count_drul_[-d] = middle_beams;
266     }
267   while (flip (&d) != LEFT);
268
269   infos_ = splits[LEFT].infos_;
270   infos_.insert (infos_.end (),
271                  splits[RIGHT].infos_.begin (),
272                  splits[RIGHT].infos_.end ());
273 }
274
275
276 /*
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.
280 */
281 void
282 Beaming_pattern::unbeam_invisible_stems ()
283 {
284   for (vsize i = 1; i < infos_.size (); i++)
285     if (infos_[i].invisible_)
286       {
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;
290       }
291
292   for (vsize i = infos_.size (); i--;)
293     if (infos_[i].invisible_)
294       {
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;
298       }
299 }
300
301
302 void
303 Beaming_pattern::add_stem (Moment m, int b, bool invisible)
304 {
305   infos_.push_back (Beam_rhythmic_element (m, b, invisible));
306 }
307
308 Beaming_pattern::Beaming_pattern ()
309 {
310 }
311
312 int
313 Beaming_pattern::beamlet_count (int i, Direction d) const
314 {
315   return infos_.at (i).beam_count_drul_[d];
316 }
317
318 void
319 Beaming_options::from_context (Context *context)
320 {
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));
325 }
326
327 Beaming_options::Beaming_options ()
328 {
329   grouping_ = SCM_EOL;
330   subdivide_beams_ = false;
331 }