]> git.donarmstrong.com Git - lilypond.git/blob - lily/beam-engraver.cc
patch::: 1.3.108.jcn3
[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--2000 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   void typeset_beam ();
40   void set_melisma (bool);
41 protected:
42   virtual void do_pre_move_processing ();
43   virtual void do_post_move_processing ();
44   virtual void do_removal_processing ();
45   virtual void process_acknowledged ();
46   virtual void acknowledge_element (Score_element_info);
47   virtual bool do_try_music (Music*);
48   void deprecated_process_music ();
49 public:
50   Beam_engraver ();
51   VIRTUAL_COPY_CONS (Translator);
52 };
53
54
55 Beam_engraver::Beam_engraver ()
56 {
57   beam_p_ = 0;
58   finished_beam_p_ =0;
59   finished_beam_info_p_=0;
60   beam_info_p_ =0;
61   reqs_drul_[LEFT] = reqs_drul_[RIGHT] =0;
62   prev_start_req_ =0;
63 }
64
65 bool
66 Beam_engraver::do_try_music (Music *m)
67 {
68   if (Span_req * c = dynamic_cast<Span_req*>(m))
69     {
70       if (scm_equal_p (c->get_mus_property ("span-type"),
71                        ly_str02scm ("abort")) == SCM_BOOL_T)
72         {
73           reqs_drul_[START] = 0;
74           reqs_drul_[STOP] = 0;
75           if (beam_p_)
76             beam_p_->suicide ();
77           beam_p_ = 0;
78         }
79       else if (scm_equal_p (c->get_mus_property ("span-type"),
80                        ly_str02scm ("beam")) == SCM_BOOL_T)
81         {
82       
83           Direction d =c->get_span_dir ();
84
85           if (d == STOP && !beam_p_)
86             {
87               m->origin ()->warning  (_ ("can't find start of beam"));
88               return false;
89             }
90
91           if(d == STOP)
92             {
93               SCM m = get_property ("automaticMelismata");
94               SCM b = get_property("noAutoBeaming");
95               if (to_boolean (m) && to_boolean(b))
96                 {
97                   set_melisma (false);
98                 }
99             }
100
101           reqs_drul_[d ] = c;
102           return true;
103         }
104     }
105   return false;
106 }
107
108 void
109 Beam_engraver::set_melisma (bool m)
110 {
111   daddy_trans_l_->set_property ("beamMelismaBusy", m ? SCM_BOOL_T :SCM_BOOL_F);
112 }
113
114
115 void
116 Beam_engraver::deprecated_process_music ()
117 {
118   if (reqs_drul_[STOP])
119     {
120       if (!beam_p_)
121         reqs_drul_[STOP]->origin ()->warning (_("can't find start of beam"));
122       prev_start_req_ =0;
123       finished_beam_p_ = beam_p_;
124       finished_beam_info_p_ = beam_info_p_;
125
126       beam_info_p_ =0;
127       beam_p_ = 0;
128     }
129
130
131   if (beam_p_  &&  !to_boolean (get_property ("weAreGraceContext")))
132     {
133       Score_engraver * e = 0;
134       Translator * t  =  daddy_grav_l ();
135       for (; !e && t;  t = t->daddy_trans_l_)
136         {
137           e = dynamic_cast<Score_engraver*> (t);
138         }
139       
140       if (!e)
141         programming_error ("No score engraver!");
142       else
143         e->forbid_breaks ();
144     }
145   
146   if (reqs_drul_[START])
147     {
148       if (beam_p_)
149         {
150           reqs_drul_[START]->origin ()->warning (_ ("already have a beam"));
151           return;
152         }
153
154       prev_start_req_ = reqs_drul_[START];
155       beam_p_ = new Spanner (get_property ("Beam"));
156       Beam::set_interface (beam_p_);
157       
158       SCM smp = get_property ("measurePosition");
159       Moment mp =  (unsmob_moment (smp)) ? *unsmob_moment (smp) : Moment (0);
160
161       beam_start_location_ = mp;
162       beam_start_mom_ = now_mom();
163       beam_info_p_ = new Beaming_info_list;
164       
165       
166       /* urg, must copy to Auto_beam_engraver too */
167  
168       announce_element (beam_p_, reqs_drul_[START]);
169     }
170   reqs_drul_[STOP] = 0;
171   reqs_drul_[START] = 0;
172 }
173
174 void
175 Beam_engraver::typeset_beam ()
176 {
177   if (finished_beam_p_)
178     {
179       finished_beam_info_p_->beamify ();
180       
181       Beam::set_beaming (finished_beam_p_, finished_beam_info_p_);
182       typeset_element (finished_beam_p_);
183       delete finished_beam_info_p_;
184       finished_beam_info_p_ =0;
185       finished_beam_p_ = 0;
186     
187       reqs_drul_[STOP] = 0;
188     }
189 }
190
191 void
192 Beam_engraver::do_post_move_processing ()
193 {
194   reqs_drul_ [START] =0;
195   if(beam_p_) {
196     SCM m = get_property ("automaticMelismata");
197     SCM b = get_property("noAutoBeaming");
198     if (to_boolean (m) && to_boolean(b)) {
199       set_melisma (true);
200     }
201   }
202 }
203
204 void
205 Beam_engraver::do_pre_move_processing ()
206 {
207   typeset_beam ();
208 }
209
210 void
211 Beam_engraver::do_removal_processing ()
212 {
213   typeset_beam ();
214   if (beam_p_)
215     {
216       prev_start_req_->origin ()->warning (_ ("unterminated beam"));
217 #if 0
218       finished_beam_p_ = beam_p_;
219       finished_beam_info_p_ = beam_info_p_;
220       typeset_beam ();
221 #else
222       beam_p_->suicide ();
223       delete beam_info_p_;
224 #endif
225     }
226 }
227
228 void
229 Beam_engraver::process_acknowledged ()
230 {
231   deprecated_process_music ();
232 }
233
234
235 void
236 Beam_engraver::acknowledge_element (Score_element_info info)
237 {
238   if (beam_p_)
239     {
240       if (Rest::has_interface (info.elem_l_))
241         {
242           info.elem_l_->add_offset_callback (Beam::rest_collision_callback_proc, Y_AXIS);
243         }
244       else if (Stem::has_interface (info.elem_l_))
245         {
246           Item *stem_l = dynamic_cast<Item*> (info.elem_l_);
247           if (Stem::beam_l (stem_l))
248             return;
249
250           bool stem_grace = stem_l->get_elt_property ("grace") == SCM_BOOL_T;
251
252           SCM wg =get_property ("weAreGraceContext");
253           bool wgb= to_boolean (wg);
254
255           if (wgb!= stem_grace)
256             return;
257
258           Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
259           if (!rhythmic_req)
260             {
261               String s = _ ("stem must have Rhythmic structure");
262               if (info.req_l_)
263                 info.req_l_->origin ()->warning (s);
264               else
265                 ::warning (s);
266           
267               return;
268             }
269
270       int durlog  = unsmob_duration (rhythmic_req->get_mus_property ("duration"))-> duration_log ();
271           if (durlog <= 2)
272             {
273               rhythmic_req->origin ()->warning (_ ("stem doesn't fit in beam"));
274               prev_start_req_->origin ()->warning (_ ("beam was started here"));
275               /*
276                 don't return, since
277
278                 [r4 c8] can just as well be modern notation.
279               */
280             }
281
282           stem_l->set_elt_property ("duration-log",
283                                     gh_int2scm (durlog));
284           Moment stem_location = now_mom () - beam_start_mom_ + beam_start_location_;
285           beam_info_p_->add_stem (stem_location,
286                                   (durlog- 2) >? 1);
287           Beam::add_stem (beam_p_, stem_l);
288         }
289     }
290 }
291
292
293
294 ADD_THIS_TRANSLATOR(Beam_engraver);
295