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