]> git.donarmstrong.com Git - lilypond.git/blob - lily/beaming-pattern.cc
Merge branch 'lilypond/translation' of ssh://trettig@git.sv.gnu.org/srv/git/lilypond...
[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 /*
20   Represents a stem belonging to a beam. Sometimes (for example, if the stem
21   belongs to a rest and stemlets aren't used) the stem will be invisible.
22
23   The rhythmic_importance_ of an element tells us the significance of the
24   moment at which this element occurs. For example, an element that occurs at
25   a beat is more significant than one that doesn't. Smaller number are
26   more important. The rhythmic_importance_ is decided and filled in by
27   Beaming_pattern. A rhythmic_importance_ smaller than zero has extra
28   significance: it represents the start of a beat and therefore beams may
29   need to be subdivided.
30 */
31 Beam_rhythmic_element::Beam_rhythmic_element ()
32 {
33   start_moment_ = 0;
34   rhythmic_importance_ = 0;
35   beam_count_drul_[LEFT] = 0;
36   beam_count_drul_[RIGHT] = 0;
37   invisible_ = false;
38
39 }
40
41 Beam_rhythmic_element::Beam_rhythmic_element (Moment m, int i, bool inv)
42 {
43   start_moment_ = m;
44   rhythmic_importance_ = 0;
45   beam_count_drul_[LEFT] = i;
46   beam_count_drul_[RIGHT] = i;
47   invisible_ = inv;
48 }
49
50 void
51 Beam_rhythmic_element::de_grace ()
52 {
53   if (start_moment_.grace_part_)
54     {
55       start_moment_.main_part_ = start_moment_.grace_part_; 
56       start_moment_.grace_part_ = 0;
57     }
58 }
59
60 int
61 Beam_rhythmic_element::count (Direction d) const
62 {
63   return beam_count_drul_[d];
64 }
65
66 /*
67   Finds the appropriate direction for the flags at the given index that
68   hang below the neighbouring flags. If
69   the stem has no more flags than either of its neighbours, this returns
70   CENTER.
71 */
72 Direction
73 Beaming_pattern::flag_direction (vsize i) const
74 {
75   // The extremal stems shouldn't be messed with, so it's appropriate to
76   // return CENTER here also.
77   if (i == 0 || i == infos_.size () - 1)
78     return CENTER;
79
80   int count = infos_[i].count (LEFT); // Both directions should still be the same
81   int left_count = infos_[i-1].count (RIGHT);
82   int right_count = infos_[i+1].count (LEFT);
83
84   if (count <= left_count && count <= right_count)
85     return CENTER;
86
87   // Try to avoid sticking-out flags as much as possible by pointing my flags
88   // at the neighbour with the most flags.
89   else if (right_count > left_count)
90     return RIGHT;
91   else if (left_count > right_count)
92     return LEFT;
93
94   // If all else fails, point the beamlet away from the important moment.
95   return (infos_[i].rhythmic_importance_ <= infos_[i+1].rhythmic_importance_) ? RIGHT : LEFT;
96 }
97
98 void
99 Beaming_pattern::de_grace ()
100 {
101   for (vsize i = 0; i < infos_.size (); i ++)
102     {
103       infos_[i].de_grace ();
104     }
105 }
106
107 void
108 Beaming_pattern::beamify (Beaming_options const &options)
109 {
110   unbeam_invisible_stems ();
111
112   if (infos_.size () <= 1)
113     return;
114
115   if (infos_[0].start_moment_.grace_part_)
116     de_grace ();
117
118   if (infos_[0].start_moment_ < Moment (0))
119     for (vsize i = 0; i < infos_.size (); i++)
120       infos_[i].start_moment_ += options.measure_length_;
121
122   find_rhythmic_importance (options);
123
124   for (vsize i = 1; i < infos_.size () - 1; i++)
125     {
126       Direction non_flag_dir = other_dir (flag_direction (i));
127       if (non_flag_dir)
128         {
129           int importance = (non_flag_dir == LEFT)
130             ? infos_[i].rhythmic_importance_ : infos_[i+1].rhythmic_importance_;
131           int count = (importance < 0)
132             ? 1 : min (infos_[i].count (non_flag_dir),
133                        infos_[i+non_flag_dir].count (-non_flag_dir));
134
135           infos_[i].beam_count_drul_[non_flag_dir] = count;
136         }
137     }
138 }
139
140 void
141 Beaming_pattern::find_rhythmic_importance (Beaming_options const &options)
142 {
143   Moment measure_pos (0);  
144   SCM grouping = options.grouping_;
145   vsize i = 0;
146
147   // Mark the importance of stems that start at a beat or a beat group.
148   while (i < infos_.size ())
149     {
150       // If a beat grouping is not specified, default to 2 beats per group.
151       int count = 2;
152       if (scm_is_pair (grouping))
153         {
154           count = scm_to_int (scm_car (grouping));
155           grouping = scm_cdr (grouping);
156         }
157
158       // Mark the start of this beat group
159       if (infos_[i].start_moment_ == measure_pos)
160         infos_[i].rhythmic_importance_ = -2;
161
162       // Mark the start of each beat up to the end of this beat group.
163       for (int beat = 1; beat <= count; beat++)
164         {
165           Moment next_measure_pos = measure_pos + options.beat_length_;
166
167           while (i < infos_.size () && infos_[i].start_moment_ < next_measure_pos)
168             {
169               Moment dt = infos_[i].start_moment_ - measure_pos;
170
171               // The rhythmic importance of a stem between beats depends on its fraction
172               // of a beat: those stems with a lower denominator are deemed more
173               // important.
174               // FIXME: This is not the right way to do things for tuplets. For example,
175               // in an 8th-note triplet with a quarter-note beat, 1/3 of a beat should be
176               // more important than 1/2.
177               if (infos_[i].rhythmic_importance_ >= 0)
178                 infos_[i].rhythmic_importance_ = (dt / options.beat_length_).den ();
179
180               i++;
181             }
182
183           measure_pos = next_measure_pos;
184           if (i < infos_.size () && infos_[i].start_moment_ == measure_pos)
185             infos_[i].rhythmic_importance_ = -1;
186         }
187     }
188 }
189
190
191 /*
192   Invisible stems should be treated as though they have the same number of
193   beams as their least-beamed neighbour. Here we go through the stems and
194   modify the invisible stems to satisfy this requirement.
195 */
196 void
197 Beaming_pattern::unbeam_invisible_stems ()
198 {
199   for (vsize i = 1; i < infos_.size (); i++)
200     if (infos_[i].invisible_)
201       {
202         int b = min (infos_[i].count (LEFT), infos_[i-1].count (LEFT));
203         infos_[i].beam_count_drul_[LEFT] = b;
204         infos_[i].beam_count_drul_[RIGHT] = b;
205       }
206
207   for (vsize i = infos_.size (); i--;)
208     if (infos_[i].invisible_)
209       {
210         int b = min (infos_[i].count (LEFT), infos_[i+1].count (LEFT));
211         infos_[i].beam_count_drul_[LEFT] = b;
212         infos_[i].beam_count_drul_[RIGHT] = b;
213       }
214 }
215
216
217 void
218 Beaming_pattern::add_stem (Moment m, int b, bool invisible)
219 {
220   infos_.push_back (Beam_rhythmic_element (m, b, invisible));
221 }
222
223 Beaming_pattern::Beaming_pattern ()
224 {
225 }
226
227 int
228 Beaming_pattern::beamlet_count (int i, Direction d) const
229 {
230   return infos_.at (i).beam_count_drul_[d];
231 }
232
233 void
234 Beaming_options::from_context (Context *context)
235 {
236   grouping_ = context->get_property ("beatGrouping");
237   subdivide_beams_ = to_boolean (context->get_property ("subdivideBeams"));
238   beat_length_ = robust_scm2moment (context->get_property ("beatLength"), Moment (1, 4));
239   measure_length_ = robust_scm2moment (context->get_property ("measureLength"), Moment (1, 4));
240 }
241
242 Beaming_options::Beaming_options ()
243 {
244   grouping_ = SCM_EOL;
245   subdivide_beams_ = false;
246 }