]> git.donarmstrong.com Git - lilypond.git/blob - lily/auto-beam-engraver.cc
patch::: 1.1.64.lu1
[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 #include "new-beaming.hh"
10 #include "auto-beam-engraver.hh"
11 #include "musical-request.hh"
12 #include "bar.hh"
13 #include "beam.hh"
14 #include "rest.hh"
15 #include "stem.hh"
16 #include "debug.hh"
17 #include "timing-engraver.hh"
18 #include "engraver-group-engraver.hh"
19
20 ADD_THIS_TRANSLATOR (Auto_beam_engraver);
21
22 Auto_beam_engraver::Auto_beam_engraver ()
23 {
24   stem_l_arr_p_ = 0;
25   shortest_mom_ = Moment (1, 8);
26   finished_beam_p_ = 0;
27   finished_grouping_p_ = 0;
28   grouping_p_ = 0;
29   timer_l_ =0;
30 }
31
32 void
33 Auto_beam_engraver::do_creation_processing ()
34 {
35   Translator * t = daddy_grav_l  ()->get_simple_translator ("Timing_engraver");
36   timer_l_ = dynamic_cast<Timing_engraver*> (t);
37 }
38
39 bool
40 Auto_beam_engraver::do_try_music (Music*) 
41 {
42   return false;
43
44
45 void
46 Auto_beam_engraver::do_process_requests ()
47 {
48   consider_end_and_begin (shortest_mom_);
49 }
50
51 void
52 Auto_beam_engraver::consider_end_and_begin (Moment test_mom)
53 {
54   if (!timer_l_)
55       return;
56   
57   Time_description const *time = &timer_l_->time_;
58   int num = time->whole_per_measure_ / time->one_beat_;
59   int den = time->one_beat_.den_i ();
60   String time_str = String ("time") + to_str (num) + "_" + to_str (den);
61
62   String type_str;
63   if (test_mom.num () != 1)
64     type_str = to_str (test_mom.num ());
65   if (test_mom.den () != 1)
66     type_str = type_str + "_" + to_str (test_mom.den ());
67
68   /*
69     Determine end moment for auto beaming (and begin, mostly 0==anywhere) 
70     In order of increasing priority:
71
72     i.   every beat <den>
73     ii.  time<num>_<den>beamAutoEnd
74     iii. time<num>_<den>beamAutoEnd<type>
75     iv.  beamAutoEnd
76     v.   beamAutoEnd<type>
77
78
79     Rationale:
80
81     [to be defined in config file]
82     i.   easy catch-all rule
83     ii.  exceptions for time signature
84     iii. exceptions for time signature, for specific duration type
85
86     [user override]
87     iv.  generic override
88     v.   override for specific duration type
89
90     The user overrides should be required for common cases.
91    */
92   
93   /*
94     first guess: begin beam at any position
95   */
96   Moment begin_mom (0);
97   /*
98     first guess: end beam at end of beat
99   */
100   Moment end_mom = time->one_beat_;
101
102   /*
103     second guess: property generic time exception
104   */
105   Scalar begin = get_property (time_str + "beamAutoBegin", 0);
106   if (begin.length_i ())
107     begin_mom = begin.to_rat ();
108
109   Scalar end = get_property (time_str + "beamAutoEnd", 0);
110   if (end.length_i ())
111     end_mom = end.to_rat ();
112
113   /*
114     third guess: property time exception, specific for duration type
115   */
116   if (type_str.length_i ())
117     {
118       Scalar end_mult = get_property (time_str + "beamAutoEnd" + type_str, 0);
119       if (end_mult.length_i ())
120         end_mom = end_mult.to_rat ();
121       Scalar begin_mult = get_property (time_str + "beamAutoBegin" + type_str, 0);
122       if (begin_mult.length_i ())
123         begin_mom = begin_mult.to_rat ();
124     }
125
126   /*
127     fourth guess [user override]: property plain generic
128   */
129   begin = get_property ("beamAutoBegin", 0);
130   if (begin.length_i ())
131     begin_mom = begin.to_rat ();
132   
133   end = get_property ("beamAutoEnd", 0);
134   if (end.length_i ())
135     end_mom = end.to_rat ();
136
137   /*
138     fifth guess [user override]: property plain, specific for duration type
139   */
140   if (type_str.length_i ())
141     {
142       Scalar end_mult = get_property (String ("beamAutoEnd") + type_str, 0);
143       if (end_mult.length_i ())
144         end_mom = end_mult.to_rat ();
145       Scalar begin_mult = get_property (String ("beamAutoBegin") + type_str, 0);
146       if (begin_mult.length_i ())
147         begin_mom = begin_mult.to_rat ();
148     }
149
150   Rational r;
151   if (end_mom)
152     r = time->whole_in_measure_.mod_rat (end_mom);
153   else
154     r = Moment (1);
155
156   if (stem_l_arr_p_ && !r)
157     end_beam ();
158      
159   /*
160     Allow already started autobeam to end
161    */
162   Scalar on = get_property ("beamAuto", 0);
163   if (!on.to_bool ())
164     return;
165
166   if (begin_mom)
167     r = time->whole_in_measure_.mod_rat (begin_mom);
168   if (!stem_l_arr_p_ && (!begin_mom || !r))
169     begin_beam ();
170 }
171
172       
173 void
174 Auto_beam_engraver::begin_beam ()
175 {
176   assert (!stem_l_arr_p_);
177   stem_l_arr_p_ = new Array<Stem*>;
178   assert (!grouping_p_);
179   grouping_p_ = new Beaming_info_list;
180   beam_start_moment_ = now_mom ();
181   beam_start_location_ = timer_l_->time_.whole_in_measure_;
182 }
183
184 Beam*
185 Auto_beam_engraver::create_beam_p ()
186 {
187   Beam* beam_p = new Beam;
188
189   for (int i = 0; i < stem_l_arr_p_->size (); i++)
190     beam_p->add_stem ((*stem_l_arr_p_)[i]);
191
192   /* urg, copied from Beam_engraver */
193   Scalar prop = get_property ("beamslopedamping", 0);
194   if (prop.isnum_b ()) 
195     beam_p->set_elt_property (damping_scm_sym, gh_int2scm( prop));
196
197   prop = get_property ("beamquantisation", 0);
198   if (prop.isnum_b ()) 
199     beam_p->quantisation_ = (Beam::Quantisation)(int)prop;
200  
201   announce_element (Score_element_info (beam_p, 0));
202   return beam_p;
203 }
204
205 void
206 Auto_beam_engraver::end_beam ()
207 {
208   if (stem_l_arr_p_->size () < 2)
209     {
210       junk_beam ();
211     }
212   else
213     {
214       finished_beam_p_ = create_beam_p ();
215       finished_grouping_p_ = grouping_p_;
216       delete stem_l_arr_p_;
217       stem_l_arr_p_ = 0;
218       grouping_p_ = 0;
219       shortest_mom_ = Moment (1, 8);
220     }
221 }
222  
223 void
224 Auto_beam_engraver::typeset_beam ()
225 {
226   if (finished_beam_p_)
227     {
228       finished_grouping_p_->beamify ();
229       finished_beam_p_->set_beaming (finished_grouping_p_);
230       typeset_element (finished_beam_p_);
231       finished_beam_p_ = 0;
232     
233       delete finished_grouping_p_;
234       finished_grouping_p_= 0;
235     }
236 }
237
238 void
239 Auto_beam_engraver::do_post_move_processing ()
240 {
241   /*
242     don't beam over skips
243    */
244   if (stem_l_arr_p_)
245     {
246       Moment now = now_mom ();
247       if (extend_mom_ < now)
248         {
249           end_beam ();
250         }
251     }
252 }
253
254 void
255 Auto_beam_engraver::do_pre_move_processing ()
256 {
257   typeset_beam ();
258 }
259
260 void
261 Auto_beam_engraver::do_removal_processing ()
262 {
263   /* finished beams may be typeset */
264   typeset_beam ();
265   /* but unfinished may need another announce/acknoledge pass */
266   if (stem_l_arr_p_)
267     junk_beam ();
268 }
269
270 bool
271 Auto_beam_engraver::same_grace_state_b (Score_element* e)
272 {
273   bool gr = (e->get_elt_property (grace_scm_sym) != SCM_BOOL_F) ;
274
275   return gr == get_property ("weAreGraceContext",0).to_bool ();
276 }
277
278 void
279 Auto_beam_engraver::acknowledge_element (Score_element_info info)
280 {
281   if (!same_grace_state_b (info.elem_l_) || !timer_l_)
282     return;
283   
284   if (stem_l_arr_p_)
285     {
286       if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
287         {
288           junk_beam ();
289         }
290       else if (Bar *b = dynamic_cast<Bar *> (info.elem_l_))
291         {
292           junk_beam ();
293         }
294       else if (Rest* rest_l = dynamic_cast<Rest *> (info.elem_l_))
295         {
296           end_beam ();
297         }
298     }
299   
300   if (Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_))
301     {
302       Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
303       if (!rhythmic_req)
304         {
305           programming_error ("Stem must have rhythmic structure");
306           return;
307         }
308       
309       /*
310         Don't (start) auto-beam over empty stems; skips or rests
311         */
312       if (!stem_l->head_l_arr_.size ())
313         {
314           if (stem_l_arr_p_)
315             end_beam ();
316           return;
317         }
318
319       if (stem_l->beam_l_)
320         {
321           if (stem_l_arr_p_)
322             junk_beam ();
323           return ;
324         }
325               
326       int durlog  =rhythmic_req->duration_.durlog_i_;
327       if (durlog <= 2)
328         {
329           if (stem_l_arr_p_)
330             end_beam ();
331           return;
332         }
333
334       /*
335         if shortest duration would change
336         reconsider ending/starting beam first.
337       */
338       Moment mom = rhythmic_req->duration_.length_mom ();
339       consider_end_and_begin (mom);
340       if (!stem_l_arr_p_)
341         return;
342       if (mom < shortest_mom_)
343         {
344           if (stem_l_arr_p_->size ())
345             {
346               shortest_mom_ = mom;
347               consider_end_and_begin (shortest_mom_);
348               if (!stem_l_arr_p_)
349                 return;
350             }
351           shortest_mom_ = mom;
352         }
353       Moment now = now_mom ();
354       
355       grouping_p_->add_stem (now - beam_start_moment_ + beam_start_location_,
356                              durlog - 2);
357       stem_l_arr_p_->push (stem_l);
358       last_add_mom_ = now;
359       extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
360     }
361 }
362
363 void
364 Auto_beam_engraver::junk_beam () 
365 {
366   assert (stem_l_arr_p_);
367   
368   delete stem_l_arr_p_;
369   stem_l_arr_p_ = 0;
370   delete grouping_p_;
371   grouping_p_ = 0;
372   shortest_mom_ = Moment (1, 8);
373 }
374
375 void
376 Auto_beam_engraver::process_acknowledged ()
377 {
378   if (stem_l_arr_p_)
379     {
380       Moment now = now_mom ();
381       if ((extend_mom_ < now)
382           || ((extend_mom_ == now) && (last_add_mom_ != now )))
383         {
384           end_beam ();
385         }
386       else if (!stem_l_arr_p_->size ())
387         {
388           junk_beam ();
389         }
390     }
391 }