]> git.donarmstrong.com Git - lilypond.git/blob - lily/auto-beam-engraver.cc
patch::: 1.1.27.jcn3: geen genade
[lilypond.git] / lily / auto-beam-engraver.cc
1 /*   
2   auto-beam-engraver.cc --  implement Auto_beam_engraver
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 1999 Jan Nieuwenhuizen <janneke@gnu.org>
7   
8  */
9
10 #include "auto-beam-engraver.hh"
11 #include "musical-request.hh"
12 #include "bar.hh"
13 #include "beam.hh"
14 #include "rhythmic-grouping.hh"
15 #include "rest.hh"
16 #include "stem.hh"
17 #include "debug.hh"
18 #include "time-description.hh"
19
20 ADD_THIS_TRANSLATOR (Auto_beam_engraver);
21
22 Auto_beam_engraver::Auto_beam_engraver ()
23 {
24   beam_p_ = 0;
25   mult_i_ = 0;
26   finished_beam_p_ = 0;
27   finished_grouping_p_ = 0;
28   grouping_p_ = 0;
29 }
30
31 void
32 Auto_beam_engraver::do_process_requests ()
33 {
34   consider_end_and_begin ();
35 }
36
37 void
38 Auto_beam_engraver::consider_end_and_begin ()
39 {
40   Time_description const *time = get_staff_info().time_C_;
41   int num = time->whole_per_measure_ / time->one_beat_;
42   int den = time->one_beat_.den_i ();
43   String time_str = String ("time") + to_str (num) + "_" + to_str (den);
44   int type = 1 << (mult_i_ + 2);
45   String type_str = to_str (type);
46
47   /*
48     Determine end moment for auto beaming (and begin, mostly 0==anywhere) 
49     In order of increasing priority:
50
51     i.   every beat <den>
52     ii.  time<num>_<den>beamAutoEnd
53     iii. time<num>_<den>beamAutoEnd<type>
54     iv.  beamAutoEnd
55     v.   beamAutoEnd<type>
56
57
58     Rationale:
59
60     [to be defined in config file]
61     i.   easy catch-all rule
62     ii.  exceptions for time signature
63     iii. exceptions for time signature, for specific duration type
64
65     [user override]
66     iv.  generic override
67     v.   override for specific duration type
68
69     The user overrides should be required for common cases.
70    */
71   
72   /*
73     first guess: begin beam at any position
74   */
75   Moment begin_mom (0);
76   /*
77     first guess: end beam at end of beat
78   */
79   Moment end_mom = time->one_beat_;
80
81   /*
82     second guess: property generic time exception
83   */
84   Scalar begin = get_property (time_str + "beamAutoBegin", 0);
85   if (begin.length_i ())
86     begin_mom = begin.to_rat ();
87
88   Scalar end = get_property (time_str + "beamAutoEnd", 0);
89   if (end.length_i ())
90     end_mom = end.to_rat ();
91
92   /*
93     third guess: property time exception, specific for duration type
94   */
95   if (mult_i_)
96     {
97       Scalar end_mult = get_property (time_str + "beamAutoEnd" + type_str, 0);
98       if (end_mult.length_i ())
99         end_mom = end_mult.to_rat ();
100       Scalar begin_mult = get_property (time_str + "beamAutoBegin" + type_str, 0);
101       if (begin_mult.length_i ())
102         begin_mom = begin_mult.to_rat ();
103     }
104
105   /*
106     fourth guess [user override]: property plain generic
107   */
108   begin = get_property ("beamAutoBegin", 0);
109   if (begin.length_i ())
110     begin_mom = begin.to_rat ();
111   
112   end = get_property ("beamAutoEnd", 0);
113   if (end.length_i ())
114     end_mom = end.to_rat ();
115
116   /*
117     fifth guess [user override]: property plain, specific for duration type
118   */
119   if (mult_i_)
120     {
121       Scalar end_mult = get_property (String ("beamAutoEnd") + type_str, 0);
122       if (end_mult.length_i ())
123         end_mom = end_mult.to_rat ();
124       Scalar begin_mult = get_property (String ("beamAutoBegin") + type_str, 0);
125       if (begin_mult.length_i ())
126         begin_mom = begin_mult.to_rat ();
127     }
128
129   Real f;
130   if (end_mom)
131     f = fmod (time->whole_in_measure_, end_mom);
132   else
133     f = Moment (1);
134
135   // enge floots
136   Real epsilon_f = Moment (1, 512);
137   if (beam_p_ && (abs (f) < epsilon_f))
138     end_beam ();
139      
140   /*
141     Allow already started autobeam to end
142    */
143   Scalar on = get_property ("beamAuto", 0);
144   if (!on.to_bool ())
145     return;
146
147   if (begin_mom)
148     f = fmod (time->whole_in_measure_, begin_mom);
149   if (!beam_p_ && (!begin_mom || (abs (f) < epsilon_f)))
150     begin_beam ();
151 }
152
153       
154 void
155 Auto_beam_engraver::begin_beam ()
156 {
157   DOUT << String ("starting autobeam at: ") + now_mom ().str () + "\n";
158   beam_p_ = new Beam;
159   grouping_p_ = new Rhythmic_grouping;
160
161       /* urg, copied from Beam_engraver */
162   Scalar prop = get_property ("beamslopedamping", 0);
163   if (prop.isnum_b ()) 
164     beam_p_->damping_i_ = prop;
165
166   prop = get_property ("beamquantisation", 0);
167   if (prop.isnum_b ()) 
168     beam_p_->quantisation_ = (Beam::Quantisation)(int)prop;
169  
170       // must set minVerticalAlign = = maxVerticalAlign to get sane results
171       // see input/test/beam-interstaff.ly
172   prop = get_property ("minVerticalAlign", 0);
173   if (prop.isnum_b ())
174     beam_p_->vertical_align_drul_[MIN] = prop;
175
176   prop = get_property ("maxVerticalAlign", 0);
177   if (prop.isnum_b ())
178     beam_p_->vertical_align_drul_[MAX] = prop;
179
180   announce_element (Score_element_info (beam_p_, 0));
181 }
182
183 void
184 Auto_beam_engraver::end_beam ()
185 {
186   DOUT << String ("ending autobeam at: ") + now_mom ().str () + "\n";
187   if (beam_p_->stems_.size () < 2)
188     {
189       DOUT << "junking autombeam: less than two stems\n";
190       junk_beam ();
191     }
192   else
193     {
194       finished_beam_p_ = beam_p_;
195       finished_grouping_p_ = grouping_p_;
196       beam_p_ = 0;
197       grouping_p_ = 0;
198       mult_i_ = 0;
199     }
200 }
201  
202 void
203 Auto_beam_engraver::typeset_beam ()
204 {
205   if (finished_beam_p_)
206     {
207       Rhythmic_grouping const * rg_C = get_staff_info().rhythmic_C_;
208       rg_C->extend (finished_grouping_p_->interval());
209       finished_beam_p_->set_grouping (*rg_C, *finished_grouping_p_);
210       typeset_element (finished_beam_p_);
211       finished_beam_p_ = 0;
212     
213       delete finished_grouping_p_;
214       finished_grouping_p_= 0;
215     }
216 }
217
218 void
219 Auto_beam_engraver::do_post_move_processing ()
220 {
221 }
222
223 void
224 Auto_beam_engraver::do_pre_move_processing ()
225 {
226   typeset_beam ();
227 }
228
229 void
230 Auto_beam_engraver::do_removal_processing ()
231 {
232   typeset_beam ();
233   if (beam_p_)
234     {
235       DOUT << "Unfinished beam\n";
236       junk_beam ();
237     }
238 }
239
240 void
241 Auto_beam_engraver::acknowledge_element (Score_element_info info)
242 {
243   if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
244     {
245       if (beam_p_)
246         {
247           DOUT << "junking autobeam: beam encountered\n";
248           junk_beam ();
249         }
250     }
251   if (Bar *b = dynamic_cast<Bar *> (info.elem_l_))
252     {
253       if (beam_p_)
254         {
255           DOUT << "junking autobeam: bar encountered\n";
256           junk_beam ();
257         }
258     }
259
260   if (beam_p_)
261     {
262       Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
263       if (!rhythmic_req)
264         return;
265
266       if (dynamic_cast<Rest *> (info.elem_l_))
267         {
268           DOUT << "junking autobeam: rest encountered\n";
269           end_beam ();
270           return;
271         }
272
273       Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_);
274       if (!stem_l)
275         return;
276
277       if (stem_l->beam_l_ && (stem_l->beam_l_ != beam_p_))
278         {
279           DOUT << "junking autobeam: beamed stem encountered\n";
280           junk_beam ();
281           return;
282         }
283         
284
285       /*
286         now that we have last_add_mom_, perhaps we can (should) do away
287         with these individual junk_beams
288        */
289       if (rhythmic_req->duration_.durlog_i_<= 2)
290         {
291           DOUT << "ending autobeam: stem doesn't fit in beam\n";
292           end_beam ();
293           return;
294         }
295
296       Moment start = get_staff_info().time_C_->whole_in_measure_;
297       if (!grouping_p_->child_fit_b (start))
298         {
299           DOUT << "ending autobeam: stem doesn't fit in group\n";
300           end_beam ();
301         }
302       else
303         {
304           int m = (rhythmic_req->duration_.durlog_i_ - 2);
305           /*
306             if multiplicity would become greater,
307             reconsider ending/starting beam first.
308            */
309           if (m > mult_i_)
310             {
311               mult_i_ = m;
312               consider_end_and_begin ();
313             }
314           mult_i_ = m;
315           grouping_p_->add_child (start, rhythmic_req->length_mom ());
316           stem_l->flag_i_ = rhythmic_req->duration_.durlog_i_;
317           beam_p_->add_stem (stem_l);
318           Moment now = now_mom ();
319           last_add_mom_ = now;
320           extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
321         }
322     }
323 }
324
325 void
326 Auto_beam_engraver::junk_beam () 
327 {
328   assert (beam_p_);
329   for (int i=0; i < beam_p_->stems_.size (); i++)
330     {
331       Stem* s = beam_p_->stems_[i];
332       s->beams_i_drul_[LEFT] = 0;
333       s->beams_i_drul_[RIGHT] = 0;
334       s->mult_i_ = 0;
335       s->beam_l_ = 0;
336     }
337   
338   beam_p_->unlink ();
339   beam_p_ = 0;
340   delete grouping_p_;
341   grouping_p_ = 0;
342   mult_i_ = 0;
343 }
344
345 void
346 Auto_beam_engraver::process_acknowledged ()
347 {
348   if (beam_p_)
349     {
350       Moment now = now_mom ();
351       if ((extend_mom_ < now)
352           || ((extend_mom_ == now) && (last_add_mom_ != now )))
353         {
354           DOUT << String ("junking autobeam: no stem added since: ")
355             + last_add_mom_.str () + "\n";
356           end_beam ();
357         }
358       else if (!beam_p_->stems_.size ())
359         {
360           DOUT << "junking started autobeam: no stems\n";
361           junk_beam ();
362         }
363     }
364 }