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