]> git.donarmstrong.com Git - lilypond.git/blob - lily/auto-beam-engraver.cc
patch::: 1.1.24.jcn2: jcn2
[lilypond.git] / lily / auto-beam-engraver.cc
1 /*   
2   auto-beam-engraver.cc --  implement Auto_beam_engraver
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 1999 Jan Nieuwenhuizen <janneke@gnu.org>
7   
8  */
9
10 #include "auto-beam-engraver.hh"
11 #include "musical-request.hh"
12 #include "bar.hh"
13 #include "beam.hh"
14 #include "grouping.hh"
15 #include "rest.hh"
16 #include "stem.hh"
17 #include "debug.hh"
18 #include "time-description.hh"
19
20 ADD_THIS_TRANSLATOR (Auto_beam_engraver);
21
22 Auto_beam_engraver::Auto_beam_engraver ()
23 {
24   beam_p_ = 0;
25   finished_beam_p_ = 0;
26   finished_grouping_p_ = 0;
27   grouping_p_ = 0;
28 }
29
30 void
31 Auto_beam_engraver::do_process_requests ()
32 {
33   consider_end_and_begin ();
34 }
35
36 void
37 Auto_beam_engraver::consider_end_and_begin ()
38 {
39   Time_description const *time = get_staff_info().time_C_;
40
41   Scalar begin = get_property ("beamAutoBegin", 0);
42   Moment begin_mom = begin.to_rat ();
43   
44   Scalar end = get_property ("beamAutoEnd", 0);
45   Moment end_mom = end.to_rat ();
46
47   if (mult_i_)
48     {
49       int type = 1 << (mult_i_ + 2);
50       Scalar end_mult = get_property (String ("beamAutoEnd")
51                                       + to_str (type), 0);
52       if (end_mult.length_i ())
53         end_mom = end_mult.to_rat ();
54       else if (Moment (type, 4) / end_mom > Moment (4))
55         end_mom /= Moment (type, 8);
56     }
57
58   Real f;
59   if (end_mom)
60     f = fmod (time->whole_in_measure_, end_mom);
61   else
62     f = Moment (1);
63
64   // enge floots
65   Real epsilon_f = Moment (1, 512);
66   if (beam_p_ && (abs (f) < epsilon_f))
67     end_beam ();
68      
69   /*
70     Allow already started autobeam to end
71    */
72   Scalar on = get_property ("beamAuto", 0);
73   if (!on.to_bool ())
74     return;
75
76   if (begin_mom)
77     f = fmod (time->whole_in_measure_, begin_mom);
78   if (!beam_p_ && (!begin_mom || (abs (f) < epsilon_f)))
79     begin_beam ();
80 }
81
82       
83 void
84 Auto_beam_engraver::begin_beam ()
85 {
86   DOUT << String ("starting autobeam at: ") + now_moment ().str () + "\n";
87   beam_p_ = new Beam;
88   grouping_p_ = new Rhythmic_grouping;
89
90       /* urg, copied from Beam_engraver */
91   Scalar prop = get_property ("beamslopedamping", 0);
92   if (prop.isnum_b ()) 
93     beam_p_->damping_i_ = prop;
94
95   prop = get_property ("beamquantisation", 0);
96   if (prop.isnum_b ()) 
97     beam_p_->quantisation_ = (Beam::Quantisation)(int)prop;
98  
99       // must set minVerticalAlign = = maxVerticalAlign to get sane results
100       // see input/test/beam-interstaff.ly
101   prop = get_property ("minVerticalAlign", 0);
102   if (prop.isnum_b ())
103     beam_p_->vertical_align_drul_[MIN] = prop;
104
105   prop = get_property ("maxVerticalAlign", 0);
106   if (prop.isnum_b ())
107     beam_p_->vertical_align_drul_[MAX] = prop;
108
109   announce_element (Score_element_info (beam_p_, 0));
110 }
111
112 void
113 Auto_beam_engraver::end_beam ()
114 {
115   DOUT << String ("ending autobeam at: ") + now_moment ().str () + "\n";
116   if (beam_p_->stems_.size () < 2)
117     {
118       DOUT << "junking autombeam: less than two stems\n";
119       junk_beam ();
120     }
121   else
122     {
123       finished_beam_p_ = beam_p_;
124       finished_grouping_p_ = grouping_p_;
125       beam_p_ = 0;
126       grouping_p_ = 0;
127       mult_i_ = 0;
128     }
129 }
130  
131 void
132 Auto_beam_engraver::typeset_beam ()
133 {
134   if (finished_beam_p_)
135     {
136       Rhythmic_grouping const * rg_C = get_staff_info().rhythmic_C_;
137       rg_C->extend (finished_grouping_p_->interval());
138       finished_beam_p_->set_grouping (*rg_C, *finished_grouping_p_);
139       typeset_element (finished_beam_p_);
140       finished_beam_p_ = 0;
141     
142       delete finished_grouping_p_;
143       finished_grouping_p_= 0;
144     }
145 }
146
147 void
148 Auto_beam_engraver::do_post_move_processing ()
149 {
150 }
151
152 void
153 Auto_beam_engraver::do_pre_move_processing ()
154 {
155   typeset_beam ();
156 }
157
158 void
159 Auto_beam_engraver::do_removal_processing ()
160 {
161   typeset_beam ();
162   if (beam_p_)
163     {
164       DOUT << "Unfinished beam\n";
165       junk_beam ();
166     }
167 }
168
169 void
170 Auto_beam_engraver::acknowledge_element (Score_element_info info)
171 {
172   if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
173     {
174       if (beam_p_)
175         {
176           DOUT << "junking autobeam: beam encountered\n";
177           junk_beam ();
178         }
179     }
180   if (Bar *b = dynamic_cast<Bar *> (info.elem_l_))
181     {
182       if (beam_p_)
183         {
184           DOUT << "junking autobeam: bar encountered\n";
185           junk_beam ();
186         }
187     }
188
189   if (beam_p_)
190     {
191       Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
192       if (!rhythmic_req)
193         return;
194
195       if (dynamic_cast<Rest *> (info.elem_l_))
196         {
197           DOUT << "junking autobeam: rest encountered\n";
198           end_beam ();
199           return;
200         }
201
202       Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_);
203       if (!stem_l)
204         return;
205
206       if (stem_l->beam_l_ && (stem_l->beam_l_ != beam_p_))
207         {
208           DOUT << "junking autobeam: beamed stem encountered\n";
209           junk_beam ();
210           return;
211         }
212         
213
214       /*
215         now that we have last_add_mom_, perhaps we can (should) do away
216         with these individual junk_beams
217        */
218       if (rhythmic_req->duration_.durlog_i_<= 2)
219         {
220           DOUT << "ending autobeam: stem doesn't fit in beam\n";
221           end_beam ();
222           return;
223         }
224
225       Moment start = get_staff_info().time_C_->whole_in_measure_;
226       if (!grouping_p_->child_fit_b (start))
227         {
228           DOUT << "ending autobeam: stem doesn't fit in group\n";
229           end_beam ();
230         }
231       else
232         {
233           int m = (rhythmic_req->duration_.durlog_i_ - 2);
234           /*
235             if multiplicity would become greater,
236             reconsider ending/starting beam first.
237            */
238           if (m > mult_i_)
239             {
240               mult_i_ = m;
241               consider_end_and_begin ();
242             }
243           mult_i_ = m;
244           grouping_p_->add_child (start, rhythmic_req->duration ());
245           stem_l->flag_i_ = rhythmic_req->duration_.durlog_i_;
246           beam_p_->add_stem (stem_l);
247           Moment now = now_moment ();
248           last_add_mom_ = now;
249           extend_mom_ = extend_mom_ >? now + rhythmic_req->duration ();
250         }
251     }
252 }
253
254 void
255 Auto_beam_engraver::junk_beam () 
256 {
257   assert (beam_p_);
258   for (int i=0; i < beam_p_->stems_.size (); i++)
259     {
260       Stem* s = beam_p_->stems_[i];
261       s->beams_i_drul_[LEFT] = 0;
262       s->beams_i_drul_[RIGHT] = 0;
263       s->mult_i_ = 0;
264       s->beam_l_ = 0;
265     }
266   
267   beam_p_->unlink ();
268   beam_p_ = 0;
269   delete grouping_p_;
270   grouping_p_ = 0;
271   mult_i_ = 0;
272 }
273
274 void
275 Auto_beam_engraver::process_acknowledged ()
276 {
277   if (beam_p_)
278     {
279       Moment now = now_moment ();
280       if ((extend_mom_ < now)
281           || ((extend_mom_ == now) && (last_add_mom_ != now )))
282         {
283           DOUT << String ("junking autobeam: no stem added since: ")
284             + last_add_mom_.str () + "\n";
285           end_beam ();
286         }
287       else if (!beam_p_->stems_.size ())
288         {
289           DOUT << "junking started autobeam: no stems\n";
290           junk_beam ();
291         }
292     }
293 }