]> git.donarmstrong.com Git - lilypond.git/blob - lily/beam-engraver.cc
release: 1.5.30
[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   Drul_array<Span_req*> reqs_drul_;
25   
26   Spanner *finished_beam_p_;
27   Spanner *beam_p_;
28   Span_req * prev_start_req_;
29
30   Beaming_info_list * beam_info_p_;
31   Beaming_info_list * finished_beam_info_p_;  
32
33   /// location  within measure where beam started.
34   Moment beam_start_location_;
35
36   /// moment (global time) where beam started.
37   Moment beam_start_mom_;
38
39   bool subdivide_beams_;
40
41   void typeset_beam ();
42   void set_melisma (bool);
43 protected:
44   virtual void stop_translation_timestep ();
45   virtual void start_translation_timestep ();
46   virtual void finalize ();
47
48   virtual void acknowledge_grob (Grob_info);
49   virtual bool try_music (Music*);
50   virtual void process_music ();
51
52 public:
53   TRANSLATOR_DECLARATIONS(  Beam_engraver );
54 };
55
56
57 Beam_engraver::Beam_engraver ()
58 {
59   beam_p_ = 0;
60   finished_beam_p_ =0;
61   finished_beam_info_p_=0;
62   beam_info_p_ =0;
63   reqs_drul_[LEFT] = reqs_drul_[RIGHT] =0;
64   prev_start_req_ =0;
65   
66 }
67
68 bool
69 Beam_engraver::try_music (Music *m)
70 {
71   if (Span_req * c = dynamic_cast<Span_req*> (m))
72     {
73       if (scm_equal_p (c->get_mus_property ("span-type"),
74                        ly_str02scm ("abort")) == SCM_BOOL_T)
75         {
76           reqs_drul_[START] = 0;
77           reqs_drul_[STOP] = 0;
78           if (beam_p_)
79             beam_p_->suicide ();
80           beam_p_ = 0;
81         }
82       else if (scm_equal_p (c->get_mus_property ("span-type"),
83                        ly_str02scm ("beam")) == SCM_BOOL_T)
84         {
85       
86           Direction d =c->get_span_dir ();
87
88           if (d == STOP)
89             {
90               SCM m = get_property ("automaticMelismata");
91               SCM b = get_property ("noAutoBeaming");
92               if (to_boolean (m) && to_boolean (b))
93                 {
94                   set_melisma (false);
95                 }
96             }
97
98           reqs_drul_[d ] = c;
99           return true;
100         }
101     }
102   return false;
103 }
104
105 void
106 Beam_engraver::set_melisma (bool m)
107 {
108   daddy_trans_l_->set_property ("beamMelismaBusy", m ? SCM_BOOL_T :SCM_BOOL_F);
109 }
110
111 void
112 Beam_engraver::process_music ()
113 {
114   if (reqs_drul_[STOP])
115     {
116       if (!beam_p_)
117         reqs_drul_[STOP]->origin ()->warning (_ ("can't find start of beam"));
118       prev_start_req_ =0;
119       finished_beam_p_ = beam_p_;
120       finished_beam_info_p_ = beam_info_p_;
121
122       beam_info_p_ =0;
123       beam_p_ = 0;
124     }
125
126
127   if (beam_p_)
128     {
129       top_engraver ()->forbid_breaks ();
130     }
131   if (reqs_drul_[START])
132     {
133       if (beam_p_)
134         {
135           reqs_drul_[START]->origin ()->warning (_ ("already have a beam"));
136           return;
137         }
138
139       prev_start_req_ = reqs_drul_[START];
140       beam_p_ = new Spanner (get_property ("Beam"));
141       SCM smp = get_property ("measurePosition");
142       Moment mp = (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
143
144       beam_start_location_ = mp;
145       beam_start_mom_ = now_mom ();
146       
147       beam_info_p_ = new Beaming_info_list;
148       
149       /* urg, must copy to Auto_beam_engraver too */
150  
151       announce_grob(beam_p_, reqs_drul_[START]->self_scm());
152     }
153
154 }
155
156
157 void
158 Beam_engraver::typeset_beam ()
159 {
160   if (finished_beam_p_)
161     {
162       finished_beam_info_p_->beamify(*unsmob_moment (get_property ("beatLength")),
163                                      subdivide_beams_);
164
165       Beam::set_beaming (finished_beam_p_, finished_beam_info_p_);
166       typeset_grob (finished_beam_p_);
167       delete finished_beam_info_p_;
168       finished_beam_info_p_ =0;
169       finished_beam_p_ = 0;
170     }
171 }
172
173 void
174 Beam_engraver::start_translation_timestep ()
175 {
176   reqs_drul_ [START] =0;
177   reqs_drul_[STOP] = 0;
178   
179   if (beam_p_)
180     {
181       SCM m = get_property ("automaticMelismata");
182       SCM b = get_property ("noAutoBeaming");
183       if (to_boolean (m) && to_boolean (b))
184         {
185           set_melisma (true);
186         }
187       subdivide_beams_ = to_boolean(get_property("subdivideBeams")); 
188     }
189 }
190
191 void
192 Beam_engraver::stop_translation_timestep ()
193 {
194   typeset_beam ();
195 }
196
197 void
198 Beam_engraver::finalize ()
199 {
200   typeset_beam ();
201   if (beam_p_)
202     {
203       prev_start_req_->origin ()->warning (_ ("unterminated beam"));
204
205       /*
206         we don't typeset it, (we used to, but it was commented
207         out. Reason unknown) */
208       beam_p_->suicide ();
209       delete beam_info_p_;
210     }
211 }
212
213 void
214 Beam_engraver::acknowledge_grob (Grob_info info)
215 {
216   if (beam_p_)
217     {
218       if (Rest::has_interface (info.grob_l_))
219         {
220           info.grob_l_->add_offset_callback (Beam::rest_collision_callback_proc, Y_AXIS);
221         }
222       else if (Stem::has_interface (info.grob_l_))
223         {
224           Moment now = now_mom();
225
226           if(bool (now.grace_part_ ) != bool (beam_start_mom_.grace_part_))
227             return ;
228           
229           Item *stem_l = dynamic_cast<Item*> (info.grob_l_);
230           if (Stem::beam_l (stem_l))
231             return;
232
233           Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.music_cause ());
234           if (!rhythmic_req)
235             {
236               String s = _ ("stem must have Rhythmic structure");
237               if (info.music_cause ())
238                 info.music_cause ()->origin ()->warning (s);
239               else
240                 ::warning (s);
241           
242               return;
243             }
244
245       int durlog  = unsmob_duration (rhythmic_req->get_mus_property ("duration"))-> duration_log ();
246           if (durlog <= 2)
247             {
248               rhythmic_req->origin ()->warning (_ ("stem doesn't fit in beam"));
249               prev_start_req_->origin ()->warning (_ ("beam was started here"));
250               /*
251                 don't return, since
252
253                 [r4 c8] can just as well be modern notation.
254               */
255             }
256
257           stem_l->set_grob_property ("duration-log",
258                                     gh_int2scm (durlog));
259           Moment stem_location = now - beam_start_mom_ + beam_start_location_;
260           beam_info_p_->add_stem (stem_location,
261  (durlog- 2) >? 1);
262           Beam::add_stem (beam_p_, stem_l);
263         }
264     }
265 }
266
267
268
269
270
271 ENTER_DESCRIPTION(Beam_engraver,
272 /* descr */       "Handles Beam_requests by engraving Beams.    If omitted, then notes will be
273 printed with flags instead of beams.",
274 /* creats*/       "Beam",
275 /* acks  */       "stem-interface rest-interface",
276 /* reads */       "beamMelismaBusy subdivideBeams",
277 /* write */       "");