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