]> git.donarmstrong.com Git - lilypond.git/blob - lily/beam-engraver.cc
nested grace beams
[lilypond.git] / lily / beam-engraver.cc
1 /*   
2   beam-engraver.cc --  implement Beam_engraver
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 1998--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9 #include "engraver-group-engraver.hh"
10 #include "engraver.hh"
11 #include "musical-request.hh"
12 #include "beam.hh"
13 #include "stem.hh"
14 #include "warn.hh"
15 #include "beaming.hh"
16 #include "score-engraver.hh"
17 #include "rest.hh"
18 #include "drul-array.hh"
19 #include "item.hh"
20 #include "spanner.hh"
21
22 class Beam_engraver : public Engraver
23 {
24 protected:  
25   Drul_array<Span_req*> reqs_drul_;
26   
27   Spanner *finished_beam_p_;
28   Spanner *beam_p_;
29   Span_req * prev_start_req_;
30
31   Beaming_info_list * beam_info_p_;
32   Beaming_info_list * finished_beam_info_p_;  
33
34   /// location  within measure where beam started.
35   Moment beam_start_location_;
36
37   /// moment (global time) where beam started.
38   Moment beam_start_mom_;
39
40   bool subdivide_beams_;
41
42   void typeset_beam ();
43   void set_melisma (bool);
44
45   Moment last_stem_added_at_;
46   
47
48
49   virtual void stop_translation_timestep ();
50   virtual void start_translation_timestep ();
51   virtual void finalize ();
52
53   virtual void acknowledge_grob (Grob_info);
54   virtual bool try_music (Music*);
55   virtual void process_music ();
56
57   virtual bool valid_start_moment();
58   virtual bool valid_end_moment ();
59   
60 public:
61   TRANSLATOR_DECLARATIONS(  Beam_engraver );
62 };
63
64
65
66 bool
67 Beam_engraver::valid_start_moment()
68 {
69   Moment n = now_mom ();
70
71   return n.grace_part_ == Rational (0);
72 }
73
74 bool
75 Beam_engraver::valid_end_moment()
76 {
77   return last_stem_added_at_.grace_part_ == Rational(0);
78 }
79
80
81 Beam_engraver::Beam_engraver ()
82 {
83   beam_p_ = 0;
84   finished_beam_p_ =0;
85   finished_beam_info_p_=0;
86   beam_info_p_ =0;
87   reqs_drul_[LEFT] = reqs_drul_[RIGHT] =0;
88   prev_start_req_ =0;
89   
90 }
91
92 bool
93 Beam_engraver::try_music (Music *m)
94 {
95   if (Span_req * c = dynamic_cast<Span_req*> (m))
96     {
97       if (scm_equal_p (c->get_mus_property ("span-type"),
98                        ly_str02scm ("abort")) == SCM_BOOL_T)
99         {
100           reqs_drul_[START] = 0;
101           reqs_drul_[STOP] = 0;
102           if (beam_p_)
103             beam_p_->suicide ();
104           beam_p_ = 0;
105         }
106       else if (scm_equal_p (c->get_mus_property ("span-type"),
107                             ly_str02scm ("beam")) == SCM_BOOL_T)
108         {
109           Direction d =c->get_span_dir ();
110
111
112           if (d == STOP && !valid_end_moment())
113             return false;
114
115           if (d == START && !valid_start_moment ())
116             return false;
117           
118           if (d == STOP)
119             {
120               SCM m = get_property ("automaticMelismata");
121               SCM b = get_property ("autoBeaming");
122               if (to_boolean (m) && !to_boolean (b))
123                 {
124                   set_melisma (false);
125                 }
126             }
127
128           reqs_drul_[d ] = c;
129           return true;
130         }
131     }
132   return false;
133 }
134
135 void
136 Beam_engraver::set_melisma (bool m)
137 {
138   daddy_trans_l_->set_property ("beamMelismaBusy", m ? SCM_BOOL_T :SCM_BOOL_F);
139 }
140
141 void
142 Beam_engraver::process_music ()
143 {
144   if (reqs_drul_[STOP])
145     {
146       prev_start_req_ =0;
147       finished_beam_p_ = beam_p_;
148       finished_beam_info_p_ = beam_info_p_;
149
150       beam_info_p_ =0;
151       beam_p_ = 0;
152     }
153
154
155   if (beam_p_)
156     {
157       top_engraver ()->forbid_breaks ();
158     }
159   if (reqs_drul_[START])
160     {
161       if (beam_p_)
162         {
163           reqs_drul_[START]->origin ()->warning (_ ("already have a beam"));
164           return;
165         }
166
167       prev_start_req_ = reqs_drul_[START];
168       beam_p_ = new Spanner (get_property ("Beam"));
169       SCM smp = get_property ("measurePosition");
170       Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
171
172       beam_start_location_ = mp;
173       beam_start_mom_ = now_mom ();
174       
175       beam_info_p_ = new Beaming_info_list;
176       
177       /* urg, must copy to Auto_beam_engraver too */
178  
179       announce_grob(beam_p_, reqs_drul_[START]->self_scm());
180     }
181
182 }
183
184
185 void
186 Beam_engraver::typeset_beam ()
187 {
188   if (finished_beam_p_)
189     {
190       finished_beam_info_p_->beamify(*unsmob_moment (get_property ("beatLength")),
191                                      subdivide_beams_);
192
193       Beam::set_beaming (finished_beam_p_, finished_beam_info_p_);
194       typeset_grob (finished_beam_p_);
195       delete finished_beam_info_p_;
196       finished_beam_info_p_ =0;
197       finished_beam_p_ = 0;
198     }
199 }
200
201 void
202 Beam_engraver::start_translation_timestep ()
203 {
204   reqs_drul_ [START] =0;
205   reqs_drul_[STOP] = 0;
206   
207   if (beam_p_)
208     {
209       SCM m = get_property ("automaticMelismata");
210       SCM b = get_property ("autoBeaming");
211       if (to_boolean (m) && !to_boolean (b))
212         {
213           set_melisma (true);
214         }
215       subdivide_beams_ = to_boolean(get_property("subdivideBeams")); 
216     }
217 }
218
219 void
220 Beam_engraver::stop_translation_timestep ()
221 {
222   typeset_beam ();
223 }
224
225 void
226 Beam_engraver::finalize ()
227 {
228   typeset_beam ();
229   if (beam_p_)
230     {
231       prev_start_req_->origin ()->warning (_ ("unterminated beam"));
232
233       /*
234         we don't typeset it, (we used to, but it was commented
235         out. Reason unknown) */
236       beam_p_->suicide ();
237       delete beam_info_p_;
238     }
239 }
240
241 void
242 Beam_engraver::acknowledge_grob (Grob_info info)
243 {
244   if (beam_p_)
245     {
246       if (Rest::has_interface (info.grob_l_))
247         {
248           info.grob_l_->add_offset_callback (Beam::rest_collision_callback_proc, Y_AXIS);
249         }
250       else if (Stem::has_interface (info.grob_l_))
251         {
252           Moment now = now_mom();
253
254           if (!valid_start_moment ())
255             return ;
256           
257           Item *stem_l = dynamic_cast<Item*> (info.grob_l_);
258           if (Stem::beam_l (stem_l))
259             return;
260
261           Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.music_cause ());
262           if (!rhythmic_req)
263             {
264               String s = _ ("stem must have Rhythmic structure");
265               if (info.music_cause ())
266                 info.music_cause ()->origin ()->warning (s);
267               else
268                 ::warning (s);
269           
270               return;
271             }
272
273
274           last_stem_added_at_ = now;
275           int durlog  = unsmob_duration (rhythmic_req->get_mus_property ("duration"))-> duration_log ();
276           if (durlog <= 2)
277             {
278               rhythmic_req->origin ()->warning (_ ("stem doesn't fit in beam"));
279               prev_start_req_->origin ()->warning (_ ("beam was started here"));
280               /*
281                 don't return, since
282
283                 [r4 c8] can just as well be modern notation.
284               */
285             }
286
287           stem_l->set_grob_property ("duration-log",
288                                     gh_int2scm (durlog));
289           Moment stem_location = now - beam_start_mom_ + beam_start_location_;
290           beam_info_p_->add_stem (stem_location,
291  (durlog- 2) >? 0);
292           Beam::add_stem (beam_p_, stem_l);
293         }
294     }
295 }
296
297
298
299
300
301 ENTER_DESCRIPTION(Beam_engraver,
302 /* descr */       "Handles Beam_requests by engraving Beams.    If omitted, then notes will be
303 printed with flags instead of beams.",
304 /* creats*/       "Beam",
305 /* acks  */       "stem-interface rest-interface",
306 /* reads */       "beamMelismaBusy subdivideBeams",
307 /* write */       "");
308
309
310 class Grace_beam_engraver : public Beam_engraver
311 {
312 public:
313   TRANSLATOR_DECLARATIONS(Grace_beam_engraver);  
314
315 protected:
316   virtual bool valid_start_moment();
317   virtual bool valid_end_moment ();
318 };
319
320 Grace_beam_engraver::Grace_beam_engraver()
321 {
322 }
323
324 bool
325 Grace_beam_engraver::valid_start_moment()
326 {
327   Moment n = now_mom ();
328
329   return n.grace_part_ != Rational (0);
330 }
331
332
333 bool
334 Grace_beam_engraver::valid_end_moment ()
335 {
336   return beam_p_ && last_stem_added_at_.grace_part_ != Rational(0);
337 }
338
339
340
341 ENTER_DESCRIPTION(Grace_beam_engraver,
342 /* descr */       "Handles Beam_requests by engraving Beams.  If omitted, then notes will
343 be printed with flags instead of beams. Only engraves beams when we
344 are at grace points in time.
345 ",
346 /* creats*/       "Beam",
347 /* acks  */       "stem-interface rest-interface",
348 /* reads */       "beamMelismaBusy subdivideBeams",
349 /* write */       "");
350