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