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